From 824263fa6ebc6264e74cab303cf1fdf607d10094 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Sat, 4 Apr 2026 22:47:48 +0200 Subject: [PATCH 01/72] Config system v1 Roughly inspired by what I've learned from my work on Space Station 14, without some of the unnecessary cruft and complexity. Implementation is relatively simple once I figured out all the template order shenanigans. --- CMakeLists.txt | 8 +- files.cmake | 6 + include/dusk/appname.hpp | 20 ++ include/dusk/config.hpp | 114 +++++++++++ include/dusk/config_var.hpp | 228 ++++++++++++++++++++++ include/dusk/io.hpp | 75 ++++++++ include/dusk/scope.hpp | 29 +++ include/dusk/settings.hpp | 24 +++ include/m_Do/m_Do_controller_pad.h | 5 +- src/d/actor/d_a_alink.cpp | 8 +- src/d/actor/d_a_alink_demo.inc | 4 +- src/d/actor/d_a_alink_dusk.cpp | 2 +- src/d/actor/d_a_alink_hvyboots.inc | 2 +- src/d/d_camera.cpp | 2 +- src/d/d_kankyo.cpp | 2 +- src/dusk/config.cpp | 230 +++++++++++++++++++++++ src/dusk/imgui/ImGuiConfig.hpp | 17 ++ src/dusk/imgui/ImGuiMenuEnhancements.cpp | 25 +-- src/dusk/imgui/ImGuiMenuEnhancements.hpp | 12 -- src/dusk/io.cpp | 143 ++++++++++++++ src/dusk/settings.cpp | 28 +++ src/m_Do/m_Do_graphic.cpp | 4 +- src/m_Do/m_Do_main.cpp | 39 +++- 23 files changed, 984 insertions(+), 43 deletions(-) create mode 100644 include/dusk/appname.hpp create mode 100644 include/dusk/config.hpp create mode 100644 include/dusk/config_var.hpp create mode 100644 include/dusk/io.hpp create mode 100644 include/dusk/scope.hpp create mode 100644 include/dusk/settings.hpp create mode 100644 src/dusk/config.cpp create mode 100644 src/dusk/imgui/ImGuiConfig.hpp create mode 100644 src/dusk/io.cpp create mode 100644 src/dusk/settings.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e0cf678839..9e2be043ee 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -69,6 +69,12 @@ FetchContent_Declare( ) FetchContent_MakeAvailable(cxxopts) +FetchContent_Declare(json + URL https://github.com/nlohmann/json/releases/download/v3.12.0/json.tar.xz + URL_HASH SHA256=42f6e95cad6ec532fd372391373363b62a14af6d771056dbfc86160e6dfff7aa + DOWNLOAD_EXTRACT_TIMESTAMP TRUE +) +FetchContent_MakeAvailable(json) include(files.cmake) @@ -108,7 +114,7 @@ target_include_directories(game_debug PUBLIC extern ${CMAKE_SOURCE_DIR}/build/${DUSK_TP_VERSION}/include build/${DUSK_TP_VERSION}/include) -target_link_libraries(game_debug PUBLIC aurora::core aurora::gx aurora::gd aurora::si aurora::vi aurora::pad aurora::mtx aurora::os aurora::dvd aurora::card) +target_link_libraries(game_debug PUBLIC aurora::core aurora::gx aurora::gd aurora::si aurora::vi aurora::pad aurora::mtx aurora::os aurora::dvd aurora::card nlohmann_json::nlohmann_json) set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) add_library(game SHARED ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${SSYSTEM_FILES} ${JSYSTEM_FILES} ${REL_FILES} ${DUSK_FILES} ${DOLPHIN_FILES} diff --git a/files.cmake b/files.cmake index 26cae0f1a9..8a9e7be4d5 100644 --- a/files.cmake +++ b/files.cmake @@ -1332,16 +1332,22 @@ set(DOLPHIN_FILES set(DUSK_FILES include/dusk/endian_gx.hpp + include/dusk/config.hpp + include/dusk/settings.hpp src/d/actor/d_a_alink_dusk.cpp src/dusk/asserts.cpp + src/dusk/config.cpp + src/dusk/settings.cpp src/dusk/logging.cpp src/dusk/layout.cpp src/dusk/stubs.cpp src/dusk/endian.cpp src/dusk/extras.c src/dusk/extras.cpp + src/dusk/io.cpp src/dusk/globals.cpp #src/dusk/m_Do_ext_dusk.cpp + src/dusk/imgui/ImGuiConfig.hpp src/dusk/imgui/ImGuiConsole.hpp src/dusk/imgui/ImGuiConsole.cpp src/dusk/imgui/ImGuiMenuGame.cpp diff --git a/include/dusk/appname.hpp b/include/dusk/appname.hpp new file mode 100644 index 0000000000..d5d5f40083 --- /dev/null +++ b/include/dusk/appname.hpp @@ -0,0 +1,20 @@ +#ifndef DUSK_APPNAME_HPP +#define DUSK_APPNAME_HPP + +namespace dusk { + /** + * \brief The internal application name for the game. + * + * This gets used for file paths and such, and cannot be changed! + */ + constexpr auto AppName = "Dusk"; + + /** + * \brief The internal organization name for the game. + * + * This gets used for file paths and such, and cannot be changed! + */ + constexpr auto OrgName = "TwilitRealm"; +} + +#endif // DUSK_APPNAME_HPP diff --git a/include/dusk/config.hpp b/include/dusk/config.hpp new file mode 100644 index 0000000000..5cd0807b3b --- /dev/null +++ b/include/dusk/config.hpp @@ -0,0 +1,114 @@ +#ifndef DUSK_CONFIG_HPP +#define DUSK_CONFIG_HPP + +#include +#include "nlohmann/json.hpp" +#include "config_var.hpp" + +namespace dusk::config { + +/** + * \brief Base class containing virtual functions used for save/load of CVars. + */ +class ConfigImplBase { +protected: + virtual ~ConfigImplBase() = default; + +public: + /** + * \brief Load a JSON value into a CVar at the Value layer. + */ + virtual void loadFromJson(ConfigVarBase& cVar, const nlohmann::json& jsonValue) const = 0; + + /** + * \brief Load a simple launch argument into the CVar at the Override layer. + */ + virtual void loadFromArg(ConfigVarBase& cVar, std::string_view stringValue) const = 0; + + /** + * \brief Dump the value contained in the CVar to JSON. + */ + [[nodiscard]] virtual nlohmann::json dumpToJson(const ConfigVarBase& cVar) const = 0; +}; + +template +class ConfigImpl : public ConfigImplBase { + // Just downcasting the references... + void loadFromJson(ConfigVarBase& cVar, const nlohmann::json& jsonValue) const final { + assert(typeid(cVar) == typeid(ConfigVar)); + loadFromJson(dynamic_cast&>(cVar), jsonValue); + } + + void loadFromArg(ConfigVarBase& cVar, std::string_view stringValue) const final { + assert(typeid(cVar) == typeid(ConfigVar)); + loadFromArg(dynamic_cast&>(cVar), stringValue); + } + + [[nodiscard]] nlohmann::json dumpToJson(const ConfigVarBase& cVar) const final { + assert(typeid(cVar) == typeid(ConfigVar)); + return dumpToJson(dynamic_cast&>(cVar)); + } + + /** + * \brief Load a JSON value into a CVar at the Value layer. + */ + static void loadFromJson(ConfigVar& cVar, const nlohmann::json& jsonValue); + + /** + * \brief Load a simple launch argument into the CVar at the Override layer. + */ + static void loadFromArg(ConfigVar& cVar, std::string_view stringValue); + + /** + * \brief Dump the value contained in the CVar to JSON. + */ + [[nodiscard]] static nlohmann::json dumpToJson(const ConfigVar& cVar); +}; + +/** + * \brief Thrown by config loading functions if the value provided is invalid for the CVar. + */ +class InvalidConfigError : public std::runtime_error { +public: + explicit InvalidConfigError(const char* what) : runtime_error(what) {} +}; + +/** + * \brief Register a CVar to make the config system aware of it. + * + * This must be done on startup *before* config has been loaded. + */ +void Register(ConfigVarBase& configVar); + +/** + * \brief Indicate that all registrations have happened and everything should lock in. + */ +void FinishRegistration(); + +/** + * \brief Load config from the standard user preferences location. + */ +void LoadFromUserPreferences(); +void LoadFromFileName(const char* path); + +/** + * \brief Save the config to file. + */ +void Save(); + +/** + * \brief Get a registered CVar by name. + * + * @return null if the CVar does not exist. + */ +ConfigVarBase* GetConfigVar(std::string_view name); + +template +const ConfigImplBase* GetConfigImpl() { + static ConfigImpl config; + return &config; +} + +} // namespace dusk::config + +#endif diff --git a/include/dusk/config_var.hpp b/include/dusk/config_var.hpp new file mode 100644 index 0000000000..b775aa0584 --- /dev/null +++ b/include/dusk/config_var.hpp @@ -0,0 +1,228 @@ +#ifndef DUSK_CONFIG_VAR_HPP +#define DUSK_CONFIG_VAR_HPP + +#include "dolphin/types.h" +#include +#include +#include + +/** + * The configuration system. + * + * Configuration works via "configuration variables" aka "CVars". Each stores a single value that + * may be individually written to/from a configuration file. + * + * CVars, like ogres, have layers. Higher layers (e.g. a set value) override lower layers + * (e.g. the default value). + * + * To define a CVar, simply make a global variable of type ConfigVar, + * and make sure Register() is called on it during program startup. + * + * config_var.hpp contains the simplest "just the configuration vars themselves". + * This should be safe to include for files that need to *access* configuration, + * without blowing up compile times on implementation details. + * + * config.hpp on the other hand contains far more calls for mutating, loading, and defining CVars. + */ +namespace dusk::config { + +/** + * \brief Layers that a configuration variable can currently be at. + * + * A configuration variable can be on one of multiple *layers*, which determines where + * the current value is coming from. + */ +enum class ConfigVarLayer : u8 { + /** + * The CVar is at the default value defined by the application code. + */ + Default, + + /** + * The CVar has been modified by the user and may be saved to config. + */ + Value, + + /** + * The CVar is modified by launch argument, overruling the normal config value. + * Will not get saved to config. + */ + Override, +}; + +class ConfigImplBase; + +/** + * Base class that all CVars inherit from. + * You want the templated ConfigVar instead for actual usage. + */ +class ConfigVarBase { +protected: + /** + * The name of this CVar, used in the configuration file. + */ + const char* name; + + /** + * Whether this CVar has been registered with the global managing logic. + * If this is not done, it is not functional. + */ + bool registered; + + /** + * The layer this CVar is at. + */ + ConfigVarLayer layer; + + /** + * Pointer to an implementation struct for various load/save calls. + */ + const ConfigImplBase* impl; + + ConfigVarBase(const char* name, const ConfigImplBase* impl); + virtual ~ConfigVarBase() = default; + + /** + * Check that the CVar is registered, aborting if this is not the case. + */ + void checkRegistered() const { + if (!registered) + abort(); + } + +public: + /** + * Get the name of this CVar, used in the configuration file. + */ + [[nodiscard]] const char* getName() const noexcept; + + /** + * Get the pointer to the implementation struct. + */ + [[nodiscard]] const ConfigImplBase* getImpl() const noexcept; + + /** + * Get the layer this CVar is currently at. + */ + [[nodiscard]] constexpr ConfigVarLayer getLayer() const noexcept { + return layer; + } + + /** + * Mark this CVar as being registered with the central save/load logic. + * This is necessary to make it legal to access. + */ + void markRegistered(); +}; + +template +concept ConfigValueInteger = + std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v + || std::is_same_v; + +/** + * \brief Concept that defines the legal set of types that can be used for CVar values. + * + * Valid types cannot be cv-qualified and must be basic primitive types (int, float, bool), + * strings, or enums of the basic primitives. + */ +template +concept ConfigValue = + !std::is_const_v + && !std::is_volatile_v + && (std::is_same_v + || ConfigValueInteger + || std::is_same_v + || std::is_same_v + || std::is_same_v + || (std::is_enum_v && ConfigValueInteger>)); + +template +const ConfigImplBase* GetConfigImpl(); + +/** + * \brief A CVar storing values. + * + * @tparam T The type of value stored in the CVar. + */ +template +class ConfigVar : public ConfigVarBase { + T defaultValue; + T value; + T overrideValue; + +public: + /** + * \brief Construct a CVar. + * + * @param name The name of this CVar. Must be unique. + * @param arg Arguments to forward to construct the default value. + */ + template + explicit ConfigVar(const char* name, Args&&... arg) + : ConfigVarBase(name, GetConfigImpl()), defaultValue(std::forward(arg)...), + value(), overrideValue() {} + + /** + * \brief Get the current value of the CVar. + */ + [[nodiscard]] constexpr const T& getValue() const noexcept { + checkRegistered(); + switch (layer) { + case ConfigVarLayer::Default: + return defaultValue; + case ConfigVarLayer::Value: + return value; + case ConfigVarLayer::Override: + return overrideValue; + default: + abort(); + } + } + + /** + * \brief Change the value of a CVar. + * + * The new value is always stored at the Value layer. + * + * @param newValue The new value the CVar will get. + * @param replaceOverride If true, clear an existing override layer if there is one. + * If this is false and there is an override layer, + * the result of getValue() will not change immediately. + */ + void setValue(T newValue, bool replaceOverride = true) { + checkRegistered(); + value = std::move(newValue); + + if (replaceOverride) { + overrideValue = {}; + layer = ConfigVarLayer::Value; + } else if (layer != ConfigVarLayer::Override) { + layer = ConfigVarLayer::Value; + } + } + + /** + * \brief Give a CVar an override value. + * + * This overrides (but does not replace) the apparent set value of this CVar. + * The overriden value will not get saved to config. + * + * @param newValue The new value the CVar will get. + */ + void setOverrideValue(T newValue) { + checkRegistered(); + overrideValue = std::move(newValue); + layer = ConfigVarLayer::Override; + } +}; + +} + +#endif // DUSK_CONFIG_VAR_HPP diff --git a/include/dusk/io.hpp b/include/dusk/io.hpp new file mode 100644 index 0000000000..fb71a77d68 --- /dev/null +++ b/include/dusk/io.hpp @@ -0,0 +1,75 @@ +#ifndef DUSK_IO_HPP +#define DUSK_IO_HPP + +#include + +// I can't believe it's 2026 and neither SDL (no error codes) nor +// C++ (no error codes) have a file system API functional enough for me to use. +// Here you go, this one's inspired by C#. I only wrote the functions I need. + +namespace dusk::io { + +/** + * \brief A simple file stream wrapping cstdio FILE*. + * + * Methods on this class throw appropriate C++ exceptions when an error occurs. + */ +class FileStream { + void* file; + +public: + FileStream() noexcept; + + /** + * \brief Take ownership of a FILE* handle. + */ + explicit FileStream(void* file); + FileStream(const FileStream& other) = delete; + FileStream(FileStream&& other) noexcept; + + ~FileStream(); + + /** + * \brief Open a file for reading at the given path. + */ + static FileStream OpenRead(const char* utf8Path); + + /** + * \brief Create a file for writing. + * + * If there is an existing file, its contents are demolished. + */ + static FileStream Create(const char* utf8Path); + + /** + * \brief Read the byte contents of a file directly into a vector. + */ + static std::vector ReadAllBytes(const char* utf8Path); + + /** + * \brief Read the byte contents of a file directly into a vector. + */ + static void WriteAllText(const char* utf8Path, std::string_view text); + + /** + * \brief Read the remaining contents of the file directly into a vector. + */ + std::vector ReadFull(); + + /** + * Get direct access to the underlying FILE* handle. + */ + [[nodiscard]] void* GetFileHandle() const noexcept { + return file; + } + + /** + * Write data to the file. + */ + void Write(const char* data, size_t dataLen); +}; + +} + + +#endif // DUSK_IO_HPP diff --git a/include/dusk/scope.hpp b/include/dusk/scope.hpp new file mode 100644 index 0000000000..e1cfcb9a58 --- /dev/null +++ b/include/dusk/scope.hpp @@ -0,0 +1,29 @@ +#ifndef DUSK_SCOPE_HPP +#define DUSK_SCOPE_HPP + +namespace dusk { + +/** + * A simple value wrapper that will destroy the value at the end of its scope. + * @tparam T The type of value contained. + * @tparam Destructor The type of function used to destroy the value. + */ +template + struct ScopeValue { + T value; + Destructor destructor; + + explicit ScopeValue(T value, Destructor destructor) : value(value), destructor(destructor) { + } + + ~ScopeValue() { + destructor(value); + } + + constexpr operator T&() const noexcept { + return value; + } + }; +} + +#endif // DUSK_SCOPE_HPP diff --git a/include/dusk/settings.hpp b/include/dusk/settings.hpp new file mode 100644 index 0000000000..79c9981647 --- /dev/null +++ b/include/dusk/settings.hpp @@ -0,0 +1,24 @@ +#ifndef DUSK_SETTINGS_HPP +#define DUSK_SETTINGS_HPP + +#include "config_var.hpp" + +namespace dusk::settings { + using namespace dusk::config; + + namespace enhancements { + extern ConfigVar FastIronBoots; + extern ConfigVar InvertCameraXAxis; + extern ConfigVar QuickTransform; + extern ConfigVar RestoreWiiGlitches; + extern ConfigVar EnableBloom; + extern ConfigVar UseWaterProjectionOffset; + extern ConfigVar MirrorMode; + + void Register(); + } + + void Register(); +} + +#endif // DUSK_SETTINGS_HPP diff --git a/include/m_Do/m_Do_controller_pad.h b/include/m_Do/m_Do_controller_pad.h index b8cee23ca3..57de651bc0 100644 --- a/include/m_Do/m_Do_controller_pad.h +++ b/include/m_Do/m_Do_controller_pad.h @@ -3,6 +3,7 @@ #include "JSystem/JUtility/JUTGamePad.h" #include "SSystem/SComponent/c_API_controller_pad.h" +#include "dusk/settings.hpp" #include "dusk/imgui/ImGuiMenuEnhancements.hpp" @@ -57,7 +58,7 @@ public: static s16 getStickAngle3D(u32 pad) { #if TARGET_PC - if (dusk::ImGuiMenuEnhancements::m_enhancements.mirrorMode) { + if (dusk::settings::enhancements::MirrorMode.getValue()) { return -getCpadInfo(pad).mMainStickAngle; } else { return getCpadInfo(pad).mMainStickAngle; @@ -69,7 +70,7 @@ public: static f32 getSubStickX3D(u32 pad) { #if TARGET_PC - if (dusk::ImGuiMenuEnhancements::m_enhancements.mirrorMode) { + if (dusk::settings::enhancements::MirrorMode.getValue()) { return -getCpadInfo(pad).mCStickPosX; } else { return getCpadInfo(pad).mCStickPosX; diff --git a/src/d/actor/d_a_alink.cpp b/src/d/actor/d_a_alink.cpp index 2c5bcf46cd..f847fde1cb 100644 --- a/src/d/actor/d_a_alink.cpp +++ b/src/d/actor/d_a_alink.cpp @@ -54,6 +54,8 @@ #include "res/Object/Alink.h" #include +#include "dusk/settings.hpp" + static int daAlink_Create(fopAc_ac_c* i_this); static int daAlink_Delete(daAlink_c* i_this); static int daAlink_Execute(daAlink_c* i_this); @@ -7510,7 +7512,7 @@ void daAlink_c::setBlendMoveAnime(f32 i_morf) { BOOL sp24 = checkEventRun(); BOOL sp20 = checkBootsMoveAnime(1); #if TARGET_PC - if (dusk::ImGuiMenuEnhancements::m_enhancements.fastIronBoots) { + if (dusk::settings::enhancements::FastIronBoots.getValue()) { sp20 = FALSE; } #endif @@ -9475,7 +9477,7 @@ void daAlink_c::setStickData() { mHeavySpeedMultiplier = mpHIO->mItem.mIronBoots.m.mInputFactor; } #if TARGET_PC - if (dusk::ImGuiMenuEnhancements::m_enhancements.fastIronBoots) { + if (dusk::settings::enhancements::FastIronBoots.getValue()) { mHeavySpeedMultiplier = 1.0f; } #endif @@ -9487,7 +9489,7 @@ void daAlink_c::setStickData() { mHeavySpeedMultiplier = mpHIO->mItem.mIronBoots.m.mWaterInputFactor; } #if TARGET_PC - if (dusk::ImGuiMenuEnhancements::m_enhancements.fastIronBoots) { + if (dusk::settings::enhancements::FastIronBoots.getValue()) { mHeavySpeedMultiplier = 1.0f; } #endif diff --git a/src/d/actor/d_a_alink_demo.inc b/src/d/actor/d_a_alink_demo.inc index 7acccbde13..936b0128d5 100644 --- a/src/d/actor/d_a_alink_demo.inc +++ b/src/d/actor/d_a_alink_demo.inc @@ -4301,7 +4301,7 @@ bool daAlink_c::checkAcceptWarp() { */ if (mLinkAcch.ChkGroundHit() && !checkModeFlg(MODE_PLAYER_FLY) #if TARGET_PC - && (dusk::ImGuiMenuEnhancements::m_enhancements.restoreWiiGlitches || !checkNoResetFlg0(FLG0_WATER_IN_MOVE)) + && (dusk::settings::enhancements::RestoreWiiGlitches.getValue() || !checkNoResetFlg0(FLG0_WATER_IN_MOVE)) #elif VERSION != VERSION_WII_USA_R0 && !checkNoResetFlg0(FLG0_WATER_IN_MOVE) #endif @@ -4312,7 +4312,7 @@ bool daAlink_c::checkAcceptWarp() { */ if ( #if TARGET_PC - (dusk::ImGuiMenuEnhancements::m_enhancements.restoreWiiGlitches || !getSlidePolygon(&plane)) && + (dusk::settings::enhancements::RestoreWiiGlitches.getValue() || !getSlidePolygon(&plane)) && #elif VERSION != VERSION_WII_USA_R0 !getSlidePolygon(&plane) && #endif diff --git a/src/d/actor/d_a_alink_dusk.cpp b/src/d/actor/d_a_alink_dusk.cpp index 47501d4f3d..f49443a0d0 100644 --- a/src/d/actor/d_a_alink_dusk.cpp +++ b/src/d/actor/d_a_alink_dusk.cpp @@ -6,7 +6,7 @@ #include "dusk/imgui/ImGuiMenuEnhancements.hpp" void daAlink_c::handleQuickTransform() { - if (!dusk::ImGuiMenuEnhancements::m_enhancements.quickTransform) { + if (!dusk::settings::enhancements::QuickTransform.getValue()) { return; } diff --git a/src/d/actor/d_a_alink_hvyboots.inc b/src/d/actor/d_a_alink_hvyboots.inc index ed52ffcb36..af00c28b1b 100644 --- a/src/d/actor/d_a_alink_hvyboots.inc +++ b/src/d/actor/d_a_alink_hvyboots.inc @@ -351,7 +351,7 @@ int daAlink_c::procMagneBootsFly() { */ if (dComIfG_Bgsp().ChkPolySafe(mPolyInfo2) #if TARGET_PC - && (dusk::ImGuiMenuEnhancements::m_enhancements.restoreWiiGlitches || checkEquipHeavyBoots()) + && (dusk::settings::enhancements::RestoreWiiGlitches.getValue() || checkEquipHeavyBoots()) #elif PLATFORM_GCN || VERSION == VERSION_WII_KOR && checkEquipHeavyBoots() #endif diff --git a/src/d/d_camera.cpp b/src/d/d_camera.cpp index 59ed1d2c11..6e63d8b940 100644 --- a/src/d/d_camera.cpp +++ b/src/d/d_camera.cpp @@ -766,7 +766,7 @@ void dCamera_c::updatePad() { var_f31 = mDoCPd_c::getSubStickX3D(mPadID); #if TARGET_PC - if (dusk::ImGuiMenuEnhancements::m_enhancements.invertCameraXAxis) { + if (dusk::settings::enhancements::InvertCameraXAxis.getValue()) { var_f31 *= -1.0f; } #endif diff --git a/src/d/d_kankyo.cpp b/src/d/d_kankyo.cpp index a61219ffac..e772098eae 100644 --- a/src/d/d_kankyo.cpp +++ b/src/d/d_kankyo.cpp @@ -11381,7 +11381,7 @@ void dKy_bg_MAxx_proc(void* bg_model_p) { C_MTXLightPerspective(sp1D8, dComIfGd_getView()->fovy, camera_p->view.aspect, 1.0f, 1.0f, #if TARGET_PC - dusk::ImGuiMenuEnhancements::m_enhancements.useWaterProjectionOffset ? -0.01f : 0.0f, 0.0f); + dusk::settings::enhancements::UseWaterProjectionOffset.getValue() ? -0.01f : 0.0f, 0.0f); #else -0.01f, 0.0f); #endif diff --git a/src/dusk/config.cpp b/src/dusk/config.cpp new file mode 100644 index 0000000000..aeafb5ab56 --- /dev/null +++ b/src/dusk/config.cpp @@ -0,0 +1,230 @@ +#include "dusk/config.hpp" +#include "SDL3/SDL_filesystem.h" +#include "SDL3/SDL_iostream.h" +#include "dusk/appname.hpp" +#include "dusk/scope.hpp" +#include "fmt/format.h" +#include "nlohmann/json.hpp" +#include "absl/container/flat_hash_map.h" + +#include "aurora/lib/logging.hpp" +#include "dusk/io.hpp" + +#include +#include + +using namespace dusk::config; + +constexpr auto ConfigFileName = "config.json"; + +using json = nlohmann::json; + +aurora::Module DuskConfigLog("dusk::config"); + +static absl::flat_hash_map RegisteredConfigVars; +static bool RegistrationDone; + +static std::string GetConfigJsonPath() { + dusk::ScopeValue folder(SDL_GetPrefPath(dusk::OrgName, dusk::AppName), SDL_free); + if (folder.value == nullptr) { + DuskConfigLog.error("Failed to get user preference path: %s", SDL_GetError()); + return ""; + } + + return fmt::format("{}{}", folder.value, ConfigFileName); +} + +ConfigVarBase::ConfigVarBase(const char* name, const ConfigImplBase* impl) : name(name), registered(false), layer(ConfigVarLayer::Default), impl(impl) { +} + +const char* ConfigVarBase::getName() const noexcept { + return name; +} + +const ConfigImplBase* ConfigVarBase::getImpl() const noexcept { + return impl; +} + +template +void ConfigImpl::loadFromJson(ConfigVar& cVar, const json& jsonValue) { + cVar.setValue(jsonValue.get(), false); +} + +template +nlohmann::json ConfigImpl::dumpToJson(const ConfigVar& cVar) { + return cVar.getValue(); +} + +template requires std::is_integral_v && std::is_signed_v +static void loadFromArgImpl(ConfigVar& cVar, const std::string_view stringValue) { + const std::string str(stringValue); + const auto result = std::stoll(str); + if (result >= std::numeric_limits::min() && result <= std::numeric_limits::max()) { + cVar.setOverrideValue(result); + } else { + throw std::out_of_range("Value is too large"); + } +} + +template requires std::is_integral_v && std::is_unsigned_v +static void loadFromArgImpl(ConfigVar& cVar, const std::string_view stringValue) { + const std::string str(stringValue); + const auto result = std::stoull(str); + if (result <= std::numeric_limits::max()) { + cVar.setOverrideValue(result); + } else { + throw std::out_of_range("Value is too large"); + } +} + +static void loadFromArgImpl(ConfigVar& cVar, const std::string_view stringValue) { + const std::string str(stringValue); + const auto result = std::stof(str); + cVar.setOverrideValue(result); +} + +static void loadFromArgImpl(ConfigVar& cVar, const std::string_view stringValue) { + const std::string str(stringValue); + const auto result = std::stod(str); + cVar.setOverrideValue(result); +} + +static void loadFromArgImpl(ConfigVar& cVar, const std::string_view stringValue) { + cVar.setOverrideValue(std::string(stringValue)); +} + +template +void ConfigImpl::loadFromArg(ConfigVar& cVar, const std::string_view stringValue) { + loadFromArgImpl(cVar, stringValue); +} + +template<> +void ConfigImpl::loadFromArg(ConfigVar& cVar, const std::string_view stringValue) { + if (stringValue == "1" || stringValue == "TRUE" || stringValue == "true" || stringValue == "True") { + cVar.setOverrideValue(true); + } else if (stringValue == "0" || stringValue == "FALSE" || stringValue == "false" || stringValue == "False") { + cVar.setOverrideValue(false); + } else { + throw InvalidConfigError("Value cannot be parsed as boolean"); + } +} + +// My IDE is convinced this namespace is necessary. It shouldn't be AFAICT? +namespace dusk::config { + template class ConfigImpl; + template class ConfigImpl; + template class ConfigImpl; + template class ConfigImpl; + template class ConfigImpl; + template class ConfigImpl; + template class ConfigImpl; + template class ConfigImpl; + template class ConfigImpl; + template class ConfigImpl; + template class ConfigImpl; + template class ConfigImpl; +} + +void dusk::config::Register(ConfigVarBase& configVar) { + const auto& name = configVar.getName(); + if (RegistrationDone) { + DuskConfigLog.fatal("Tried to register CVar {} after registrations closed!", name); + } + + if (RegisteredConfigVars.contains(name)) { + DuskConfigLog.fatal("Tried to register CVar {} twice!", name); + } + + RegisteredConfigVars[name] = &configVar; + configVar.markRegistered(); +} + +void ConfigVarBase::markRegistered() { + if (registered) + abort(); + + registered = true; +} + +void dusk::config::FinishRegistration() { + RegistrationDone = true; +} + +void dusk::config::LoadFromUserPreferences() { + const auto configPath = GetConfigJsonPath(); + if (configPath.empty()) { + return; + } + LoadFromFileName(configPath.c_str()); +} + +static void LoadFromPath(const char* path) { + auto data = dusk::io::FileStream::ReadAllBytes(path); + + json j = json::parse(data); + if (!j.is_object()) { + DuskConfigLog.error("Config JSON is not an object!"); + return; + } + + for (const auto& el : j.items()) { + const auto& key = el.key(); + auto configVar = RegisteredConfigVars.find(key); + if (configVar == RegisteredConfigVars.end()) { + DuskConfigLog.error("Unknown key '{}' found in config!", key); + continue; + } + + try { + configVar->second->getImpl()->loadFromJson(*configVar->second, el.value()); + } catch (std::exception& e) { + DuskConfigLog.error("Failed to load key '{}' from config: {}", key, e.what()); + } + } +} + +void dusk::config::LoadFromFileName(const char* path) { + if (!RegistrationDone) { + DuskConfigLog.fatal("Registration not finished yet!"); + } + + DuskConfigLog.info("Loading config from '{}'", path); + + try { + LoadFromPath(path); + } catch (const std::system_error& e) { + if (e.code() == std::errc::no_such_file_or_directory) { + DuskConfigLog.info("Config file did not exist, staying with defaults"); + } else { + DuskConfigLog.error("Failed to load from config! {}", e.what()); + } + } +} + +void dusk::config::Save() { + const auto configPath = GetConfigJsonPath(); + if (configPath.empty()) { + return; + } + + DuskConfigLog.info("Saving config to '{}'", configPath); + + json j; + + for (const auto& pair : RegisteredConfigVars) { + if (pair.second->getLayer() == ConfigVarLayer::Value) { + j[pair.first] = pair.second->getImpl()->dumpToJson(*pair.second); + } + } + + io::FileStream::WriteAllText(configPath.c_str(), j.dump(4)); +} + +ConfigVarBase* dusk::config::GetConfigVar(std::string_view name) { + const auto configVar = RegisteredConfigVars.find(name); + if (configVar != RegisteredConfigVars.end()) { + return configVar->second; + } + + return nullptr; +} \ No newline at end of file diff --git a/src/dusk/imgui/ImGuiConfig.hpp b/src/dusk/imgui/ImGuiConfig.hpp new file mode 100644 index 0000000000..c4ecb61d77 --- /dev/null +++ b/src/dusk/imgui/ImGuiConfig.hpp @@ -0,0 +1,17 @@ +#ifndef DUSK_IMGUICONFIG_HPP +#define DUSK_IMGUICONFIG_HPP + +#include "dusk/config.hpp" +#include "imgui.h" + +namespace dusk::config { + inline void ImguiCheckbox(const char* title, ConfigVar& var) { + bool copy = var.getValue(); + if (ImGui::Checkbox(title, ©)) { + var.setValue(copy); + Save(); + } + } +} + +#endif // DUSK_IMGUICONFIG_HPP diff --git a/src/dusk/imgui/ImGuiMenuEnhancements.cpp b/src/dusk/imgui/ImGuiMenuEnhancements.cpp index 5ea315d8ec..c582bc2335 100644 --- a/src/dusk/imgui/ImGuiMenuEnhancements.cpp +++ b/src/dusk/imgui/ImGuiMenuEnhancements.cpp @@ -4,43 +4,36 @@ #include "ImGuiConsole.hpp" #include "ImGuiMenuEnhancements.hpp" +#include "ImGuiConfig.hpp" +#include "dusk/settings.hpp" #include namespace dusk { - EnhancementsSettings ImGuiMenuEnhancements::m_enhancements = { - .fastIronBoots = false, - .invertCameraXAxis = false, - .restoreWiiGlitches = false, - .enableBloom = true, - .useWaterProjectionOffset = false, - .mirrorMode = false, - }; - ImGuiMenuEnhancements::ImGuiMenuEnhancements() {} void ImGuiMenuEnhancements::draw() { if (ImGui::BeginMenu("Enhancements")) { if (ImGui::BeginMenu("Quality of Life")) { - ImGui::Checkbox("Fast Iron Boots", &m_enhancements.fastIronBoots); - ImGui::Checkbox("Invert Camera X Axis", &m_enhancements.invertCameraXAxis); - ImGui::Checkbox("Quick Transform (R+Y)", &m_enhancements.quickTransform); + config::ImguiCheckbox("Fast Iron Boots", settings::enhancements::FastIronBoots); + config::ImguiCheckbox("Invert Camera X Axis", settings::enhancements::InvertCameraXAxis); + config::ImguiCheckbox("Quick Transform (R+Y)", settings::enhancements::QuickTransform); ImGui::EndMenu(); } if (ImGui::BeginMenu("Graphics")) { - ImGui::Checkbox("Native Bloom", &m_enhancements.enableBloom); - ImGui::Checkbox("Water Projection Offset", &m_enhancements.useWaterProjectionOffset); + config::ImguiCheckbox("Native Bloom", settings::enhancements::EnableBloom); + config::ImguiCheckbox("Water Projection Offset", settings::enhancements::UseWaterProjectionOffset); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Adds GC-specific -0.01 transS offset\n" "that causes ~6px ghost artifacts in water reflections"); } - ImGui::Checkbox("Mirror Mode", &m_enhancements.mirrorMode); + config::ImguiCheckbox("Mirror Mode", settings::enhancements::MirrorMode); ImGui::EndMenu(); } if (ImGui::BeginMenu("Restorations")) { - ImGui::Checkbox("Restore Wii 1.0 Glitches", &m_enhancements.restoreWiiGlitches); + config::ImguiCheckbox("Restore Wii 1.0 Glitches", settings::enhancements::RestoreWiiGlitches); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Restores patched glitches from Wii USA 1.0, the first released version"); } diff --git a/src/dusk/imgui/ImGuiMenuEnhancements.hpp b/src/dusk/imgui/ImGuiMenuEnhancements.hpp index 0238317ce4..f40baaad65 100644 --- a/src/dusk/imgui/ImGuiMenuEnhancements.hpp +++ b/src/dusk/imgui/ImGuiMenuEnhancements.hpp @@ -8,22 +8,10 @@ #include "imgui.h" namespace dusk { - struct EnhancementsSettings { - bool fastIronBoots; - bool invertCameraXAxis; - bool quickTransform; - bool restoreWiiGlitches; - bool enableBloom; - bool useWaterProjectionOffset; - bool mirrorMode; - }; - class ImGuiMenuEnhancements { public: ImGuiMenuEnhancements(); void draw(); - - static EnhancementsSettings m_enhancements; }; } diff --git a/src/dusk/io.cpp b/src/dusk/io.cpp new file mode 100644 index 0000000000..f930c2ceaa --- /dev/null +++ b/src/dusk/io.cpp @@ -0,0 +1,143 @@ +#include "dusk/io.hpp" +#include +#include + +using namespace dusk::io; + +#if _WIN32 +#define MODE_TYPE wchar_t +#define MODE(val) L##val +#define ftell(file) _ftelli64(file) +#define fseek(a, b, c) _fseeki64(a, b, c) +#else +#define MODE_TYPE char +#define MODE(val) ##val +#endif + +static FILE* ThrowIfNotOpen(const FileStream& file) { + if (!file.GetFileHandle()) { + throw std::runtime_error("Invalid file handle!"); + } + + return static_cast(file.GetFileHandle()); +} + +[[noreturn]] static void ThrowForError(int code) { + throw std::system_error(std::make_error_code(static_cast(code))); +} + +static FILE* OpenCore(const std::filesystem::path& path, const MODE_TYPE* mode) { + FILE* file; + + int err; +#if _WIN32 + static_assert(std::is_same_v); + err = _wfopen_s(&file, path.c_str(), mode); +#else + errno = 0; + static_assert(std::is_same_v); + file = fopen(path.c_str(), mode); + err = errno; +#endif + + if (!file) { + ThrowForError(err); + } + + return file; +} + +static FILE* OpenCore(const char* path, const MODE_TYPE* mode) { + return OpenCore(reinterpret_cast(path), mode); +} + +FileStream::FileStream() noexcept : file(nullptr) { +} + +FileStream::FileStream(void* file) : file(file) { + if (!file) { + CRASH("Invalid file handle"); + } +} + +FileStream::FileStream(FileStream&& other) noexcept { + file = other.file; + other.file = nullptr; +} + +FileStream::~FileStream() { + if (file) + fclose(static_cast(file)); +} + +FileStream FileStream::OpenRead(const char* utf8Path) { + return FileStream(OpenCore(utf8Path, MODE("rb"))); +} + +FileStream FileStream::Create(const char* utf8Path) { + return FileStream(OpenCore(utf8Path, MODE("wb"))); +} + +std::vector FileStream::ReadFull() { + const auto fileHandle = ThrowIfNotOpen(*this); + + std::vector result; + + const auto startPos = ftell(fileHandle); + if (startPos == -1) { + ThrowForError(errno); + } + + auto seekRes = fseek(fileHandle, 0, SEEK_END); + if (seekRes != 0) { + ThrowForError(errno); + } + + const auto endPos = ftell(fileHandle); + if (endPos == -1) { + ThrowForError(errno); + } + + seekRes = fseek(fileHandle, startPos, SEEK_SET); + if (seekRes != 0) { + ThrowForError(errno); + } + + result.resize(endPos - startPos); + + if (result.empty()) { + return result; + } + + auto ret = fread(result.data(), 1, result.size(), fileHandle); + if (ret < result.size()) { + int err = errno; + // Error or EOF + if (feof(fileHandle)) { + result.resize(ret); + } else { + ThrowForError(err); + } + } + + return result; +} + +std::vector FileStream::ReadAllBytes(const char* utf8Path) { + auto handle = OpenRead(utf8Path); + return std::move(handle.ReadFull()); +} + +void FileStream::Write(const char* data, size_t dataLen) { + FILE* fileHandle = ThrowIfNotOpen(*this); + + const auto ret = fwrite(data, 1, dataLen, fileHandle); + if (ret < dataLen) { + ThrowForError(errno); + } +} + +void FileStream::WriteAllText(const char* utf8Path, const std::string_view text) { + auto handle = Create(utf8Path); + handle.Write(text.data(), text.size()); +} diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp new file mode 100644 index 0000000000..2be800b6a5 --- /dev/null +++ b/src/dusk/settings.cpp @@ -0,0 +1,28 @@ +#include "dusk/settings.hpp" +#include "dusk/config.hpp" + +namespace dusk::settings::enhancements { + ConfigVar FastIronBoots("enhancements.fast_iron_boots", false); + ConfigVar InvertCameraXAxis("enhancements.invert_camera_x_axis", false); + ConfigVar QuickTransform("enhancements.quick_transform", false); + ConfigVar RestoreWiiGlitches("enhancements.restore_wii_glitches", false); + ConfigVar EnableBloom("enhancements.enable_bloom", true); + ConfigVar UseWaterProjectionOffset("enhancements.use_water_projection_offset", false); + ConfigVar MirrorMode("enhancements.mirror_mode", false); + + void Register() { + Register(FastIronBoots); + Register(InvertCameraXAxis); + Register(QuickTransform); + Register(RestoreWiiGlitches); + Register(EnableBloom); + Register(UseWaterProjectionOffset); + Register(MirrorMode); + } +} + +namespace dusk::settings { + void Register() { + enhancements::Register(); + } +} diff --git a/src/m_Do/m_Do_graphic.cpp b/src/m_Do/m_Do_graphic.cpp index 06d6efd4eb..8ecc4bbb8f 100644 --- a/src/m_Do/m_Do_graphic.cpp +++ b/src/m_Do/m_Do_graphic.cpp @@ -1163,7 +1163,7 @@ void mDoGph_gInf_c::bloom_c::remove() { void mDoGph_gInf_c::bloom_c::draw() { #if TARGET_PC - if (!dusk::ImGuiMenuEnhancements::m_enhancements.enableBloom) { + if (!dusk::settings::enhancements::EnableBloom.getValue()) { return; } #endif @@ -2113,7 +2113,7 @@ int mDoGph_Painter() { #endif #if TARGET_PC - if (dusk::ImGuiMenuEnhancements::m_enhancements.mirrorMode) + if (dusk::settings::enhancements::MirrorMode.getValue()) #elif PLATFORM_WII if (data_8053a730) #endif diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index 03ff6b8c0f..b8d6fe9728 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -56,6 +56,8 @@ #include #include "cxxopts.hpp" +#include "dusk/config.hpp" +#include "dusk/settings.hpp" // --- GLOBALS --- s8 mDoMain::developmentMode = -1; @@ -225,10 +227,41 @@ static AuroraBackend ParseAuroraBackend(const std::string& value) { exit(1); } +static void ApplyCVarOverrides(const cxxopts::OptionValue& option) { + if (option.count() == 0) { + return; + } + + const auto& cVars = option.as>(); + for (const auto& cvarArg : cVars) { + const auto sep = cvarArg.find('='); + if (sep == std::string::npos) { + DuskLog.fatal("--cvar argument has no '=': '{}'", cvarArg); + continue; + } + + const auto name = std::string_view(cvarArg).substr(0, sep); + const auto value = std::string_view(cvarArg).substr(sep + 1); + + const auto cVar = dusk::config::GetConfigVar(name); + if (!cVar) { + DuskLog.fatal("Unknown --cvar name: '{}'", name); + } + + try { + cVar->getImpl()->loadFromArg(*cVar, value); + } catch (const std::exception& e) { + DuskLog.fatal("Unable to parse: '{}': {}", value, e.what()); + } + } +} + // ========================================================================= // PC ENTRY POINT // ========================================================================= int game_main(int argc, char* argv[]) { + dusk::settings::Register(); + cxxopts::ParseResult parsed_arg_options; try { @@ -238,7 +271,8 @@ int game_main(int argc, char* argv[]) { ("l,log-level", "Log level from " + std::to_string(AuroraLogLevel::LOG_DEBUG) + " to " + std::to_string(AuroraLogLevel::LOG_FATAL), cxxopts::value()->default_value("0")) ("h,help", "Print usage") ("dvd", "Path to DVD image file", cxxopts::value()->default_value("game.iso")) - ("backend", "Graphics API backend to use (auto, d3d11, d3d12, metal, vulkan, opengl, opengles, webgpu, null)", cxxopts::value()->default_value("auto")); + ("backend", "Graphics API backend to use (auto, d3d11, d3d12, metal, vulkan, opengl, opengles, webgpu, null)", cxxopts::value()->default_value("auto")) + ("cvar", "Override configuration variables without modifying config", cxxopts::value>()); arg_options.parse_positional({"dvd"}); arg_options.positional_help(""); @@ -257,6 +291,9 @@ int game_main(int argc, char* argv[]) { exit(1); } + dusk::config::LoadFromUserPreferences(); + ApplyCVarOverrides(parsed_arg_options["cvar"]); + AuroraConfig config{}; config.appName = "Dusk"; config.windowPosX = -1; From e55537f23ef10334e89e1c292057ed060462c1d5 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Sat, 4 Apr 2026 22:49:51 +0200 Subject: [PATCH 02/72] I realize that's an important comment for C++ --- include/dusk/config_var.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/include/dusk/config_var.hpp b/include/dusk/config_var.hpp index b775aa0584..bb1710662c 100644 --- a/include/dusk/config_var.hpp +++ b/include/dusk/config_var.hpp @@ -171,6 +171,9 @@ public: /** * \brief Get the current value of the CVar. + * + * This reference is not guaranteed to remain up-to-date after modification of the CVar. + * It will, however, remain sound to access. */ [[nodiscard]] constexpr const T& getValue() const noexcept { checkRegistered(); From 14026397e92d8f4f310da7418458c01731382f0b Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Sat, 4 Apr 2026 23:00:33 +0200 Subject: [PATCH 03/72] Implicit conversion operator is probably a good idea tbh. --- include/dusk/config_var.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/dusk/config_var.hpp b/include/dusk/config_var.hpp index bb1710662c..064d37028d 100644 --- a/include/dusk/config_var.hpp +++ b/include/dusk/config_var.hpp @@ -211,6 +211,10 @@ public: } } + operator const T&() { + return getValue(); + } + /** * \brief Give a CVar an override value. * From f732eccf6c99b6703e8b34ff2b0ff40d66854531 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Sun, 5 Apr 2026 19:03:26 +0200 Subject: [PATCH 04/72] Set Aurora config path --- include/dusk/dusk.h | 1 + include/dusk/scope.hpp | 29 ----------------------------- src/dusk/config.cpp | 28 ++++++++++------------------ src/m_Do/m_Do_main.cpp | 17 ++++++++++++++++- 4 files changed, 27 insertions(+), 48 deletions(-) delete mode 100644 include/dusk/scope.hpp diff --git a/include/dusk/dusk.h b/include/dusk/dusk.h index d84e496827..7fc2a23070 100644 --- a/include/dusk/dusk.h +++ b/include/dusk/dusk.h @@ -4,5 +4,6 @@ #include extern AuroraInfo auroraInfo; +extern const char* configPath; #endif // DUSK_DUSK_H diff --git a/include/dusk/scope.hpp b/include/dusk/scope.hpp deleted file mode 100644 index e1cfcb9a58..0000000000 --- a/include/dusk/scope.hpp +++ /dev/null @@ -1,29 +0,0 @@ -#ifndef DUSK_SCOPE_HPP -#define DUSK_SCOPE_HPP - -namespace dusk { - -/** - * A simple value wrapper that will destroy the value at the end of its scope. - * @tparam T The type of value contained. - * @tparam Destructor The type of function used to destroy the value. - */ -template - struct ScopeValue { - T value; - Destructor destructor; - - explicit ScopeValue(T value, Destructor destructor) : value(value), destructor(destructor) { - } - - ~ScopeValue() { - destructor(value); - } - - constexpr operator T&() const noexcept { - return value; - } - }; -} - -#endif // DUSK_SCOPE_HPP diff --git a/src/dusk/config.cpp b/src/dusk/config.cpp index aeafb5ab56..159706fac8 100644 --- a/src/dusk/config.cpp +++ b/src/dusk/config.cpp @@ -1,8 +1,4 @@ #include "dusk/config.hpp" -#include "SDL3/SDL_filesystem.h" -#include "SDL3/SDL_iostream.h" -#include "dusk/appname.hpp" -#include "dusk/scope.hpp" #include "fmt/format.h" #include "nlohmann/json.hpp" #include "absl/container/flat_hash_map.h" @@ -13,6 +9,8 @@ #include #include +#include "dusk/dusk.h" + using namespace dusk::config; constexpr auto ConfigFileName = "config.json"; @@ -25,13 +23,7 @@ static absl::flat_hash_map RegisteredConfigVar static bool RegistrationDone; static std::string GetConfigJsonPath() { - dusk::ScopeValue folder(SDL_GetPrefPath(dusk::OrgName, dusk::AppName), SDL_free); - if (folder.value == nullptr) { - DuskConfigLog.error("Failed to get user preference path: %s", SDL_GetError()); - return ""; - } - - return fmt::format("{}{}", folder.value, ConfigFileName); + return fmt::format("{}{}", configPath, ConfigFileName); } ConfigVarBase::ConfigVarBase(const char* name, const ConfigImplBase* impl) : name(name), registered(false), layer(ConfigVarLayer::Default), impl(impl) { @@ -151,11 +143,11 @@ void dusk::config::FinishRegistration() { } void dusk::config::LoadFromUserPreferences() { - const auto configPath = GetConfigJsonPath(); - if (configPath.empty()) { + const auto configJsonPath = GetConfigJsonPath(); + if (configJsonPath.empty()) { return; } - LoadFromFileName(configPath.c_str()); + LoadFromFileName(configJsonPath.c_str()); } static void LoadFromPath(const char* path) { @@ -202,12 +194,12 @@ void dusk::config::LoadFromFileName(const char* path) { } void dusk::config::Save() { - const auto configPath = GetConfigJsonPath(); - if (configPath.empty()) { + const auto configJsonPath = GetConfigJsonPath(); + if (configJsonPath.empty()) { return; } - DuskConfigLog.info("Saving config to '{}'", configPath); + DuskConfigLog.info("Saving config to '{}'", configJsonPath); json j; @@ -217,7 +209,7 @@ void dusk::config::Save() { } } - io::FileStream::WriteAllText(configPath.c_str(), j.dump(4)); + io::FileStream::WriteAllText(configJsonPath.c_str(), j.dump(4)); } ConfigVarBase* dusk::config::GetConfigVar(std::string_view name) { diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index ba86f17d79..16d2644f69 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -44,6 +44,7 @@ #include #include #include "SSystem/SComponent/c_API.h" +#include "dusk/appname.hpp" #include "dusk/dusk.h" #include "dusk/logging.h" #include "dusk/time.h" @@ -56,6 +57,7 @@ #include #include +#include "SDL3/SDL_filesystem.h" #include "cxxopts.hpp" #include "dusk/config.hpp" @@ -108,6 +110,7 @@ s32 LOAD_COPYDATE(void*) { } AuroraInfo auroraInfo; +const char* configPath; void main01(void) { OS_REPORT("\x1b[m"); @@ -263,6 +266,15 @@ static void ApplyCVarOverrides(const cxxopts::OptionValue& option) { } } +static const char* CalculateConfigPath() { + const auto result = SDL_GetPrefPath(dusk::OrgName, dusk::AppName); + if (!result) { + DuskLog.fatal("Unable to get PrefPath: {}", SDL_GetError()); + } + + return result; +} + // ========================================================================= // PC ENTRY POINT // ========================================================================= @@ -299,11 +311,14 @@ int game_main(int argc, char* argv[]) { exit(1); } + configPath = CalculateConfigPath(); + dusk::config::LoadFromUserPreferences(); ApplyCVarOverrides(parsed_arg_options["cvar"]); AuroraConfig config{}; - config.appName = "Dusk"; + config.appName = dusk::AppName; + config.configPath = configPath; config.windowPosX = -1; config.windowPosY = -1; config.windowWidth = 608 * 2; From 49412fae51a18f4e7c32b2a20bf9f4bd3b876d1a Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Sun, 5 Apr 2026 19:20:10 +0200 Subject: [PATCH 05/72] appname.hpp -> app_info.hpp --- include/dusk/{appname.hpp => app_info.hpp} | 0 src/m_Do/m_Do_main.cpp | 8 ++++---- 2 files changed, 4 insertions(+), 4 deletions(-) rename include/dusk/{appname.hpp => app_info.hpp} (100%) diff --git a/include/dusk/appname.hpp b/include/dusk/app_info.hpp similarity index 100% rename from include/dusk/appname.hpp rename to include/dusk/app_info.hpp diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index 16d2644f69..ffe6bb5ab6 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -44,12 +44,12 @@ #include #include #include "SSystem/SComponent/c_API.h" -#include "dusk/appname.hpp" +#include "dusk/app_info.hpp" #include "dusk/dusk.h" -#include "dusk/logging.h" -#include "dusk/time.h" -#include "dusk/main.h" #include "dusk/imgui/ImGuiEngine.hpp" +#include "dusk/logging.h" +#include "dusk/main.h" +#include "dusk/time.h" #include #include From bfbf524be2815276969be58fd2495bd6aadf07b8 Mon Sep 17 00:00:00 2001 From: Max Roncace Date: Sun, 5 Apr 2026 16:48:44 -0400 Subject: [PATCH 06/72] Build "game" as a static library (#236) * Build "game" as a static library This effectively renames the "game" lib to game_base, builds it and game_debug as object libraries, and links both into a single static library. There is also some refactoring done to remove the game_base's dependencies on game_debug's compile-time parameters which have now been moved into shared buildscript variables. * Fix build --------- Co-authored-by: PJB3005 --- CMakeLists.txt | 85 +++++++++++++++++++++++++++++++------------------- 1 file changed, 53 insertions(+), 32 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e3fbb82437..dbf9a92e88 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,9 +88,37 @@ message(STATUS "dusk: TP Version: ${DUSK_TP_VERSION}") source_group("dolzel" FILES ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${JSYSTEM_FILES} ${JSYSTEM_DEBUG_FILES} ${REL_FILES}) source_group("dusk" FILES ${DUSK_FILES}) +set(GAME_COMPILE_DEFS TARGET_PC AVOID_UB=1 VERSION=0 + DUSK_TP_VERSION="${DUSK_TP_VERSION}" DUSK_GAME_NAME="${DUSK_GAME_NAME}" DUSK_GAME_VERSION="${DUSK_GAME_VERSION}") + +set(GAME_INCLUDE_DIRS + include + src + assets/${DUSK_TP_VERSION} + libs/JSystem/include + libs + extern/aurora/include/dolphin + extern + ${CMAKE_SOURCE_DIR}/build/${DUSK_TP_VERSION}/include + build/${DUSK_TP_VERSION}/include) + +set(GAME_LIBS aurora::core aurora::gx aurora::gd aurora::si aurora::vi aurora::pad aurora::mtx aurora::os aurora::dvd + aurora::card freeverb cxxopts::cxxopts absl::flat_hash_map) + +if (DUSK_MOVIE_SUPPORT_REAL) + if (TARGET libjpeg-turbo::turbojpeg-static) + message(STATUS "dusk: Linking against libjpeg-turbo static library") + list(APPEND GAME_LIBS "libjpeg-turbo::turbojpeg-static") + else () + message(STATUS "dusk: Linking against libjpeg-turbo shared library") + list(APPEND GAME_LIBS "libjpeg-turbo::turbojpeg") + endif () + list(APPEND GAME_COMPILE_DEFS MOVIE_SUPPORT=1) +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 -add_library(game_debug STATIC ${JSYSTEM_DEBUG_FILES} ${SSYSTEM_FILES} +add_library(game_debug OBJECT ${JSYSTEM_DEBUG_FILES} ${SSYSTEM_FILES} src/dusk/audio/DuskAudioSystem.cpp src/dusk/audio/JASCriticalSection.cpp src/dusk/audio/DuskDsp.hpp @@ -98,40 +126,33 @@ add_library(game_debug STATIC ${JSYSTEM_DEBUG_FILES} ${SSYSTEM_FILES} src/dusk/audio/Adpcm.cpp src/dusk/audio/Adpcm.hpp src/dusk/audio/DspStub.cpp) -target_compile_definitions(game_debug PRIVATE TARGET_PC AVOID_UB=1 VERSION=0 $<$:DEBUG=1>) -# Make these properties PUBLIC so that the regular game target also sees them. -target_include_directories(game_debug PUBLIC - include - src - assets/${DUSK_TP_VERSION} - libs/JSystem/include - libs - extern/aurora/include/dolphin - extern - ${CMAKE_SOURCE_DIR}/build/${DUSK_TP_VERSION}/include - build/${DUSK_TP_VERSION}/include) -target_link_libraries(game_debug PUBLIC aurora::core aurora::gx aurora::gd aurora::si aurora::vi aurora::pad aurora::mtx aurora::os aurora::dvd aurora::card freeverb) - -set(CMAKE_WINDOWS_EXPORT_ALL_SYMBOLS ON) -add_library(game SHARED ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${SSYSTEM_FILES} ${JSYSTEM_FILES} ${REL_FILES} ${DUSK_FILES} ${DOLPHIN_FILES} +# game_base is for all other game code files +add_library(game_base OBJECT ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${JSYSTEM_FILES} ${REL_FILES} ${DUSK_FILES} + ${DOLPHIN_FILES} src/dusk/imgui/ImGuiStubLog.cpp src/dusk/imgui/ImGuiAudio.cpp) -target_link_libraries(game PRIVATE game_debug cxxopts::cxxopts absl::flat_hash_map freeverb) -if (DUSK_MOVIE_SUPPORT_REAL) - if (TARGET libjpeg-turbo::turbojpeg-static) - message(STATUS "dusk: Linking against libjpeg-turbo static library") - target_link_libraries(game PRIVATE libjpeg-turbo::turbojpeg-static) - else () - message(STATUS "dusk: Linking against libjpeg-turbo shared library") - target_link_libraries(game PRIVATE libjpeg-turbo::turbojpeg) - endif () - target_compile_definitions(game PRIVATE MOVIE_SUPPORT=1) -endif () -target_compile_definitions(game PRIVATE TARGET_PC AVOID_UB=1 VERSION=0 NDEBUG=1 NDEBUG_DEFINED=1 DEBUG_DEFINED=0 - DUSK_TP_VERSION="${DUSK_TP_VERSION}" DUSK_GAME_NAME="${DUSK_GAME_NAME}" DUSK_GAME_VERSION="${DUSK_GAME_VERSION}") -target_precompile_headers(game PRIVATE "$<$:${CMAKE_SOURCE_DIR}/include/dusk_pch.hpp>") +target_compile_definitions(game_debug PRIVATE ${GAME_COMPILE_DEFS} $<$:DEBUG=1>) +target_compile_definitions(game_base PRIVATE ${GAME_COMPILE_DEFS} NDEBUG=1 NDEBUG_DEFINED=1 DEBUG_DEFINED=0) + +# only apply PCH to game_base since not all headers are necessarily validated with DEBUG=1 +target_precompile_headers(game_base PRIVATE "$<$:${CMAKE_SOURCE_DIR}/include/dusk_pch.hpp>") + +target_include_directories(game_debug PRIVATE ${GAME_INCLUDE_DIRS}) +target_include_directories(game_base PRIVATE ${GAME_INCLUDE_DIRS}) + +# This implicitly pulls in the library include directories even though no +# linking actually takes place for object libraries +target_link_libraries(game_debug PRIVATE ${GAME_LIBS}) +target_link_libraries(game_base PRIVATE ${GAME_LIBS}) + +# Combined game library +add_library(game STATIC + $ + $) +target_link_libraries(game PUBLIC ${GAME_LIBS}) + add_executable(dusk src/dusk/main.cpp) target_compile_definitions(dusk PRIVATE TARGET_PC AVOID_UB=1 VERSION=0) target_include_directories(dusk PRIVATE include) @@ -145,7 +166,7 @@ add_custom_command(TARGET dusk POST_BUILD ) include(extern/aurora/cmake/AuroraCopyRuntimeDLLs.cmake) -aurora_copy_runtime_dlls(dusk game) +aurora_copy_runtime_dlls(dusk) if (DUSK_SELECTED_OPT) if (CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") From 3414cec13c2bd54b963da4bd51056b60caff7226 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Sat, 21 Mar 2026 13:41:46 -0400 Subject: [PATCH 07/72] initial commit with working 3D view at all times --- CMakeLists.txt | 2 +- include/m_Do/m_Do_graphic.h | 12 ++++++++++++ src/d/d_menu_collect.cpp | 2 +- src/d/d_menu_item_explain.cpp | 5 +++++ src/d/d_meter2_draw.cpp | 33 +++++++++++++++++++++++++++++++++ src/d/d_meter_HIO.cpp | 2 +- src/d/d_meter_map.cpp | 6 ++++++ src/m_Do/m_Do_graphic.cpp | 31 +++++++++++++++++++++++++++++++ 8 files changed, 90 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index dbf9a92e88..cfb76e85ff 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,7 +88,7 @@ message(STATUS "dusk: TP Version: ${DUSK_TP_VERSION}") source_group("dolzel" FILES ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${JSYSTEM_FILES} ${JSYSTEM_DEBUG_FILES} ${REL_FILES}) source_group("dusk" FILES ${DUSK_FILES}) -set(GAME_COMPILE_DEFS TARGET_PC AVOID_UB=1 VERSION=0 +set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT AVOID_UB=1 VERSION=0 DUSK_TP_VERSION="${DUSK_TP_VERSION}" DUSK_GAME_NAME="${DUSK_GAME_NAME}" DUSK_GAME_VERSION="${DUSK_GAME_VERSION}") set(GAME_INCLUDE_DIRS diff --git a/include/m_Do/m_Do_graphic.h b/include/m_Do/m_Do_graphic.h index 3d560efeb6..d69ab59a9c 100644 --- a/include/m_Do/m_Do_graphic.h +++ b/include/m_Do/m_Do_graphic.h @@ -117,6 +117,13 @@ public: static void setTickRate(u32 rate) { JFWDisplay::getManager()->setTickRate(rate); } static void waitBlanking(int wait) { JFWDisplay::getManager()->waitBlanking(wait); } +#if TARGET_PC + static f32 hudAspectScaleDown; + static f32 hudAspectScaleUp; + static f32 ScaleHUDXLeft(f32 baseX) { return getMinXF() + baseX; } + static f32 ScaleHUDXRight(f32 baseX) { return -getMinXF() + baseX; } +#endif + static void setBlureMtx(const Mtx m) { cMtx_copy(m, mBlureMtx); } @@ -266,7 +273,12 @@ public: #if WIDESCREEN_SUPPORT static void setTvSize(); + #if TARGET_PC + static void onWide(f32 width, f32 height); + #else static void onWide(); + #endif + static void offWide(); static u8 isWide(); diff --git a/src/d/d_menu_collect.cpp b/src/d/d_menu_collect.cpp index c1281a86c2..c30bd85f9b 100644 --- a/src/d/d_menu_collect.cpp +++ b/src/d/d_menu_collect.cpp @@ -2555,7 +2555,7 @@ f32 dMenu_Collect3D_c::mViewOffsetY = -100.0f; void dMenu_Collect3D_c::setupItem3D(Mtx param_0) { #if TARGET_PC - f32 scaleFactor = mDoGph_gInf_c::getWidth() / FB_WIDTH; // TODO: get display pixel density from aurora + f32 scaleFactor = mDoGph_gInf_c::getHeight() / FB_HEIGHT; GXSetViewport(0.0f, mViewOffsetY * scaleFactor, mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight(), 0.0f, 1.0f); #else GXSetViewport(0.0f, mViewOffsetY, FB_WIDTH, FB_HEIGHT, 0.0f, 1.0f); diff --git a/src/d/d_menu_item_explain.cpp b/src/d/d_menu_item_explain.cpp index 21a3a32fdd..c106b4bd8c 100644 --- a/src/d/d_menu_item_explain.cpp +++ b/src/d/d_menu_item_explain.cpp @@ -310,7 +310,12 @@ void dMenu_ItemExplain_c::draw(J2DOrthoGraph* i_graph) { mpLabel->scale(g_ringHIO.mItemDescTitleScale, g_ringHIO.mItemDescTitleScale); mpLabel->paneTrans(g_ringHIO.mItemDescTitlePosX, g_ringHIO.mItemDescTitlePosY); if (mpBackTex != NULL) { + #if TARGET_PC + mpBackTex->draw(mDoGph_gInf_c::ScaleHUDXLeft(0.0f), 0.0f, mDoGph_gInf_c::getWidthF(), + FB_HEIGHT, false, false, false); + #else mpBackTex->draw(0.0f, 0.0f, FB_WIDTH, FB_HEIGHT, false, false, false); + #endif } if (field_0xc8 != field_0xd0) { field_0xd0 = field_0xc8; diff --git a/src/d/d_meter2_draw.cpp b/src/d/d_meter2_draw.cpp index f222ee752a..ab4b1cc86c 100644 --- a/src/d/d_meter2_draw.cpp +++ b/src/d/d_meter2_draw.cpp @@ -564,7 +564,13 @@ void dMeter2Draw_c::exec(u32 i_status) { { mButtonsPosX = g_drawHIO.mMainHUDButtonsPosX; mButtonsPosY = g_drawHIO.mMainHUDButtonsPosY; + + #if TARGET_PC + mpButtonParent->paneTrans(mDoGph_gInf_c::ScaleHUDXRight(g_drawHIO.mMainHUDButtonsPosX), + g_drawHIO.mMainHUDButtonsPosY); + #else mpButtonParent->paneTrans(g_drawHIO.mMainHUDButtonsPosX, g_drawHIO.mMainHUDButtonsPosY); + #endif } if (mButtonsScale != g_drawHIO.mMainHUDButtonsScale) { @@ -1476,7 +1482,11 @@ 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 + mpLifeParent->paneTrans(mDoGph_gInf_c::ScaleHUDXLeft(i_posX), i_posY); + #else mpLifeParent->paneTrans(i_posX, i_posY); + #endif } void dMeter2Draw_c::setAlphaLifeChange(bool param_0) { @@ -1589,7 +1599,14 @@ void dMeter2Draw_c::drawKanteraScreen(u8 i_meterType) { mpMagicFrameR->move(field_0x59c[i_meterType], field_0x5a8[i_meterType]); mpMagicBase->resize(field_0x5b4[i_meterType], field_0x5c0[i_meterType]); mpMagicParent->scale(field_0x5cc[i_meterType], field_0x5d8[i_meterType]); + + #if TARGET_PC + mpMagicParent->paneTrans(mDoGph_gInf_c::ScaleHUDXLeft(field_0x5e4[i_meterType]), + field_0x5f0[i_meterType]); + #else mpMagicParent->paneTrans(field_0x5e4[i_meterType], field_0x5f0[i_meterType]); + #endif + mpKanteraScreen->draw(0.0f, 0.0f, graf_ctx); } @@ -1854,7 +1871,12 @@ void dMeter2Draw_c::drawLightDrop(u8 i_num, u8 i_needNum, f32 i_posX, f32 i_posY mLightDropVesselScale = i_vesselScale; mpLightDropParent->scale(mLightDropVesselScale * field_0x6f8, mLightDropVesselScale * field_0x6f8); + + #if TARGET_PC + mpLightDropParent->paneTrans(mDoGph_gInf_c::ScaleHUDXRight(i_posX), i_posY); + #else mpLightDropParent->paneTrans(i_posX, i_posY); + #endif } void dMeter2Draw_c::setAlphaLightDropChange(bool unused) {} @@ -2001,7 +2023,13 @@ void dMeter2Draw_c::drawRupee(s16 i_rupeeNum) { mpRupeeKeyParent->scale(g_drawHIO.mRupeeKeyScale * field_0x718, g_drawHIO.mRupeeKeyScale * field_0x718); + + #if TARGET_PC + mpRupeeKeyParent->paneTrans(mDoGph_gInf_c::ScaleHUDXRight(g_drawHIO.mRupeeKeyPosX), + g_drawHIO.mRupeeKeyPosY); + #else 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); @@ -2582,7 +2610,12 @@ void dMeter2Draw_c::drawButtonCross(f32 i_posX, f32 i_posY) { mpButtonCrossParent->scale(g_drawHIO.mButtonCrossScale, g_drawHIO.mButtonCrossScale); mpTextI->scale(g_drawHIO.mButtonCrossTextScale, g_drawHIO.mButtonCrossTextScale); mpTextM->scale(g_drawHIO.mButtonCrossTextScale, g_drawHIO.mButtonCrossTextScale); + + #if TARGET_PC + mpButtonCrossParent->paneTrans(mDoGph_gInf_c::ScaleHUDXLeft(i_posX), i_posY); + #else mpButtonCrossParent->paneTrans(i_posX, i_posY); + #endif } void dMeter2Draw_c::setAlphaButtonCrossAnimeMin() { diff --git a/src/d/d_meter_HIO.cpp b/src/d/d_meter_HIO.cpp index 685f9c580c..240dcb8d45 100644 --- a/src/d/d_meter_HIO.cpp +++ b/src/d/d_meter_HIO.cpp @@ -3003,7 +3003,7 @@ void dMeter_drawHIO_c::updateFMsgDebug() { #endif dMeter_ringHIO_c::dMeter_ringHIO_c() { -#if WIDESCREEN_SUPPORT +#if WIDESCREEN_SUPPORT && !TARGET_PC updateOnWide(); #else mRingRadiusH = 175.0f; diff --git a/src/d/d_meter_map.cpp b/src/d/d_meter_map.cpp index 7e55d899fd..362a996d60 100644 --- a/src/d/d_meter_map.cpp +++ b/src/d/d_meter_map.cpp @@ -628,7 +628,13 @@ void dMeterMap_c::draw() { #endif mMapJ2DPicture->setAlpha(alpha); + #if TARGET_PC + mMapJ2DPicture->draw(mDoGph_gInf_c::ScaleHUDXLeft(drawPosX), drawPosY, sizeX, sizeY, false, false, + false); + #else mMapJ2DPicture->draw(drawPosX, drawPosY, sizeX, sizeY, false, false, false); + #endif + mMapJ2DPicture->calcMtx(); } } diff --git a/src/m_Do/m_Do_graphic.cpp b/src/m_Do/m_Do_graphic.cpp index a7a09a8d87..3c2b0240bc 100644 --- a/src/m_Do/m_Do_graphic.cpp +++ b/src/m_Do/m_Do_graphic.cpp @@ -552,8 +552,16 @@ const tvSize l_tvSize[2] = { {808, 448}, }; +#if TARGET_PC +tvSize pc_tvSize = {608, 448}; +#endif + void mDoGph_gInf_c::setTvSize() { +#if TARGET_PC + const tvSize* tvsize = &pc_tvSize; +#else const tvSize* tvsize = &l_tvSize[mWide]; +#endif m_width = tvsize->width; m_height = tvsize->height; @@ -572,18 +580,35 @@ void mDoGph_gInf_c::setTvSize() { m_aspect = m_widthF / m_heightF; m_scale = m_aspect / 1.3571428f; m_invScale = 1.0f / m_scale; + +#if TARGET_PC + hudAspectScaleDown = 1.3571428f / mDoGph_gInf_c::getAspect(); + hudAspectScaleUp = 1.0f / hudAspectScaleDown; +#endif } +#if TARGET_PC +void mDoGph_gInf_c::onWide(f32 width, f32 height) { + mWide = TRUE; + pc_tvSize.width = width; + pc_tvSize.height = height; + setTvSize(); +} +#else void mDoGph_gInf_c::onWide() { mWide = TRUE; setTvSize(); dMeter2Info_onWide2D(); } +#endif void mDoGph_gInf_c::offWide() { mWide = FALSE; setTvSize(); + +#if !TARGET_PC dMeter2Info_offWide2D(); +#endif } void mDoGph_gInf_c::onWideZoom() { @@ -686,10 +711,16 @@ void mDoGph_gInf_c::setWideZoomLightProjection(Mtx& m) { #endif #if TARGET_PC +f32 mDoGph_gInf_c::hudAspectScaleDown = 1.0f; +f32 mDoGph_gInf_c::hudAspectScaleUp = 1.0f; + void mDoGph_gInf_c::setWindowSize(AuroraWindowSize const& size) { JUTVideo::getManager()->setWindowSize(size); dComIfGp_setWindow(0, 0.0f, 0.0f, getWidth(), getHeight(), 0.0f, 1.0f, 0, 2); mFader->mBox.set(0, 0, getWidth(), getHeight()); + + f32 newWidth = (getWidth() / getHeight()) * 448.0f; + onWide(newWidth, 448.0f); } #endif From bbe205d3bf318bf918aedf847869b4ebd866eccb Mon Sep 17 00:00:00 2001 From: Irastris Date: Mon, 30 Mar 2026 04:09:05 -0400 Subject: [PATCH 08/72] Fix fmap cursor and options screen --- src/d/d_menu_fmap2D.cpp | 4 ++++ src/d/d_menu_option.cpp | 12 ++++++++++++ 2 files changed, 16 insertions(+) diff --git a/src/d/d_menu_fmap2D.cpp b/src/d/d_menu_fmap2D.cpp index 29ec5db854..eac8d1992b 100644 --- a/src/d/d_menu_fmap2D.cpp +++ b/src/d/d_menu_fmap2D.cpp @@ -359,7 +359,11 @@ void dMenu_Fmap2DBack_c::draw() { drawDebugRegionArea(); } +#if TARGET_PC + grafPort->scissor(scissorLeft, scissorTop, mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight()); +#else grafPort->scissor(scissorLeft, scissorTop, scissorWidth, scissorHeight); +#endif grafPort->setScissor(); if (isArrowDrawFlag()) { diff --git a/src/d/d_menu_option.cpp b/src/d/d_menu_option.cpp index abe9f864ce..9384bc06b9 100644 --- a/src/d/d_menu_option.cpp +++ b/src/d/d_menu_option.cpp @@ -555,13 +555,25 @@ void dMenu_Option_c::_draw() { #endif mpBlackTex->setAlpha(0xff); +#if TARGET_PC + mpBlackTex->draw(mDoGph_gInf_c::getMinXF(), mDoGph_gInf_c::getMinYF(), mDoGph_gInf_c::getWidthF(), mDoGph_gInf_c::getHeightF(), 0, 0, 0); +#else mpBlackTex->draw(0.0f, 0.0f, FB_WIDTH, FB_HEIGHT, 0, 0, 0); +#endif mpBackScreen->draw(0.0f, 0.0f, ctx); f32 alpha = (f32)g_drawHIO.mOptionScreen.mBackgroundAlpha * (f32)field_0x374; mpBlackTex->setAlpha(alpha); +#if TARGET_PC + mpBlackTex->draw(mDoGph_gInf_c::getMinXF(), mDoGph_gInf_c::getMinYF(), mDoGph_gInf_c::getWidthF(), mDoGph_gInf_c::getHeightF(), 0, 0, 0); +#else mpBlackTex->draw(0.0f, 0.0f, FB_WIDTH, FB_HEIGHT, 0, 0, 0); +#endif mpScreen->draw(0.0f, 0.0f, ctx); mpClipScreen->draw(0.0f, 0.0f, ctx); +#if TARGET_PC + ctx->scissor(0.0f, 0.0f, mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight()); + ctx->setScissor(); +#endif mpShadowScreen->draw(0.0f, 0.0f, ctx); if (field_0x3f3 == 1 || field_0x3f3 == 2 || field_0x3f3 == 3) { mpTVScreen->draw(0.0f, 0.0f, ctx); From 74d0c0b28241a0919ef410d99c440aca93878a46 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Tue, 31 Mar 2026 13:37:18 -0400 Subject: [PATCH 09/72] scale bloom depending on the window size --- src/m_Do/m_Do_graphic.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/m_Do/m_Do_graphic.cpp b/src/m_Do/m_Do_graphic.cpp index 3c2b0240bc..2657b0cd16 100644 --- a/src/m_Do/m_Do_graphic.cpp +++ b/src/m_Do/m_Do_graphic.cpp @@ -1316,7 +1316,13 @@ void mDoGph_gInf_c::bloom_c::draw() { GXSetTexCoordGen(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, 0x3c); for (int texCoord = (int)GX_TEXCOORD1; texCoord < (int)GX_MAX_TEXCOORD; texCoord++) { GXSetTexCoordGen((GXTexCoordID)texCoord, GX_TG_MTX2x4, GX_TG_TEX0, iVar11); + + #if TARGET_PC + f32 dVar15 = mBlureSize * ((448.0f / getHeight()) / 6400.0f); + #else f32 dVar15 = mBlureSize * (1.0f / 6400.0f); + #endif + mDoMtx_stack_c::transS((dVar15 * cM_scos(sVar10)) * getInvScale(), dVar15 * cM_ssin(sVar10), 0.0f); GXLoadTexMtxImm(mDoMtx_stack_c::get(), iVar11, GX_MTX2x4); From 9d61f300c1baf5c24b31f1e223d50d2dd894f294 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Tue, 31 Mar 2026 13:45:53 -0400 Subject: [PATCH 10/72] fix reticle position --- src/d/actor/d_a_player.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/d/actor/d_a_player.cpp b/src/d/actor/d_a_player.cpp index f38fe15a3b..a2e56068d7 100644 --- a/src/d/actor/d_a_player.cpp +++ b/src/d/actor/d_a_player.cpp @@ -402,11 +402,12 @@ void daPy_sightPacket_c::setSight() { #if TARGET_PC mDoLib_project(&mPos, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); + mDoMtx_stack_c::transS(proj.x - 16.0f, proj.y - 8.0f, proj.z); #else mDoLib_project(&mPos, &proj); + mDoMtx_stack_c::transS(proj.x, proj.y, proj.z); #endif - mDoMtx_stack_c::transS(proj.x, proj.y, proj.z); mDoMtx_stack_c::scaleM(32.0f, 32.0f, 32.0f); mDoMtx_copy(mDoMtx_stack_c::get(), mProjMtx); dComIfGd_set2DXlu(this); From 483b7eaecc37c1afe1df5ea50a2504a08bb6b049 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Tue, 31 Mar 2026 13:48:23 -0400 Subject: [PATCH 11/72] nvm im dumb --- src/d/actor/d_a_player.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/d/actor/d_a_player.cpp b/src/d/actor/d_a_player.cpp index a2e56068d7..f38fe15a3b 100644 --- a/src/d/actor/d_a_player.cpp +++ b/src/d/actor/d_a_player.cpp @@ -402,12 +402,11 @@ void daPy_sightPacket_c::setSight() { #if TARGET_PC mDoLib_project(&mPos, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); - mDoMtx_stack_c::transS(proj.x - 16.0f, proj.y - 8.0f, proj.z); #else mDoLib_project(&mPos, &proj); - mDoMtx_stack_c::transS(proj.x, proj.y, proj.z); #endif + mDoMtx_stack_c::transS(proj.x, proj.y, proj.z); mDoMtx_stack_c::scaleM(32.0f, 32.0f, 32.0f); mDoMtx_copy(mDoMtx_stack_c::get(), mProjMtx); dComIfGd_set2DXlu(this); From 49ad699eb3789f7527710bc1e2ab69d59c74594e Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Tue, 31 Mar 2026 14:19:51 -0400 Subject: [PATCH 12/72] fix reticles for good --- include/m_Do/m_Do_graphic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/m_Do/m_Do_graphic.h b/include/m_Do/m_Do_graphic.h index d69ab59a9c..421e1ae47f 100644 --- a/include/m_Do/m_Do_graphic.h +++ b/include/m_Do/m_Do_graphic.h @@ -8,7 +8,7 @@ #include #endif -#if WIDESCREEN_SUPPORT +#if WIDESCREEN_SUPPORT && !TARGET_PC #define FB_WIDTH (640) #define FB_HEIGHT (456) #else From ae1018318a1460766144f6b4ac6a8aaef4a42dd5 Mon Sep 17 00:00:00 2001 From: Lurs <2795933+Lurs@users.noreply.github.com> Date: Tue, 31 Mar 2026 23:36:53 +0200 Subject: [PATCH 13/72] Fix arrows for dungeon map --- src/d/d_menu_dmap.cpp | 27 +++++++++++++++++++++++++-- 1 file changed, 25 insertions(+), 2 deletions(-) diff --git a/src/d/d_menu_dmap.cpp b/src/d/d_menu_dmap.cpp index 97721d9dd2..739dfc7843 100644 --- a/src/d/d_menu_dmap.cpp +++ b/src/d/d_menu_dmap.cpp @@ -864,7 +864,16 @@ void dMenu_DmapBg_c::draw() { J2DOrthoGraph* grafContext = (J2DOrthoGraph*)dComIfGp_getCurrentGrafPort(); grafContext->setup2D(); +#if TARGET_PC + // GXGetScissor uses 11-bit GC register fields (max 2047) which overflow + // at window widths > ~1705px, producing garbage values on restore. + scissor_left = 0; + scissor_top = 0; + scissor_width = (u32)mDoGph_gInf_c::getWidth(); + scissor_height = (u32)mDoGph_gInf_c::getHeight(); +#else GXGetScissor(&scissor_left, &scissor_top, &scissor_width, &scissor_height); +#endif #if TARGET_PC grafContext->scissor(field_0xd94, 0.0f, mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight()); #else @@ -876,8 +885,8 @@ void dMenu_DmapBg_c::draw() { dMenu_Dmap_c::myclass->drawFloorScreenBack(mFloorScreen, field_0xd94, field_0xd98, grafContext); #if TARGET_PC - f32 dVar21 = mDoGph_gInf_c::getWidth() / FB_WIDTH; - f32 dVar16 = mDoGph_gInf_c::getHeight() / FB_HEIGHT; + f32 dVar21 = mDoGph_gInf_c::getWidthF() / mDoGph_gInf_c::getWidth(); + f32 dVar16 = mDoGph_gInf_c::getHeightF() / mDoGph_gInf_c::getHeight(); #else f32 dVar21 = mDoGph_gInf_c::getWidthF() / FB_WIDTH; f32 dVar16 = mDoGph_gInf_c::getHeightF() / FB_HEIGHT; @@ -890,8 +899,15 @@ void dMenu_DmapBg_c::draw() { Mtx mtx; Vec local_200 = pane.getGlobalVtx(center_pane, &mtx, 0, false, 0); Vec local_20c = pane.getGlobalVtx(center_pane, &mtx, 3, false, 0); +#if TARGET_PC + grafContext->scissor(((local_200.x - mDoGph_gInf_c::getMinXF()) / dVar21), + ((local_200.y - mDoGph_gInf_c::getMinYF()) / dVar16), + ((local_20c.x - local_200.x) / dVar21), + (2.0f + (local_20c.y - local_200.y)) / dVar16); +#else grafContext->scissor(((local_200.x - mDoGph_gInf_c::getMinXF()) / dVar21), ((local_200.y / dVar16) / dVar16), ((local_20c.x - local_200.x) / dVar21), 2.0f + (local_20c.y - local_200.y)); +#endif grafContext->setScissor(); f32 dVar17 = field_0xd8c / 255.0f; @@ -925,10 +941,17 @@ void dMenu_DmapBg_c::draw() { Mtx local_110; Vec local_218 = pane.getGlobalVtx(center_pane, &local_110, 0, false, 0); Vec local_224 = pane.getGlobalVtx(center_pane, &local_110, 3, false, 0); +#if TARGET_PC + f32 local_294 = ((local_218.x - mDoGph_gInf_c::getMinXF()) / dVar21); + f32 local_298 = ((local_218.y - mDoGph_gInf_c::getMinYF()) / dVar16); + f32 local_29c = ((local_224.x - local_218.x) / dVar21); + f32 local_2a0 = (2.0f + (local_224.y - local_218.y)) / dVar16; +#else f32 local_294 = ((local_218.x - mDoGph_gInf_c::getMinXF()) / dVar21); f32 local_298 = ((local_218.y / dVar16) / dVar16); f32 local_29c = ((local_224.x - local_218.x) / dVar21); f32 local_2a0 = 2.0f + (local_224.y - local_218.y); +#endif grafContext->scissor(local_294, local_298, local_29c, local_2a0); grafContext->setScissor(); From 769eba2e213177a91bb7a52449b16c535c382221 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Wed, 1 Apr 2026 19:25:27 -0400 Subject: [PATCH 14/72] fix building --- src/d/d_meter_map.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/d/d_meter_map.cpp b/src/d/d_meter_map.cpp index 362a996d60..6b78e2242b 100644 --- a/src/d/d_meter_map.cpp +++ b/src/d/d_meter_map.cpp @@ -629,8 +629,8 @@ void dMeterMap_c::draw() { mMapJ2DPicture->setAlpha(alpha); #if TARGET_PC - mMapJ2DPicture->draw(mDoGph_gInf_c::ScaleHUDXLeft(drawPosX), drawPosY, sizeX, sizeY, false, false, - false); + mMapJ2DPicture->draw(mDoGph_gInf_c::ScaleHUDXLeft(drawPosX), drawPosY, sizeX, sizeY, false, + false, false); #else mMapJ2DPicture->draw(drawPosX, drawPosY, sizeX, sizeY, false, false, false); #endif From fe02fb8e612274edc0efbd7ad3bcf60cfca48824 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Wed, 1 Apr 2026 20:20:09 -0400 Subject: [PATCH 15/72] Fix underwater effect + Fading to work at any aspect ratio --- src/d/d_ovlp_fade2.cpp | 6 ++++++ src/d/d_ovlp_fade3.cpp | 6 ++++++ src/m_Do/m_Do_graphic.cpp | 6 ++++++ 3 files changed, 18 insertions(+) diff --git a/src/d/d_ovlp_fade2.cpp b/src/d/d_ovlp_fade2.cpp index 093aaadddd..37dbeedba2 100644 --- a/src/d/d_ovlp_fade2.cpp +++ b/src/d/d_ovlp_fade2.cpp @@ -51,8 +51,14 @@ void dOvlpFd2_dlst_c::draw() { GXEnd(); Mtx44 m; + + #if TARGET_PC + C_MTXPerspective(m, 60.0f, 1.3571428f, 100.0f, 100000.0f); + #else C_MTXPerspective(m, 60.0f, mDoGph_gInf_c::getWidthF() / mDoGph_gInf_c::getHeightF(), 100.0f, 100000.0f); + #endif + GXSetProjection(m, GX_PERSPECTIVE); #ifdef TARGET_PC mDoGph_gInf_c::getFrameBufferTexObj()->reset(); diff --git a/src/d/d_ovlp_fade3.cpp b/src/d/d_ovlp_fade3.cpp index 70304451fb..d6f432f3ee 100644 --- a/src/d/d_ovlp_fade3.cpp +++ b/src/d/d_ovlp_fade3.cpp @@ -64,8 +64,14 @@ void dOvlpFd3_dlst_c::draw() { GXEnd(); Mtx44 m; + + #if TARGET_PC + C_MTXPerspective(m, 60.0f, 1.3571428f, 100.0f, 100000.0f); + #else C_MTXPerspective(m, 60.0f, mDoGph_gInf_c::getWidthF() / mDoGph_gInf_c::getHeightF(), 100.0f, 100000.0f); + #endif + GXSetProjection(m, GX_PERSPECTIVE); #ifdef TARGET_PC mDoGph_gInf_c::getFrameBufferTexObj()->reset(); diff --git a/src/m_Do/m_Do_graphic.cpp b/src/m_Do/m_Do_graphic.cpp index 2657b0cd16..e4a640fd88 100644 --- a/src/m_Do/m_Do_graphic.cpp +++ b/src/m_Do/m_Do_graphic.cpp @@ -2051,7 +2051,13 @@ int mDoGph_Painter() { Mtx m2; Mtx44 m; + + #if TARGET_PC + C_MTXPerspective(m, AREG_F(8) + 60.0f, 1.3571428f, 1.0f, 100000.0f); + #else C_MTXPerspective(m, AREG_F(8) + 60.0f, mDoGph_gInf_c::getAspect(), 1.0f, 100000.0f); + #endif + GXSetProjection(m, GX_PERSPECTIVE); cXyz sp38c(0.0f, 0.0f, AREG_F(7) + -2.0f); cXyz sp398(0.0f, 1.0f, 0.0f); From ba965ae32d3a229f3e62b19cde85e54c452a58d8 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Wed, 1 Apr 2026 20:24:59 -0400 Subject: [PATCH 16/72] Fix black screen effect when turning into Wolf Link --- src/d/actor/d_a_alink_effect.inc | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/d/actor/d_a_alink_effect.inc b/src/d/actor/d_a_alink_effect.inc index 6e76280ff6..1c02cb54f0 100644 --- a/src/d/actor/d_a_alink_effect.inc +++ b/src/d/actor/d_a_alink_effect.inc @@ -1562,6 +1562,11 @@ void daAlink_c::setMetamorphoseEffectStartLink() { emitter->setGlobalParticleScale(effScale); } #endif + + #if TARGET_PC + static const Vec effWideScale = {mDoGph_gInf_c::getAspect(), 1.0f, 1.0f}; + emitter->setGlobalParticleScale(effWideScale); + #endif } void daAlink_c::setMetamorphoseEffect() { From 0ae4f5a78c6a6b11b9a465d36d78c02c1a860f6e Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Wed, 1 Apr 2026 20:38:59 -0400 Subject: [PATCH 17/72] Fix Wolf Senses vignette on widescreen --- src/d/d_kankyo.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d/d_kankyo.cpp b/src/d/d_kankyo.cpp index ec35ee8bc7..4a07f0be60 100644 --- a/src/d/d_kankyo.cpp +++ b/src/d/d_kankyo.cpp @@ -775,7 +775,7 @@ static void dKy_FiveSenses_fullthrottle_dark_static1() { particle_size.y = 1.0f; particle_size.z = 1.0f; - #if !PLATFORM_GCN + #if !PLATFORM_GCN || TARGET_PC particle_size.x *= mDoGph_gInf_c::getScale(); #endif From 47a8881406a4845722bc5e68b7481a63038e7489 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Thu, 2 Apr 2026 13:45:59 -0400 Subject: [PATCH 18/72] fix full map rendering with multiple ratios, cursor still glitched --- src/d/d_menu_fmap2D.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d/d_menu_fmap2D.cpp b/src/d/d_menu_fmap2D.cpp index eac8d1992b..c9ab812400 100644 --- a/src/d/d_menu_fmap2D.cpp +++ b/src/d/d_menu_fmap2D.cpp @@ -1195,7 +1195,7 @@ f32 dMenu_Fmap2DBack_c::getMapScissorAreaSizeX() { } f32 dMenu_Fmap2DBack_c::getMapScissorAreaSizeRealX() { -#if PLATFORM_GCN +#if PLATFORM_GCN && !TARGET_PC return getMapScissorAreaSizeX(); #else return getMapScissorAreaSizeX() * mDoGph_gInf_c::getScale(); From 6e6f55f1e431827f3795d0041cebf0a441f60469 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Thu, 2 Apr 2026 20:29:07 +0200 Subject: [PATCH 19/72] Fix compile by giving WIDESCREEN_SUPPORT a value --- CMakeLists.txt | 2 +- extern/aurora | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index cfb76e85ff..8be9c03446 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,7 +88,7 @@ message(STATUS "dusk: TP Version: ${DUSK_TP_VERSION}") source_group("dolzel" FILES ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${JSYSTEM_FILES} ${JSYSTEM_DEBUG_FILES} ${REL_FILES}) source_group("dusk" FILES ${DUSK_FILES}) -set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT AVOID_UB=1 VERSION=0 +set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0 DUSK_TP_VERSION="${DUSK_TP_VERSION}" DUSK_GAME_NAME="${DUSK_GAME_NAME}" DUSK_GAME_VERSION="${DUSK_GAME_VERSION}") set(GAME_INCLUDE_DIRS diff --git a/extern/aurora b/extern/aurora index b17da31593..7eb8efcd17 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit b17da315932b85d7d708eaf3e44914f70045a44e +Subproject commit 7eb8efcd172ceed27d120ffb6de86c63d1f3cad0 From 6ca9017e12ef9bec8a05c30cf2915974362d845e Mon Sep 17 00:00:00 2001 From: CraftyBoss Date: Sat, 4 Apr 2026 23:42:00 -0700 Subject: [PATCH 20/72] update HUD positions in updateOnWide instead of when drawing this change makes it so positions will properly update when resizing the window, instead of only updating on room load --- src/d/d_meter2_draw.cpp | 27 --------------------------- src/d/d_meter2_info.cpp | 4 ++++ src/d/d_meter_HIO.cpp | 13 ++++++++++++- src/m_Do/m_Do_graphic.cpp | 4 +--- 4 files changed, 17 insertions(+), 31 deletions(-) diff --git a/src/d/d_meter2_draw.cpp b/src/d/d_meter2_draw.cpp index ab4b1cc86c..58c6e24dc9 100644 --- a/src/d/d_meter2_draw.cpp +++ b/src/d/d_meter2_draw.cpp @@ -565,12 +565,7 @@ void dMeter2Draw_c::exec(u32 i_status) { mButtonsPosX = g_drawHIO.mMainHUDButtonsPosX; mButtonsPosY = g_drawHIO.mMainHUDButtonsPosY; - #if TARGET_PC - mpButtonParent->paneTrans(mDoGph_gInf_c::ScaleHUDXRight(g_drawHIO.mMainHUDButtonsPosX), - g_drawHIO.mMainHUDButtonsPosY); - #else mpButtonParent->paneTrans(g_drawHIO.mMainHUDButtonsPosX, g_drawHIO.mMainHUDButtonsPosY); - #endif } if (mButtonsScale != g_drawHIO.mMainHUDButtonsScale) { @@ -1482,11 +1477,7 @@ 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 - mpLifeParent->paneTrans(mDoGph_gInf_c::ScaleHUDXLeft(i_posX), i_posY); - #else mpLifeParent->paneTrans(i_posX, i_posY); - #endif } void dMeter2Draw_c::setAlphaLifeChange(bool param_0) { @@ -1600,12 +1591,7 @@ void dMeter2Draw_c::drawKanteraScreen(u8 i_meterType) { mpMagicBase->resize(field_0x5b4[i_meterType], field_0x5c0[i_meterType]); mpMagicParent->scale(field_0x5cc[i_meterType], field_0x5d8[i_meterType]); - #if TARGET_PC - mpMagicParent->paneTrans(mDoGph_gInf_c::ScaleHUDXLeft(field_0x5e4[i_meterType]), - field_0x5f0[i_meterType]); - #else mpMagicParent->paneTrans(field_0x5e4[i_meterType], field_0x5f0[i_meterType]); - #endif mpKanteraScreen->draw(0.0f, 0.0f, graf_ctx); } @@ -1872,11 +1858,7 @@ void dMeter2Draw_c::drawLightDrop(u8 i_num, u8 i_needNum, f32 i_posX, f32 i_posY mpLightDropParent->scale(mLightDropVesselScale * field_0x6f8, mLightDropVesselScale * field_0x6f8); - #if TARGET_PC - mpLightDropParent->paneTrans(mDoGph_gInf_c::ScaleHUDXRight(i_posX), i_posY); - #else mpLightDropParent->paneTrans(i_posX, i_posY); - #endif } void dMeter2Draw_c::setAlphaLightDropChange(bool unused) {} @@ -2024,12 +2006,7 @@ void dMeter2Draw_c::drawRupee(s16 i_rupeeNum) { mpRupeeKeyParent->scale(g_drawHIO.mRupeeKeyScale * field_0x718, g_drawHIO.mRupeeKeyScale * field_0x718); - #if TARGET_PC - mpRupeeKeyParent->paneTrans(mDoGph_gInf_c::ScaleHUDXRight(g_drawHIO.mRupeeKeyPosX), - g_drawHIO.mRupeeKeyPosY); - #else 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); @@ -2611,11 +2588,7 @@ void dMeter2Draw_c::drawButtonCross(f32 i_posX, f32 i_posY) { mpTextI->scale(g_drawHIO.mButtonCrossTextScale, g_drawHIO.mButtonCrossTextScale); mpTextM->scale(g_drawHIO.mButtonCrossTextScale, g_drawHIO.mButtonCrossTextScale); - #if TARGET_PC - mpButtonCrossParent->paneTrans(mDoGph_gInf_c::ScaleHUDXLeft(i_posX), i_posY); - #else mpButtonCrossParent->paneTrans(i_posX, i_posY); - #endif } void dMeter2Draw_c::setAlphaButtonCrossAnimeMin() { diff --git a/src/d/d_meter2_info.cpp b/src/d/d_meter2_info.cpp index 3e8d2601c1..820e65dc0d 100644 --- a/src/d/d_meter2_info.cpp +++ b/src/d/d_meter2_info.cpp @@ -1868,12 +1868,16 @@ f32 dMeter2Info_getWide2DPosX(f32* param_0) { } void dMeter2Info_onWide2D() { +#if !TARGET_PC g_ringHIO.updateOnWide(); +#endif g_drawHIO.updateOnWide(); } void dMeter2Info_offWide2D() { +#if !TARGET_PC g_ringHIO.updateOffWide(); +#endif g_drawHIO.updateOffWide(); } #endif diff --git a/src/d/d_meter_HIO.cpp b/src/d/d_meter_HIO.cpp index 240dcb8d45..94b1c79420 100644 --- a/src/d/d_meter_HIO.cpp +++ b/src/d/d_meter_HIO.cpp @@ -2287,7 +2287,18 @@ dMeter_drawHIO_c::dMeter_drawHIO_c() { } #if WIDESCREEN_SUPPORT -void dMeter_drawHIO_c::updateOnWide() {} +void dMeter_drawHIO_c::updateOnWide() { +#if TARGET_PC + g_drawHIO = {}; // this might be a bad idea + + g_drawHIO.mMainHUDButtonsPosX = mDoGph_gInf_c::ScaleHUDXRight(g_drawHIO.mMainHUDButtonsPosX); + g_drawHIO.mRupeeKeyPosX = mDoGph_gInf_c::ScaleHUDXRight(g_drawHIO.mRupeeKeyPosX); + g_drawHIO.mButtonCrossOFFPosX = mDoGph_gInf_c::ScaleHUDXLeft(g_drawHIO.mButtonCrossOFFPosX); + g_drawHIO.mButtonCrossONPosX = mDoGph_gInf_c::ScaleHUDXLeft(g_drawHIO.mButtonCrossONPosX); + g_drawHIO.mLifeGaugePosX = mDoGph_gInf_c::ScaleHUDXLeft(g_drawHIO.mLifeGaugePosX); + g_drawHIO.mLanternMeterPosX = mDoGph_gInf_c::ScaleHUDXLeft(g_drawHIO.mLanternMeterPosX); +#endif +} void dMeter_drawHIO_c::updateOffWide() {} #endif diff --git a/src/m_Do/m_Do_graphic.cpp b/src/m_Do/m_Do_graphic.cpp index e4a640fd88..5c535c2eb1 100644 --- a/src/m_Do/m_Do_graphic.cpp +++ b/src/m_Do/m_Do_graphic.cpp @@ -593,6 +593,7 @@ void mDoGph_gInf_c::onWide(f32 width, f32 height) { pc_tvSize.width = width; pc_tvSize.height = height; setTvSize(); + dMeter2Info_onWide2D(); } #else void mDoGph_gInf_c::onWide() { @@ -605,10 +606,7 @@ void mDoGph_gInf_c::onWide() { void mDoGph_gInf_c::offWide() { mWide = FALSE; setTvSize(); - -#if !TARGET_PC dMeter2Info_offWide2D(); -#endif } void mDoGph_gInf_c::onWideZoom() { From dd11e5a39f7451bb2bd321f4d5fef31731dd45b1 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Sun, 5 Apr 2026 11:15:36 -0400 Subject: [PATCH 21/72] Modified Map Name to work with aspect ratios --- src/d/d_msg_scrn_place.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/d/d_msg_scrn_place.cpp b/src/d/d_msg_scrn_place.cpp index 881852c259..b2c28efc95 100644 --- a/src/d/d_msg_scrn_place.cpp +++ b/src/d/d_msg_scrn_place.cpp @@ -101,13 +101,25 @@ void dMsgScrnPlace_c::exec() { mpFontParent->scale(g_MsgObject_HIO_c.mStageTitleCharSizeX, g_MsgObject_HIO_c.mStageTitleCharSizeY); + +#if TARGET_PC + mpFontParent->paneTrans(mDoGph_gInf_c::ScaleHUDXLeft(g_MsgObject_HIO_c.mStageTitleCharPosX), + g_MsgObject_HIO_c.mStageTitleCharPosY - mScaleX); +#else mpFontParent->paneTrans(g_MsgObject_HIO_c.mStageTitleCharPosX, g_MsgObject_HIO_c.mStageTitleCharPosY - mScaleX); +#endif mpBaseParent->scale(g_MsgObject_HIO_c.mStageTitleBaseSizeX, g_MsgObject_HIO_c.mStageTitleBaseSizeY); + +#if TARGET_PC + mpBaseParent->paneTrans(mDoGph_gInf_c::ScaleHUDXLeft(g_MsgObject_HIO_c.mStageTitleBasePosX), + g_MsgObject_HIO_c.mStageTitleBasePosY - mScaleY); +#else mpBaseParent->paneTrans(g_MsgObject_HIO_c.mStageTitleBasePosX, g_MsgObject_HIO_c.mStageTitleBasePosY - mScaleY); +#endif if (isTalkNow()) { fukiAlpha(1.0f); From 9a277188080fa20aa2aea4790a0fd2188c299388 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Sun, 5 Apr 2026 12:30:27 -0400 Subject: [PATCH 22/72] Almost all menus scaled --- include/d/d_bright_check.h | 3 ++ include/d/d_file_select.h | 3 ++ include/d/d_menu_collect.h | 5 ++ include/d/d_menu_save.h | 5 ++ include/d/d_name.h | 5 ++ src/d/d_bright_check.cpp | 49 +++++++++++++++++++ src/d/d_file_select.cpp | 99 ++++++++++++++++++++++++++++++++++++++ src/d/d_menu_collect.cpp | 98 +++++++++++++++++++++++++++++++++++++ src/d/d_menu_fishing.cpp | 7 +++ src/d/d_menu_insect.cpp | 14 ++++++ src/d/d_menu_save.cpp | 56 +++++++++++++++++++++ src/d/d_menu_skill.cpp | 14 ++++++ src/d/d_name.cpp | 60 +++++++++++++++++++++++ 13 files changed, 418 insertions(+) diff --git a/include/d/d_bright_check.h b/include/d/d_bright_check.h index d8686944e6..dc9ae941cf 100644 --- a/include/d/d_bright_check.h +++ b/include/d/d_bright_check.h @@ -29,6 +29,9 @@ public: void _move(); void modeWait(); void modeMove(); + #if TARGET_PC + void brightCheckWide(); + #endif void _draw(); void draw() { diff --git a/include/d/d_file_select.h b/include/d/d_file_select.h index 810831a830..72f7cb7f42 100644 --- a/include/d/d_file_select.h +++ b/include/d/d_file_select.h @@ -367,6 +367,9 @@ public: void menuCursorShow(); void yesnoWakuAlpahAnmInit(u8, u8, u8, u8); bool yesnoWakuAlpahAnm(u8); + #if TARGET_PC + void fileSelectWide(); + #endif void _draw(); void errorMoveAnmInitSet(int, int); bool errorMoveAnm(); diff --git a/include/d/d_menu_collect.h b/include/d/d_menu_collect.h index 01ee32f6d4..587fd5c103 100644 --- a/include/d/d_menu_collect.h +++ b/include/d/d_menu_collect.h @@ -29,6 +29,11 @@ public: class dMenu_Collect2D_c : public dDlst_base_c { public: dMenu_Collect2D_c(JKRExpHeap*, STControl*, CSTControl*); + + #if TARGET_PC + void menuCollectWide(); + #endif + void _create(); void _delete(); void initialize(); diff --git a/include/d/d_menu_save.h b/include/d/d_menu_save.h index a6b174bbf4..4a70d1d045 100644 --- a/include/d/d_menu_save.h +++ b/include/d/d_menu_save.h @@ -263,6 +263,11 @@ public: void setSaveData(); void setInitSaveData(); void _draw(); + + #if TARGET_PC + void menuSaveWide(); + #endif + void _draw2(); virtual ~dMenu_save_c() {} diff --git a/include/d/d_name.h b/include/d/d_name.h index 0d877e6b09..e685871738 100644 --- a/include/d/d_name.h +++ b/include/d/d_name.h @@ -110,6 +110,11 @@ public: void menuCursorMove(); void menuCursorMove2(); void selectCursorPosSet(int); + + #if TARGET_PC + void nameWide(); + #endif + void _draw(); void screenSet(); void displayInit(); diff --git a/src/d/d_bright_check.cpp b/src/d/d_bright_check.cpp index 36f24ebd72..ac28e46838 100644 --- a/src/d/d_bright_check.cpp +++ b/src/d/d_bright_check.cpp @@ -143,7 +143,56 @@ void dBrightCheck_c::modeMove() { } } +#if TARGET_PC +void dBrightCheck_c::brightCheckWide() { + // Main Canvas + mBrightCheck.Scr->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f); + mBrightCheck.Scr->translate(mDoGph_gInf_c::getMinXF(), 0.0f); + + // Right Square + mBrightCheck.Scr->search(MULTI_CHAR('fuchi_1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mBrightCheck.Scr->search(MULTI_CHAR('big_squa'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Middle Square + mBrightCheck.Scr->search(MULTI_CHAR('fuchi_3'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mBrightCheck.Scr->search(MULTI_CHAR('big_squ1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Left Square + mBrightCheck.Scr->search(MULTI_CHAR('fuchi_4'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mBrightCheck.Scr->search(MULTI_CHAR('big_squ2'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Gray Squares + mBrightCheck.Scr->search(MULTI_CHAR('gray_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mBrightCheck.Scr->search(MULTI_CHAR('fuchi_2'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Confirm A Button + mBrightCheck.Scr->search(MULTI_CHAR('abtn_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mBrightCheck.Scr->search(MULTI_CHAR('gcabtn_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Text + mBrightCheck.Scr->search(MULTI_CHAR('menu_6n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mBrightCheck.Scr->search(MULTI_CHAR('menu_9n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mBrightCheck.Scr->search(MULTI_CHAR('menu_10n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mBrightCheck.Scr->search(MULTI_CHAR('menu_7n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mBrightCheck.Scr->search(MULTI_CHAR('menu_8n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mBrightCheck.Scr->search(MULTI_CHAR('fmenu_8n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mBrightCheck.Scr->search(MULTI_CHAR('fmenu_7n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mBrightCheck.Scr->search(MULTI_CHAR('fmenu_10'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mBrightCheck.Scr->search(MULTI_CHAR('fmenu_6n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mBrightCheck.Scr->search(MULTI_CHAR('fmenu_9n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mBrightCheck.Scr->search(MULTI_CHAR('t_t00'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mBrightCheck.Scr->search(MULTI_CHAR('f_t00'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Spirals + mBrightCheck.Scr->search(MULTI_CHAR('t_mo_l_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mBrightCheck.Scr->search(MULTI_CHAR('t_mo_r_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); +} +#endif + void dBrightCheck_c::_draw() { + #if TARGET_PC + brightCheckWide(); + #endif dComIfGd_set2DOpa(&mBrightCheck); } diff --git a/src/d/d_file_select.cpp b/src/d/d_file_select.cpp index 16aafb721f..c739b39db2 100644 --- a/src/d/d_file_select.cpp +++ b/src/d/d_file_select.cpp @@ -2091,7 +2091,12 @@ void dFile_select_c::yesnoCursorShow() { Vec pos = mYnSelPane[field_0x0268]->getGlobalVtxCenter(0, 0); mSelIcon->setPos(pos.x, pos.y, mYnSelPane[field_0x0268]->getPanePtr(), true); mSelIcon->setAlphaRate(1.0f); + + #if TARGET_PC + mSelIcon->setParam(0.96f * mDoGph_gInf_c::hudAspectScaleUp, 0.84f, 0.06f, 0.5f, 0.5f); + #else mSelIcon->setParam(0.96f, 0.84f, 0.06f, 0.5f, 0.5f); + #endif } } @@ -2243,7 +2248,12 @@ void dFile_select_c::YesNoCancelMove() { mSelIcon->setPos(vtxCenter.x, vtxCenter.y, m3mSelPane[mSelectMenuNum]->getPanePtr(), true); mSelIcon->setAlphaRate(1.0f); + + #if TARGET_PC + mSelIcon->setParam(0.96f * mDoGph_gInf_c::hudAspectScaleUp, 0.84f, 0.06f, 0.5f, 0.5f); + #else mSelIcon->setParam(0.96f, 0.84f, 0.06f, 0.5f, 0.5f); + #endif #if PLATFORM_WII || PLATFORM_SHIELD field_0x4333 = mSelectMenuNum; @@ -3126,7 +3136,13 @@ void dFile_select_c::screenSet() { mSelIcon = JKR_NEW dSelect_cursor_c(0, 1.0f, NULL); JUT_ASSERT(5209, mSelIcon != NULL); + + #if TARGET_PC + mSelIcon->setParam(0.96f * mDoGph_gInf_c::hudAspectScaleUp, 0.94f, 0.03f, 0.7f, 0.7f); + #else mSelIcon->setParam(0.96f, 0.94f, 0.03f, 0.7f, 0.7f); + #endif + Vec vtxCenter; vtxCenter = mSelFilePanes[mSelectNum]->getGlobalVtxCenter(false, 0); mSelIcon->setPos(vtxCenter.x, vtxCenter.y, mSelFilePanes[mSelectNum]->getPanePtr(), true); @@ -3257,7 +3273,13 @@ void dFile_select_c::screenSetCopySel() { mSelIcon2 = JKR_NEW dSelect_cursor_c(0, 1.0f, NULL); JUT_ASSERT(5406, mSelIcon2 != NULL); + + #if TARGET_PC + mSelIcon2->setParam(0.96f * mDoGph_gInf_c::hudAspectScaleUp, 0.94f, 0.03f, 0.7f, 0.7f); + #else mSelIcon2->setParam(0.96f, 0.94f, 0.03f, 0.7f, 0.7f); + #endif + Vec center = mCpSelPane[0]->getGlobalVtxCenter(false, 0); mSelIcon2->setPos(center.x, center.y, mCpSelPane[0]->getPanePtr(), true); mSelIcon2->setAlphaRate(0.0f); @@ -3647,7 +3669,12 @@ void dFile_select_c::selFileCursorShow() { Vec local_1c = mSelFilePanes[mSelectNum]->getGlobalVtxCenter(false, 0); mSelIcon->setPos(local_1c.x, local_1c.y, mSelFilePanes[mSelectNum]->getPanePtr(), true); mSelIcon->setAlphaRate(1.0f); + + #if TARGET_PC + mSelIcon->setParam(0.96f * mDoGph_gInf_c::hudAspectScaleUp, 0.94f, 0.03f, 0.7f, 0.7f); + #else mSelIcon->setParam(0.96f, 0.94f, 0.03f, 0.7f, 0.7f); + #endif } void dFile_select_c::menuWakuAlpahAnmInit(u8 i_idx, u8 param_1, u8 param_2, u8 param_3) { @@ -3689,7 +3716,12 @@ void dFile_select_c::menuCursorShow() { Vec local_24 = m3mSelPane[mSelectMenuNum]->getGlobalVtxCenter(false, 0); mSelIcon->setPos(local_24.x, local_24.y, m3mSelPane[mSelectMenuNum]->getPanePtr(), true); mSelIcon->setAlphaRate(1.0f); + + #if TARGET_PC + mSelIcon->setParam(0.96f * mDoGph_gInf_c::hudAspectScaleUp, 0.84f, 0.06f, 0.5f, 0.5f); + #else mSelIcon->setParam(0.96f, 0.84f, 0.06f, 0.5f, 0.5f); + #endif } } @@ -3731,7 +3763,74 @@ bool dFile_select_c::yesnoWakuAlpahAnm(u8 param_1) { return rv; } +#if TARGET_PC +void dFile_select_c::fileSelectWide() { + mYnSel.ScrYn->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f); + mYnSel.ScrYn->translate(mDoGph_gInf_c::getMinXF(), 0.0f); + + mYnSel.ScrYn->search(MULTI_CHAR('w_no_t'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mYnSel.ScrYn->search(MULTI_CHAR('f_no_t'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mYnSel.ScrYn->search(MULTI_CHAR('w_yes_t'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mYnSel.ScrYn->search(MULTI_CHAR('f_yes_t'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + m3mSel.Scr3m->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f); + m3mSel.Scr3m->translate(mDoGph_gInf_c::getMinXF(), 0.0f); + + m3mSel.Scr3m->search(MULTI_CHAR('w_sta'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + m3mSel.Scr3m->search(MULTI_CHAR('f_sta'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + m3mSel.Scr3m->search(MULTI_CHAR('w_del'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + m3mSel.Scr3m->search(MULTI_CHAR('f_del'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + m3mSel.Scr3m->search(MULTI_CHAR('w_cop_t'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + m3mSel.Scr3m->search(MULTI_CHAR('f_cop_t'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + fileSel.Scr->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f); + fileSel.Scr->translate(mDoGph_gInf_c::getMinXF(), 0.0f); + + fileSel.Scr->search(MULTI_CHAR('t_for'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + fileSel.Scr->search(MULTI_CHAR('t_for1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + fileSel.Scr->search(MULTI_CHAR('w_btn_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + fileSel.Scr->search(MULTI_CHAR('w_n_bk00'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + fileSel.Scr->search(MULTI_CHAR('w_n_bk01'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + fileSel.Scr->search(MULTI_CHAR('w_n_bk02'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + fileSel.Scr->search(MULTI_CHAR('w_dat_i0'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + fileSel.Scr->search(MULTI_CHAR('w_dat_i1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + fileSel.Scr->search(MULTI_CHAR('w_dat_i2'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + mCpSel.Scr->search(MULTI_CHAR('w_dat_i1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mCpSel.Scr->search(MULTI_CHAR('w_dat_i2'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mCpSel.Scr->search(MULTI_CHAR('w_n_bk01'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mCpSel.Scr->search(MULTI_CHAR('w_n_bk02'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + mSelDt.ScrDt->search(MULTI_CHAR('tate_n0'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mSelDt.ScrDt->search(MULTI_CHAR('tate_n1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mSelDt.ScrDt->search(MULTI_CHAR('ken_n0'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mSelDt.ScrDt->search(MULTI_CHAR('ken_n1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mSelDt.ScrDt->search(MULTI_CHAR('fuku_n0'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mSelDt.ScrDt->search(MULTI_CHAR('fuku_n1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mSelDt.ScrDt->search(MULTI_CHAR('fuku_n2'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Spirals + fileSel.Scr->search(MULTI_CHAR('w_uzu00'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + fileSel.Scr->search(MULTI_CHAR('w_uzu01'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + fileSel.Scr->search(MULTI_CHAR('w_uzu02'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + fileSel.Scr->search(MULTI_CHAR('w_uzu03'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + fileSel.Scr->search(MULTI_CHAR('w_uzu04'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + fileSel.Scr->search(MULTI_CHAR('w_uzu05'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + fileSel.Scr->search(MULTI_CHAR('w_uzu06'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + fileSel.Scr->search(MULTI_CHAR('w_uzu07'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + fileSel.Scr->search(MULTI_CHAR('w_uzu08'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + fileSel.Scr->search(MULTI_CHAR('w_uzu09'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); +} +#endif + void dFile_select_c::_draw() { + #if TARGET_PC + fileSelectWide(); + #endif + if (!mHasDrawn) { dComIfGd_set2DOpa(&fileSel); diff --git a/src/d/d_menu_collect.cpp b/src/d/d_menu_collect.cpp index c30bd85f9b..ed5586e866 100644 --- a/src/d/d_menu_collect.cpp +++ b/src/d/d_menu_collect.cpp @@ -95,6 +95,78 @@ dMenu_Collect2D_c::~dMenu_Collect2D_c() { } } +#if TARGET_PC +void dMenu_Collect2D_c::menuCollectWide() { + // Main Canvas + mpScreen->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f); + mpScreen->translate(mDoGph_gInf_c::getMinXF(), 0.0f); + + // Pieces of Heart + mpScreen->search(MULTI_CHAR('heart_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Scents + mpScreen->search(MULTI_CHAR('wolf_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Quiver + mpScreen->search(MULTI_CHAR('item_0_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Wallet + mpScreen->search(MULTI_CHAR('item_1_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Poes + mpScreen->search(MULTI_CHAR('item_2_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Fish Bestiary + mpScreen->search(MULTI_CHAR('fish_3_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Letters + mpScreen->search(MULTI_CHAR('lett_4_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Hidden Skills + mpScreen->search(MULTI_CHAR('maki_5_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Green Tunic + mpScreen->search(MULTI_CHAR('fuku_n0'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Zora Armor + mpScreen->search(MULTI_CHAR('fuku_n1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Magic Armor + mpScreen->search(MULTI_CHAR('fuku_n2'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Ordon Shield + mpScreen->search(MULTI_CHAR('tate_n0'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Hylian Shield + mpScreen->search(MULTI_CHAR('tate_n1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Ordon Sword + mpScreen->search(MULTI_CHAR('ken_n0'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Master Sword + mpScreen->search(MULTI_CHAR('ken_n1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Bugs + mpScreen->search(MULTI_CHAR('kabu_6n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // "Collection" Text + mpScreen->search(MULTI_CHAR('t_t00'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mpScreen->search(MULTI_CHAR('f_t00'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // "Save" Text + mpScreen->search(MULTI_CHAR('sa_tex_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // "Options" Text + mpScreen->search(MULTI_CHAR('op_tex_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Item Name Text + mpScreen->search(MULTI_CHAR('itemn_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Item Description Text + mpScreen->search(MULTI_CHAR('infotxtn'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); +} +#endif + void dMenu_Collect2D_c::_create() { mpHeap->getTotalFreeSize(); mpScreen = JKR_NEW J2DScreen(); @@ -108,7 +180,17 @@ void dMenu_Collect2D_c::_create() { mpButtonAB[i] = NULL; mpButtonText[i] = NULL; } + + #if TARGET_PC + mpScreenIcon->translate(-mDoGph_gInf_c::getMinXF(), 0.0f); + #endif + dPaneClass_showNullPane(mpScreenIcon); + + #if TARGET_PC + menuCollectWide(); + #endif + mpDraw2DTop = JKR_NEW dMenu_Collect2DTop_c(this); ResTIMG* image = (ResTIMG*)dComIfGp_getMain2DArchive()->getResource('TIMG', "tt_block8x8.bti"); mpBlackTex = JKR_NEW J2DPicture(image); @@ -1004,11 +1086,23 @@ void dMenu_Collect2D_c::cursorPosSet() { Vec pos = mpSelPm[mCursorX][mCursorY]->getGlobalVtxCenter(false, 0); mpDrawCursor->setPos(pos.x, pos.y, mpSelPm[mCursorX][mCursorY]->getPanePtr(), false); if (mCursorY == 5) { + #if TARGET_PC + mpDrawCursor->setParam(1.1f * mDoGph_gInf_c::hudAspectScaleUp, 0.85f, 0.05f, 0.5f, 0.5f); + #else mpDrawCursor->setParam(1.1f, 0.85f, 0.05f, 0.5f, 0.5f); + #endif } else if (mCursorX == 6 && mCursorY == 0) { + #if TARGET_PC + mpDrawCursor->setParam(0.6f * mDoGph_gInf_c::hudAspectScaleUp, 0.85f, 0.03f, 0.6f, 0.6f); + #else mpDrawCursor->setParam(0.6f, 0.85f, 0.03f, 0.6f, 0.6f); + #endif } else { + #if TARGET_PC + mpDrawCursor->setParam(1.0f * mDoGph_gInf_c::hudAspectScaleUp, 1.0f, 0.1f, 0.7f, 0.7f); + #else mpDrawCursor->setParam(1.0f, 1.0f, 0.1f, 0.7f, 0.7f); + #endif } } @@ -2028,6 +2122,10 @@ void dMenu_Collect2D_c::_move() { void dMenu_Collect2D_c::_draw() { + #if TARGET_PC + menuCollectWide(); + #endif + J2DGrafContext* grafPort = dComIfGp_getCurrentGrafPort(); grafPort->setup2D(); mpScreen->draw(0.0f, 0.0f, grafPort); diff --git a/src/d/d_menu_fishing.cpp b/src/d/d_menu_fishing.cpp index 189ce57e0f..615323767b 100644 --- a/src/d/d_menu_fishing.cpp +++ b/src/d/d_menu_fishing.cpp @@ -114,7 +114,14 @@ void dMenu_Fishing_c::_draw() { if (mpArchive) { J2DGrafContext* grafPort = dComIfGp_getCurrentGrafPort(); mpBlackTex->setAlpha(0xff); + + #if TARGET_PC + mpBlackTex->draw(mDoGph_gInf_c::getMinXF(), mDoGph_gInf_c::getMinYF(), + mDoGph_gInf_c::getWidthF(), mDoGph_gInf_c::getHeightF(), 0, 0, 0); + #else mpBlackTex->draw(0.0f, 0.0f, FB_WIDTH, FB_HEIGHT, 0, 0, 0); + #endif + mpScreen->draw(0.0f, 0.0f, grafPort); mpIconScreen->draw(0.0f, 0.0f, grafPort); } diff --git a/src/d/d_menu_insect.cpp b/src/d/d_menu_insect.cpp index 82be9287b6..7558fe61b4 100644 --- a/src/d/d_menu_insect.cpp +++ b/src/d/d_menu_insect.cpp @@ -161,12 +161,26 @@ void dMenu_Insect_c::_draw() { if (mpArchive != NULL) { J2DGrafContext* grafPort = dComIfGp_getCurrentGrafPort(); mpBlackTex->setAlpha(0xff); + + #if TARGET_PC + mpBlackTex->draw(mDoGph_gInf_c::getMinXF(), mDoGph_gInf_c::getMinYF(), + mDoGph_gInf_c::getWidthF(), mDoGph_gInf_c::getHeightF(), 0, 0, 0); + #else mpBlackTex->draw(0.0f, 0.0f, FB_WIDTH, FB_HEIGHT, 0, 0, 0); + #endif + mpScreen->draw(0.0f, 0.0f, grafPort); mpDrawCursor->draw(); field_0xfc = mpExpParent->getAlphaRate() * 150.0f; mpBlackTex->setAlpha(field_0xfc); + + #if TARGET_PC + mpBlackTex->draw(mDoGph_gInf_c::getMinXF(), mDoGph_gInf_c::getMinYF(), + mDoGph_gInf_c::getWidthF(), mDoGph_gInf_c::getHeightF(), 0, 0, 0); + #else mpBlackTex->draw(0.0f, 0.0f, FB_WIDTH, FB_HEIGHT, 0, 0, 0); + #endif + mpExpScreen->draw(0.0f, 0.0f, grafPort); mpSelect_c->setOffsetX(g_drawHIO.mInsectListScreen.mConfirmOptionPosX_4x3); mpSelect_c->translate(g_drawHIO.mInsectListScreen.mConfirmOptionPosX_4x3 + 486.0f, diff --git a/src/d/d_menu_save.cpp b/src/d/d_menu_save.cpp index ef1fb9d61e..7ecc41f823 100644 --- a/src/d/d_menu_save.cpp +++ b/src/d/d_menu_save.cpp @@ -384,7 +384,12 @@ void dMenu_save_c::screenSet() { mSelectedFile = dComIfGs_getDataNum(); mSelIcon = JKR_NEW dSelect_cursor_c(0, 1.0f, NULL); + + #if TARGET_PC + mSelIcon->setParam(0.96f * mDoGph_gInf_c::hudAspectScaleUp, 0.94f, 0.03f, 0.7f, 0.7f); + #else mSelIcon->setParam(0.96f, 0.94f, 0.03f, 0.7f, 0.7f); + #endif Vec pos; pos = mpSelData[mSelectedFile]->getGlobalVtxCenter(false, 0); @@ -2516,7 +2521,12 @@ void dMenu_save_c::yesnoCursorShow() { Vec pos = mpNoYes[mYesNoCursor]->getGlobalVtxCenter(false, 0); mSelIcon->setPos(pos.x, pos.y, mpNoYes[mYesNoCursor]->getPanePtr(), true); mSelIcon->setAlphaRate(1.0f); + + #if TARGET_PC + mSelIcon->setParam(0.96f * mDoGph_gInf_c::hudAspectScaleUp, 0.84f, 0.06f, 0.5f, 0.5f); + #else mSelIcon->setParam(0.96f, 0.84f, 0.06f, 0.5f, 0.5f); + #endif } } @@ -2664,7 +2674,12 @@ void dMenu_save_c::selFileCursorShow() { Vec pos = mpSelData[mSelectedFile]->getGlobalVtxCenter(false, 0); mSelIcon->setPos(pos.x, pos.y, mpSelData[mSelectedFile]->getPanePtr(), true); mSelIcon->setAlphaRate(1.0f); + + #if TARGET_PC + mSelIcon->setParam(0.96f * mDoGph_gInf_c::hudAspectScaleUp, 0.94f, 0.03f, 0.7f, 0.7f); + #else mSelIcon->setParam(0.96f, 0.94f, 0.03f, 0.7f, 0.7f); + #endif } void dMenu_save_c::yesnoWakuAlpahAnmInit(u8 yesnoIdx, u8 startAlpha, u8 endAlpha, u8 anmTimer) { @@ -2763,6 +2778,43 @@ void dMenu_save_c::_draw() { } } +#if TARGET_PC +void dMenu_save_c::menuSaveWide() { + mSaveSel.Scr->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f); + mSaveSel.Scr->translate(mDoGph_gInf_c::getMinXF(), 0.0f); + + mSaveSel.Scr->search(MULTI_CHAR('t_for'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mSaveSel.Scr->search(MULTI_CHAR('t_for1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + mSaveSel.Scr->search(MULTI_CHAR('w_btn_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + mSaveSel.Scr->search(MULTI_CHAR('w_n_bk00'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mSaveSel.Scr->search(MULTI_CHAR('w_n_bk01'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mSaveSel.Scr->search(MULTI_CHAR('w_n_bk02'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + mSaveSel.Scr->search(MULTI_CHAR('w_dat_i0'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mSaveSel.Scr->search(MULTI_CHAR('w_dat_i1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mSaveSel.Scr->search(MULTI_CHAR('w_dat_i2'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + mSaveSel.Scr->search(MULTI_CHAR('w_no_t'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mSaveSel.Scr->search(MULTI_CHAR('f_no_t'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mSaveSel.Scr->search(MULTI_CHAR('w_yes_t'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mSaveSel.Scr->search(MULTI_CHAR('f_yes_t'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Spirals + mSaveSel.Scr->search(MULTI_CHAR('w_uzu00'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mSaveSel.Scr->search(MULTI_CHAR('w_uzu01'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mSaveSel.Scr->search(MULTI_CHAR('w_uzu02'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mSaveSel.Scr->search(MULTI_CHAR('w_uzu03'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mSaveSel.Scr->search(MULTI_CHAR('w_uzu04'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mSaveSel.Scr->search(MULTI_CHAR('w_uzu05'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mSaveSel.Scr->search(MULTI_CHAR('w_uzu06'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mSaveSel.Scr->search(MULTI_CHAR('w_uzu07'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mSaveSel.Scr->search(MULTI_CHAR('w_uzu08'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + mSaveSel.Scr->search(MULTI_CHAR('w_uzu09'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); +} +#endif + void dMenu_save_c::_draw2() { if (field_0x21a1 == 0) { if (mpScrnExplain != NULL) { @@ -2770,6 +2822,10 @@ void dMenu_save_c::_draw2() { } if (mDisplayMenu) { + #if TARGET_PC + menuSaveWide(); + #endif + dComIfGd_set2DOpa(&mSaveSel); for (int i = 0; i < 3; i++) { diff --git a/src/d/d_menu_skill.cpp b/src/d/d_menu_skill.cpp index cc22e136c7..78ab82af94 100644 --- a/src/d/d_menu_skill.cpp +++ b/src/d/d_menu_skill.cpp @@ -143,12 +143,26 @@ void dMenu_Skill_c::_draw() { J2DGrafContext* context = dComIfGp_getCurrentGrafPort(); u8 alpha = mpBlackTex->mAlpha; mpBlackTex->setAlpha(0xff); + + #if TARGET_PC + mpBlackTex->draw(mDoGph_gInf_c::getMinXF(), mDoGph_gInf_c::getMinYF(), + mDoGph_gInf_c::getWidthF(), mDoGph_gInf_c::getHeightF(), 0, 0, 0); + #else mpBlackTex->draw(0.0f, 0.0f, FB_WIDTH, FB_HEIGHT, 0, 0, 0); + #endif + mpBlackTex->setAlpha(alpha); mpMenuScreen->draw(mPosX, 0.0f, context); mpDrawCursor->draw(); if (mProcess == 1 || mProcess == 2 || mProcess == 3) { + + #if TARGET_PC + mpBlackTex->draw(mDoGph_gInf_c::getMinXF(), mDoGph_gInf_c::getMinYF(), + mDoGph_gInf_c::getWidthF(), mDoGph_gInf_c::getHeightF(), 0, 0, 0); + #else mpBlackTex->draw(0.0f, 0.0f, FB_WIDTH, FB_HEIGHT, 0, 0, 0); + #endif + mpLetterScreen->draw(0.0f, 0.0f, context); if (mStringID != 0) { mpString->getString(mStringID, (J2DTextBox*)mpTextPane->getPanePtr(), NULL, NULL, diff --git a/src/d/d_name.cpp b/src/d/d_name.cpp index ee51e2e583..120bcff752 100644 --- a/src/d/d_name.cpp +++ b/src/d/d_name.cpp @@ -918,6 +918,10 @@ void dName_c::selectCursorMove() { g_nmHIO.mSelCharScale); ((J2DTextBox*)mMojiIcon[mCharRow + mCharColumn * 5]->getPanePtr()) ->setWhite(JUtility::TColor(0xC8, 0xC8, 0xC8, 0xFF)); + + #if TARGET_PC + nameWide(); + #endif Vec pos = mMojiIcon[mCharRow + mCharColumn * 5]->getGlobalVtxCenter(false, 0); mSelIcon->setPos(pos.x, pos.y, mMojiIcon[mCharRow + mCharColumn * 5]->getPanePtr(), true); @@ -1281,7 +1285,58 @@ void dName_c::selectCursorPosSet(int row) { } } +#if TARGET_PC +void dName_c::nameWide() { + //Resize Select Icon + mSelIcon->setParam(0.82f * mDoGph_gInf_c::hudAspectScaleUp, 0.77f, 0.05f, 0.4f, 0.4f); + + // List of Characters Box + static u64 l_tagName[65] = { + MULTI_CHAR('m_00_0'), MULTI_CHAR('m_00_1'), MULTI_CHAR('m_00_2'), MULTI_CHAR('m_00_3'), MULTI_CHAR('m_00_4'), MULTI_CHAR('m_01_0'), MULTI_CHAR('m_01_1'), MULTI_CHAR('m_01_2'), MULTI_CHAR('m_01_3'), + MULTI_CHAR('m_01_4'), MULTI_CHAR('m_02_0'), MULTI_CHAR('m_02_1'), MULTI_CHAR('m_02_2'), MULTI_CHAR('m_02_3'), MULTI_CHAR('m_02_4'), MULTI_CHAR('m03_0'), MULTI_CHAR('m03_1'), MULTI_CHAR('m03_2'), + MULTI_CHAR('m03_3'), MULTI_CHAR('m03_4'), MULTI_CHAR('m_04_0'), MULTI_CHAR('m_04_1'), MULTI_CHAR('m_04_2'), MULTI_CHAR('m_04_3'), MULTI_CHAR('m_04_4'), MULTI_CHAR('m_05_0'), MULTI_CHAR('m_05_1'), + MULTI_CHAR('m_05_2'), MULTI_CHAR('m_05_3'), MULTI_CHAR('m_05_4'), MULTI_CHAR('m_06_0'), MULTI_CHAR('m_06_1'), MULTI_CHAR('m_06_2'), MULTI_CHAR('m_06_3'), MULTI_CHAR('m_06_4'), MULTI_CHAR('m_07_0'), + MULTI_CHAR('m_07_1'), MULTI_CHAR('m_07_2'), MULTI_CHAR('m_07_3'), MULTI_CHAR('m_07_4'), MULTI_CHAR('m_08_0'), MULTI_CHAR('m_08_1'), MULTI_CHAR('m_08_2'), MULTI_CHAR('m_08_3'), MULTI_CHAR('m_08_4'), + MULTI_CHAR('m_09_0'), MULTI_CHAR('m_09_1'), MULTI_CHAR('m_09_2'), MULTI_CHAR('m_09_3'), MULTI_CHAR('m_09_4'), MULTI_CHAR('m_10_0'), MULTI_CHAR('m_10_1'), MULTI_CHAR('m_10_2'), MULTI_CHAR('m_10_3'), + MULTI_CHAR('m_10_4'), MULTI_CHAR('m_11_0'), MULTI_CHAR('m_11_1'), MULTI_CHAR('m_11_2'), MULTI_CHAR('m_11_3'), MULTI_CHAR('m_11_4'), MULTI_CHAR('m12_0'), MULTI_CHAR('m12_1'), MULTI_CHAR('m12_2'), + MULTI_CHAR('m12_3'), MULTI_CHAR('m12_4'), + }; + + for (u32 i = 0; i < 65; i++) { + nameIn.NameInScr->search(l_tagName[i])->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + } + + // "END" Text + nameIn.NameInScr->search(MULTI_CHAR('p_end_2'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + nameIn.NameInScr->search(MULTI_CHAR('p_end_1'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + nameIn.NameInScr->search(MULTI_CHAR('p_end_0'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + + // Letters being typed + static u64 l_nameTagName[8] = { + MULTI_CHAR('name_00'), MULTI_CHAR('name_01'), MULTI_CHAR('name_02'), MULTI_CHAR('name_03'), MULTI_CHAR('name_04'), MULTI_CHAR('name_05'), MULTI_CHAR('name_06'), MULTI_CHAR('name_07'), + }; + + for (u32 i = 0; i < 8; i++) { + nameIn.NameInScr->search(l_nameTagName[i])->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + } + + // Underscores when typing below letters + static u64 l_nameCurTagName[8] = { + MULTI_CHAR('s__n_00'), MULTI_CHAR('s__n_01'), MULTI_CHAR('s__n_02'), MULTI_CHAR('s__n_03'), MULTI_CHAR('s__n_04'), MULTI_CHAR('s__n_05'), MULTI_CHAR('s__n_06'), MULTI_CHAR('s__n_07'), + }; + + for (u32 i = 0; i < 8; i++) { + nameIn.NameInScr->search(l_nameCurTagName[i]) + ->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f); + } +} +#endif + void dName_c::_draw() { + #if TARGET_PC + nameWide(); + #endif + dComIfGd_set2DOpa(&nameIn); dComIfGd_set2DOpa(mSelIcon); } @@ -1484,7 +1539,12 @@ void dName_c::screenSet() { mSelIcon = JKR_NEW dSelect_cursor_c(0, 1.0f, NULL); JUT_ASSERT(0, mSelIcon != NULL); + + #if TARGET_PC + mSelIcon->setParam(0.82f * mDoGph_gInf_c::hudAspectScaleUp, 0.77f, 0.05f, 0.4f, 0.4f); + #else mSelIcon->setParam(0.82f, 0.77f, 0.05f, 0.4f, 0.4f); + #endif Vec pos = mMojiIcon[mCharRow + mCharColumn * 5]->getGlobalVtxCenter(false, 0); mSelIcon->setPos(pos.x, pos.y, mMojiIcon[mCharRow + mCharColumn * 5]->getPanePtr(), true); From 1430f690e04fe7e728e5045d0577752fc7ca84fc Mon Sep 17 00:00:00 2001 From: bdamja <95828582+bdamja@users.noreply.github.com> Date: Sun, 5 Apr 2026 12:31:28 -0600 Subject: [PATCH 23/72] button to restore default window size and position (#234) --- src/dusk/imgui/ImGuiMenuGame.cpp | 8 ++++++++ src/m_Do/m_Do_main.cpp | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index cd1d5a06f3..46a1e58ec9 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -11,6 +11,7 @@ #include "dusk/hotkeys.h" #include "dusk/settings.h" #include "m_Do/m_Do_controller_pad.h" +#include "m_Do/m_Do_graphic.h" namespace dusk { ImGuiMenuGame::ImGuiMenuGame() {} @@ -29,6 +30,13 @@ namespace dusk { VISetWindowFullscreen(getSettings().video.enableFullscreen); } + if (ImGui::MenuItem("Default Window Size")) { + getSettings().video.enableFullscreen = false; + VISetWindowFullscreen(false); + VISetWindowSize(FB_WIDTH * 2, FB_HEIGHT * 2); + VICenterWindow(); + } + ImGui::EndMenu(); } diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index b8eeba892e..3a70e0a783 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -269,8 +269,8 @@ int game_main(int argc, char* argv[]) { config.appName = "Dusk"; config.windowPosX = -1; config.windowPosY = -1; - config.windowWidth = 608 * 2; - config.windowHeight = 448 * 2; + config.windowWidth = FB_WIDTH * 2; + config.windowHeight = FB_HEIGHT * 2; config.desiredBackend = ParseAuroraBackend(parsed_arg_options["backend"].as()); config.logCallback = &aurora_log_callback; config.logLevel = (AuroraLogLevel)parsed_arg_options["log-level"].as(); From aa54aba07cc6b60a7320c92229d3b5cb4d1bd933 Mon Sep 17 00:00:00 2001 From: madeline Date: Sun, 5 Apr 2026 12:57:52 -0700 Subject: [PATCH 24/72] update aurora sm --- extern/aurora | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/aurora b/extern/aurora index 7eb8efcd17..50163edfe7 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 7eb8efcd172ceed27d120ffb6de86c63d1f3cad0 +Subproject commit 50163edfe76694f6c920bbd74febf1dd22a35618 From 1da0655ec69bbb700e046c52e9922ff0b3ca29c9 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Sun, 5 Apr 2026 23:09:51 +0200 Subject: [PATCH 25/72] Un-duplicate togglefullscreen code again --- src/dusk/imgui/ImGuiConsole.cpp | 4 +--- src/dusk/imgui/ImGuiMenuGame.cpp | 3 ++- src/dusk/imgui/ImGuiMenuGame.hpp | 2 ++ 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index e1e8b83d31..95fb0d598f 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -193,9 +193,7 @@ namespace dusk { } if (ImGui::IsKeyPressed(ImGuiKey_F11)) { - settings::video::enableFullscreen.setValue(!settings::video::enableFullscreen); - VISetWindowFullscreen(settings::video::enableFullscreen); - config::Save(); + ImGuiMenuGame::ToggleFullscreen(); } if (CheckMenuViewToggle(ImGuiKey_F1, m_isHidden)) { diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index 992a111e78..ba872a3b86 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -14,9 +14,10 @@ #include "m_Do/m_Do_controller_pad.h" namespace dusk { - static void ToggleFullscreen() { + void ImGuiMenuGame::ToggleFullscreen() { settings::video::enableFullscreen.setValue(!settings::video::enableFullscreen); VISetWindowFullscreen(settings::video::enableFullscreen); + config::Save(); } ImGuiMenuGame::ImGuiMenuGame() {} diff --git a/src/dusk/imgui/ImGuiMenuGame.hpp b/src/dusk/imgui/ImGuiMenuGame.hpp index 6d7ed614aa..77e5952d1a 100644 --- a/src/dusk/imgui/ImGuiMenuGame.hpp +++ b/src/dusk/imgui/ImGuiMenuGame.hpp @@ -16,6 +16,8 @@ namespace dusk { void windowInputViewer(); void windowControllerConfig(); + static void ToggleFullscreen(); + private: struct { int m_selectedPort = 0; From 3eb843cc80d4d859401c85b082a87fa35e38678a Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Sun, 5 Apr 2026 23:13:33 +0200 Subject: [PATCH 26/72] Explanation at top of config.hpp (config_var.hpp already had one) --- include/dusk/config.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/include/dusk/config.hpp b/include/dusk/config.hpp index 5cd0807b3b..258e012f2b 100644 --- a/include/dusk/config.hpp +++ b/include/dusk/config.hpp @@ -7,6 +7,14 @@ namespace dusk::config { +/* + * config.hpp is a heavier "full" header for the configuration system. + * For a basic overview and the basic types (sufficient for accessing settings), + * look at config_var.hpp. + * + * Avoid including this header in the entire game, it's heavier than I'd like! + */ + /** * \brief Base class containing virtual functions used for save/load of CVars. */ From b098577ab9ae4cc7abb0f1bef890e269ac49299c Mon Sep 17 00:00:00 2001 From: Max Roncace Date: Sun, 5 Apr 2026 17:34:18 -0400 Subject: [PATCH 27/72] Reapply settings changes on top of #209 --- include/dusk/settings.h | 100 +++++++------- include/m_Do/m_Do_controller_pad.h | 4 +- src/Z2AudioLib/Z2AudioMgr.cpp | 2 +- src/Z2AudioLib/Z2SoundObjMgr.cpp | 2 +- src/d/actor/d_a_alink.cpp | 6 +- src/d/actor/d_a_alink_cut.inc | 2 +- src/d/actor/d_a_alink_damage.inc | 4 +- src/d/actor/d_a_alink_demo.inc | 6 +- src/d/actor/d_a_alink_dusk.cpp | 2 +- src/d/actor/d_a_alink_hang.inc | 24 ++-- src/d/actor/d_a_alink_hvyboots.inc | 2 +- src/d/actor/d_a_e_ym.cpp | 6 +- src/d/actor/d_a_midna.cpp | 2 +- src/d/actor/d_a_obj_drop.cpp | 8 +- src/d/d_camera.cpp | 2 +- src/d/d_kankyo.cpp | 2 +- src/d/d_s_name.cpp | 4 +- src/d/d_save.cpp | 6 +- src/dusk/imgui/ImGuiConsole.cpp | 2 +- src/dusk/imgui/ImGuiMenuEnhancements.cpp | 40 +++--- src/dusk/imgui/ImGuiMenuGame.cpp | 12 +- src/dusk/imgui/ImGuiMenuTools.cpp | 2 +- src/dusk/io.cpp | 4 + src/dusk/settings.cpp | 166 ++++++++++++----------- src/m_Do/m_Do_graphic.cpp | 4 +- src/m_Do/m_Do_main.cpp | 2 +- 26 files changed, 216 insertions(+), 200 deletions(-) diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 68850a28d0..cf4d79f6ac 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -1,68 +1,76 @@ #ifndef DUSK_CONFIG_H #define DUSK_CONFIG_H -#include "config_var.hpp" +#include "dusk/config_var.hpp" + +namespace dusk { -namespace dusk::settings { using namespace config; // Persistent user settings -namespace video { -extern ConfigVar enableFullscreen; -} +struct UserSettings { + // Program settings -namespace audio { -extern ConfigVar masterVolume; -extern ConfigVar mainMusicVolume; -extern ConfigVar subMusicVolume; -extern ConfigVar soundEffectsVolume; -extern ConfigVar fanfareVolume; -extern ConfigVar enableReverb; -} + struct { + // Video + ConfigVar enableFullscreen; + } video; -namespace game { -// QoL -extern ConfigVar enableQuickTransform; -extern ConfigVar hideTvSettingsScreen; -extern ConfigVar biggerWallets; -extern ConfigVar noReturnRupees; -extern ConfigVar disableRupeeCutscenes; -extern ConfigVar noSwordRecoil; -extern ConfigVar damageMultiplier; -extern ConfigVar instantDeath; -extern ConfigVar fastClimbing; -extern ConfigVar fastTears; -extern ConfigVar noMissClimbing; + struct { + // Audio + ConfigVar masterVolume; + ConfigVar mainMusicVolume; + ConfigVar subMusicVolume; + ConfigVar soundEffectsVolume; + ConfigVar fanfareVolume; + ConfigVar enableReverb; + } audio; -// Preferences -extern ConfigVar enableMirrorMode; -extern ConfigVar invertCameraXAxis; + // Game settings -// Graphics -extern ConfigVar enableBloom; -extern ConfigVar useWaterProjectionOffset; + struct { + // QoL + ConfigVar enableQuickTransform; + ConfigVar hideTvSettingsScreen; + ConfigVar biggerWallets; + ConfigVar noReturnRupees; + ConfigVar disableRupeeCutscenes; + ConfigVar noSwordRecoil; + ConfigVar damageMultiplier; + ConfigVar instantDeath; + ConfigVar fastClimbing; + ConfigVar noMissClimbing; + ConfigVar fastTears; -// Audio -extern ConfigVar noLowHpSound; -extern ConfigVar midnasLamentNonStop; + // Preferences + ConfigVar enableMirrorMode; + ConfigVar invertCameraXAxis; -// Cheats -extern ConfigVar enableFastIronBoots; -extern ConfigVar canTransformAnywhere; + // Graphics + ConfigVar enableBloom; + ConfigVar useWaterProjectionOffset; -// Technical -extern ConfigVar restoreWiiGlitches; + // Audio + ConfigVar noLowHpSound; + ConfigVar midnasLamentNonStop; -// Controls -extern ConfigVar enableTurboKeybind; -} + // Cheats + ConfigVar enableFastIronBoots; + ConfigVar canTransformAnywhere; -void Register(); + // Technical + ConfigVar restoreWiiGlitches; -} + // Controls + ConfigVar enableTurboKeybind; + } game; +}; + +UserSettings& getSettings(); + +void registerSettings(); -namespace dusk { // Transient settings struct CollisionViewSettings { diff --git a/include/m_Do/m_Do_controller_pad.h b/include/m_Do/m_Do_controller_pad.h index f76a38cac8..e187efd17d 100644 --- a/include/m_Do/m_Do_controller_pad.h +++ b/include/m_Do/m_Do_controller_pad.h @@ -56,7 +56,7 @@ public: static s16 getStickAngle3D(u32 pad) { #if TARGET_PC - if (dusk::settings::game::enableMirrorMode) { + if (dusk::getSettings().game.enableMirrorMode) { return -getCpadInfo(pad).mMainStickAngle; } else { return getCpadInfo(pad).mMainStickAngle; @@ -68,7 +68,7 @@ public: static f32 getSubStickX3D(u32 pad) { #if TARGET_PC - if (dusk::settings::game::enableMirrorMode) { + if (dusk::getSettings().game.enableMirrorMode) { return -getCpadInfo(pad).mCStickPosX; } else { return getCpadInfo(pad).mCStickPosX; diff --git a/src/Z2AudioLib/Z2AudioMgr.cpp b/src/Z2AudioLib/Z2AudioMgr.cpp index 8c05678222..d6d78fb4b7 100644 --- a/src/Z2AudioLib/Z2AudioMgr.cpp +++ b/src/Z2AudioLib/Z2AudioMgr.cpp @@ -157,7 +157,7 @@ void Z2AudioMgr::zeldaGFrameWork() { processBgmFramework(); #if TARGET_PC - if (!dusk::settings::game::noLowHpSound) { + if (!dusk::getSettings().game.noLowHpSound) { processHeartGaugeSound(); } #else diff --git a/src/Z2AudioLib/Z2SoundObjMgr.cpp b/src/Z2AudioLib/Z2SoundObjMgr.cpp index 463040d692..19099c7675 100644 --- a/src/Z2AudioLib/Z2SoundObjMgr.cpp +++ b/src/Z2AudioLib/Z2SoundObjMgr.cpp @@ -109,7 +109,7 @@ void Z2SoundObjMgr::searchEnemy() { #if TARGET_PC if (Z2GetSeqMgr()->checkBgmIDPlaying(Z2BGM_MIDNA_SOS) && - dusk::settings::game::midnasLamentNonStop) + dusk::getSettings().game.midnasLamentNonStop) { Z2GetSeqMgr()->changeSubBgmStatus(0); return; diff --git a/src/d/actor/d_a_alink.cpp b/src/d/actor/d_a_alink.cpp index 993f78037b..48269ddc56 100644 --- a/src/d/actor/d_a_alink.cpp +++ b/src/d/actor/d_a_alink.cpp @@ -7510,7 +7510,7 @@ void daAlink_c::setBlendMoveAnime(f32 i_morf) { BOOL sp24 = checkEventRun(); BOOL sp20 = checkBootsMoveAnime(1); #if TARGET_PC - if (dusk::settings::game::enableFastIronBoots) { + if (dusk::getSettings().game.enableFastIronBoots) { sp20 = FALSE; } #endif @@ -9475,7 +9475,7 @@ void daAlink_c::setStickData() { mHeavySpeedMultiplier = mpHIO->mItem.mIronBoots.m.mInputFactor; } #if TARGET_PC - if (dusk::settings::game::enableFastIronBoots) { + if (dusk::getSettings().game.enableFastIronBoots) { mHeavySpeedMultiplier = 1.0f; } #endif @@ -9487,7 +9487,7 @@ void daAlink_c::setStickData() { mHeavySpeedMultiplier = mpHIO->mItem.mIronBoots.m.mWaterInputFactor; } #if TARGET_PC - if (dusk::settings::game::enableFastIronBoots) { + if (dusk::getSettings().game.enableFastIronBoots) { mHeavySpeedMultiplier = 1.0f; } #endif diff --git a/src/d/actor/d_a_alink_cut.inc b/src/d/actor/d_a_alink_cut.inc index 5928f7e891..8e61a262cb 100644 --- a/src/d/actor/d_a_alink_cut.inc +++ b/src/d/actor/d_a_alink_cut.inc @@ -372,7 +372,7 @@ BOOL daAlink_c::changeCutReverseProc(daAlink_c::daAlink_ANM i_anmID) { } #if TARGET_PC - if (dusk::settings::game::noSwordRecoil) { + if (dusk::getSettings().game.noSwordRecoil) { return FALSE; } #endif diff --git a/src/d/actor/d_a_alink_damage.inc b/src/d/actor/d_a_alink_damage.inc index 9bbe04206b..420011cfd6 100644 --- a/src/d/actor/d_a_alink_damage.inc +++ b/src/d/actor/d_a_alink_damage.inc @@ -153,8 +153,8 @@ f32 daAlink_c::damageMagnification(BOOL i_checkZoraMag, int param_1) { } #if TARGET_PC - base_mag *= dusk::settings::game::damageMultiplier; - if (dusk::settings::game::instantDeath) { + base_mag *= dusk::getSettings().game.damageMultiplier; + if (dusk::getSettings().game.instantDeath) { base_mag = 9999.0f; } #endif diff --git a/src/d/actor/d_a_alink_demo.inc b/src/d/actor/d_a_alink_demo.inc index c1c8c53bd2..aa77b24129 100644 --- a/src/d/actor/d_a_alink_demo.inc +++ b/src/d/actor/d_a_alink_demo.inc @@ -2233,7 +2233,7 @@ void daAlink_c::setGetSubBgm(int i_itemNo) { BOOL daAlink_c::checkTreasureRupeeReturn(int i_itemNo) const { #if TARGET_PC - if (dusk::settings::game::noReturnRupees) { + if (dusk::getSettings().game.noReturnRupees) { return FALSE; } #endif @@ -4307,7 +4307,7 @@ bool daAlink_c::checkAcceptWarp() { */ if (mLinkAcch.ChkGroundHit() && !checkModeFlg(MODE_PLAYER_FLY) #if TARGET_PC - && (dusk::settings::game::restoreWiiGlitches || !checkNoResetFlg0(FLG0_WATER_IN_MOVE)) + && (dusk::getSettings().game.restoreWiiGlitches || !checkNoResetFlg0(FLG0_WATER_IN_MOVE)) #elif VERSION != VERSION_WII_USA_R0 && !checkNoResetFlg0(FLG0_WATER_IN_MOVE) #endif @@ -4318,7 +4318,7 @@ bool daAlink_c::checkAcceptWarp() { */ if ( #if TARGET_PC - (dusk::settings::game::restoreWiiGlitches || !getSlidePolygon(&plane)) && + (dusk::getSettings().game.restoreWiiGlitches || !getSlidePolygon(&plane)) && #elif VERSION != VERSION_WII_USA_R0 !getSlidePolygon(&plane) && #endif diff --git a/src/d/actor/d_a_alink_dusk.cpp b/src/d/actor/d_a_alink_dusk.cpp index fdd309adae..95218268ac 100644 --- a/src/d/actor/d_a_alink_dusk.cpp +++ b/src/d/actor/d_a_alink_dusk.cpp @@ -5,7 +5,7 @@ #include "d/d_meter2_info.h" void daAlink_c::handleQuickTransform() { - if (!dusk::settings::game::enableQuickTransform) { + if (!dusk::getSettings().game.enableQuickTransform) { return; } diff --git a/src/d/actor/d_a_alink_hang.inc b/src/d/actor/d_a_alink_hang.inc index 73218f4b87..89f11fc940 100644 --- a/src/d/actor/d_a_alink_hang.inc +++ b/src/d/actor/d_a_alink_hang.inc @@ -15,8 +15,8 @@ f32 daAlink_c::getHangMoveAnmSpeed() { #if TARGET_PC return getAnmSpeedStickRate( - dusk::settings::game::fastClimbing ? 2.0f : mpHIO->mWallHang.mWallMove.m.mMinAnmSpeed, - dusk::settings::game::fastClimbing ? 2.0f : mpHIO->mWallHang.mWallMove.m.mMaxAnmSpeed + dusk::getSettings().game.fastClimbing ? 2.0f : mpHIO->mWallHang.mWallMove.m.mMinAnmSpeed, + dusk::getSettings().game.fastClimbing ? 2.0f : mpHIO->mWallHang.mWallMove.m.mMaxAnmSpeed ); #else return getAnmSpeedStickRate(mpHIO->mWallHang.mWallMove.m.mMinAnmSpeed, @@ -286,7 +286,7 @@ int daAlink_c::procHangStartInit() { if (checkHangFootWall()) { #if TARGET_PC - if (!is_prev_hangReady && cM_rnd() < 0.7f && !dusk::settings::game::noMissClimbing) { + if (!is_prev_hangReady && cM_rnd() < 0.7f && !dusk::getSettings().game.noMissClimbing) { #else if (!is_prev_hangReady && cM_rnd() < 0.7f) { #endif @@ -1221,7 +1221,7 @@ void daAlink_c::setLadderPos(int param_0) { f32 daAlink_c::getLadderMoveAnmSpeed() { return getAnmSpeedStickRate(mpHIO->mLadder.m.mMoveMinASpeed, #if TARGET_PC - dusk::settings::game::fastClimbing ? 1.575f : mpHIO->mLadder.m.mMoveMaxSpeed + dusk::getSettings().game.fastClimbing ? 1.575f : mpHIO->mLadder.m.mMoveMaxSpeed #else mpHIO->mLadder.m.mMoveMaxSpeed #endif @@ -1322,7 +1322,7 @@ int daAlink_c::procLadderUpStartInit() { setSingleAnimeBaseSpeed(ANM_LADDER_UP_START, #if TARGET_PC - dusk::settings::game::fastClimbing ? 1.8f : mpHIO->mLadder.m.mClimbUpStartASpeed, + dusk::getSettings().game.fastClimbing ? 1.8f : mpHIO->mLadder.m.mClimbUpStartASpeed, #else mpHIO->mLadder.m.mClimbUpStartASpeed, #endif @@ -1378,7 +1378,7 @@ int daAlink_c::procLadderUpEndInit(BOOL param_0) { setSingleAnimeBaseSpeed(anm_id, #if TARGET_PC - dusk::settings::game::fastClimbing ? 1.765f : mpHIO->mLadder.m.mClimbUpEndASpeed, + dusk::getSettings().game.fastClimbing ? 1.765f : mpHIO->mLadder.m.mClimbUpEndASpeed, #else mpHIO->mLadder.m.mClimbUpEndASpeed, #endif @@ -1443,7 +1443,7 @@ int daAlink_c::procLadderDownStartInit() { setSingleAnimeBaseSpeed(ANM_LADDER_DOWN_START, #if TARGET_PC - dusk::settings::game::fastClimbing ? 1.8f : mpHIO->mLadder.m.mClimbDownStartASpeed, + dusk::getSettings().game.fastClimbing ? 1.8f : mpHIO->mLadder.m.mClimbDownStartASpeed, #else mpHIO->mLadder.m.mClimbDownStartASpeed, #endif @@ -1505,7 +1505,7 @@ int daAlink_c::procLadderDownEndInit(BOOL param_0) { setSingleAnimeBaseSpeed(anm_id, #if TARGET_PC - dusk::settings::game::fastClimbing ? 1.8f : mpHIO->mLadder.m.mClimbDownEndASpeed, + dusk::getSettings().game.fastClimbing ? 1.8f : mpHIO->mLadder.m.mClimbDownEndASpeed, #else mpHIO->mLadder.m.mClimbDownEndASpeed, #endif @@ -1643,7 +1643,7 @@ int daAlink_c::procLadderMove() { f32 daAlink_c::getClimbMoveUpDownAnmSpeed() { return getAnmSpeedStickRate(mpHIO->mLadder.m.mWallVerticalMinAnmSpeed, #if TARGET_PC - dusk::settings::game::fastClimbing ? 1.875f : mpHIO->mLadder.m.mWallVerticalMaxAnmSpeed + dusk::getSettings().game.fastClimbing ? 1.875f : mpHIO->mLadder.m.mWallVerticalMaxAnmSpeed #else mpHIO->mLadder.m.mWallVerticalMaxAnmSpeed #endif @@ -1653,7 +1653,7 @@ f32 daAlink_c::getClimbMoveUpDownAnmSpeed() { f32 daAlink_c::getClimbMoveSideAnmSpeed() { return getAnmSpeedStickRate(mpHIO->mLadder.m.mWallHorizontalMinAnmSpeed, #if TARGET_PC - dusk::settings::game::fastClimbing ? 2.0f : mpHIO->mLadder.m.mWallHorizontalMaxAnmSpeed + dusk::getSettings().game.fastClimbing ? 2.0f : mpHIO->mLadder.m.mWallHorizontalMaxAnmSpeed #else mpHIO->mLadder.m.mWallHorizontalMaxAnmSpeed #endif @@ -2089,7 +2089,7 @@ int daAlink_c::procClimbUpStartInit(int param_0) { mNormalSpeed = 0.0f; #if TARGET_PC - if (param_0 || var_r29 || cM_rnd() < 0.3f || dusk::settings::game::noMissClimbing) { + if (param_0 || var_r29 || cM_rnd() < 0.3f || dusk::getSettings().game.noMissClimbing) { #else if (param_0 || var_r29 || cM_rnd() < 0.3f) { #endif @@ -2170,7 +2170,7 @@ int daAlink_c::procClimbDownStartInit(s16 param_0) { deleteEquipItem(TRUE, FALSE); #if TARGET_PC - if (cM_rnd() < 0.7f || dusk::settings::game::noMissClimbing) { + if (cM_rnd() < 0.7f || dusk::getSettings().game.noMissClimbing) { #else if (cM_rnd() < 0.7f) { #endif diff --git a/src/d/actor/d_a_alink_hvyboots.inc b/src/d/actor/d_a_alink_hvyboots.inc index fd9848d85c..6f7fa8da40 100644 --- a/src/d/actor/d_a_alink_hvyboots.inc +++ b/src/d/actor/d_a_alink_hvyboots.inc @@ -349,7 +349,7 @@ int daAlink_c::procMagneBootsFly() { */ if (dComIfG_Bgsp().ChkPolySafe(mPolyInfo2) #if TARGET_PC - && (dusk::settings::game::restoreWiiGlitches || checkEquipHeavyBoots()) + && (dusk::getSettings().game.restoreWiiGlitches || checkEquipHeavyBoots()) #elif PLATFORM_GCN || VERSION == VERSION_WII_KOR && checkEquipHeavyBoots() #endif diff --git a/src/d/actor/d_a_e_ym.cpp b/src/d/actor/d_a_e_ym.cpp index 0b87d419e3..758bec6269 100644 --- a/src/d/actor/d_a_e_ym.cpp +++ b/src/d/actor/d_a_e_ym.cpp @@ -1069,7 +1069,7 @@ void daE_YM_c::executeDown() { if (mAcch.ChkGroundHit()) { if (mFlyType != 1) { #if TARGET_PC - bckSet(6, 0, 0.0f, dusk::settings::game::fastTears && dComIfGp_event_getMode() == 0 ? 2.0f : 1.0f); + bckSet(6, 0, 0.0f, dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0 ? 2.0f : 1.0f); #else bckSet(6, 0, 0.0f, 1.0f); #endif @@ -1093,7 +1093,7 @@ void daE_YM_c::executeDown() { mSound.startCreatureSound(Z2SE_CM_BODYFALL_WATER_M, 0, -1); mSound.startCreatureSound(Z2SE_EN_YM_MOGAKU, 0, -1); #if TARGET_PC - bckSet(6, 0, 0.0f, dusk::settings::game::fastTears && dComIfGp_event_getMode() == 0 ? 2.0f : 1.0f); + bckSet(6, 0, 0.0f, dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0 ? 2.0f : 1.0f); #else bckSet(6, 0, 0.0f, 1.0f); #endif @@ -1115,7 +1115,7 @@ void daE_YM_c::executeDown() { || dComIfG_Bgsp().GetGroundCode(gnd_chk) == 5) { #if TARGET_PC - bckSet(6, 0, 0.0f, dusk::settings::game::fastTears && dComIfGp_event_getMode() == 0 ? 2.0f : 1.0f); + bckSet(6, 0, 0.0f, dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0 ? 2.0f : 1.0f); #else bckSet(6, 0, 0.0f, 1.0f); #endif diff --git a/src/d/actor/d_a_midna.cpp b/src/d/actor/d_a_midna.cpp index a50a3cb1f7..c63f4e5251 100644 --- a/src/d/actor/d_a_midna.cpp +++ b/src/d/actor/d_a_midna.cpp @@ -3051,7 +3051,7 @@ BOOL daMidna_c::checkMetamorphoseEnableBase() { !dComIfGs_isEventBit(0xD04) || #if TARGET_PC (fopAcIt_Judge((fopAcIt_JudgeFunc)daMidna_searchNpc, &tmp) && - !dusk::settings::game::canTransformAnywhere) + !dusk::getSettings().game.canTransformAnywhere) #else fopAcIt_Judge((fopAcIt_JudgeFunc)daMidna_searchNpc, &tmp) #endif diff --git a/src/d/actor/d_a_obj_drop.cpp b/src/d/actor/d_a_obj_drop.cpp index 1fb93a4270..275a3d6e12 100644 --- a/src/d/actor/d_a_obj_drop.cpp +++ b/src/d/actor/d_a_obj_drop.cpp @@ -265,8 +265,8 @@ int daObjDrop_c::modeParentWait() { mModeAction = 1; #if TARGET_PC - mModeTimer = dusk::settings::game::fastTears && dComIfGp_event_getMode() == 0 ? 20 : 40; - if (dusk::settings::game::fastTears && dComIfGp_event_getMode() == 0) { + mModeTimer = dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0 ? 20 : 40; + if (dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0) { current.pos.y += 100.0f; } else { current.pos.y += 300.0f; @@ -285,7 +285,7 @@ int daObjDrop_c::modeParentWait() { case 2: createBodyEffect(); #if TARGET_PC - mModeTimer = dusk::settings::game::fastTears && dComIfGp_event_getMode() == 0 ? 5 : 45; + mModeTimer = dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0 ? 5 : 45; #else mModeTimer = 45; #endif @@ -331,7 +331,7 @@ int daObjDrop_c::modeWait() { case 2: case 50: #if TARGET_PC - if (dusk::settings::game::fastTears && dComIfGp_event_getMode() == 0) { + if (dusk::getSettings().game.fastTears && dComIfGp_event_getMode() == 0) { f32 player_dist = current.pos.abs(daPy_getPlayerActorClass()->current.pos); f32 home_dist = current.pos.abs(home.pos); diff --git a/src/d/d_camera.cpp b/src/d/d_camera.cpp index a946d85220..b2a5709736 100644 --- a/src/d/d_camera.cpp +++ b/src/d/d_camera.cpp @@ -764,7 +764,7 @@ void dCamera_c::updatePad() { var_f31 = mDoCPd_c::getSubStickX3D(mPadID); #if TARGET_PC - if (dusk::settings::game::invertCameraXAxis) { + if (dusk::getSettings().game.invertCameraXAxis) { var_f31 *= -1.0f; } #endif diff --git a/src/d/d_kankyo.cpp b/src/d/d_kankyo.cpp index 8b6d197624..ec35ee8bc7 100644 --- a/src/d/d_kankyo.cpp +++ b/src/d/d_kankyo.cpp @@ -11381,7 +11381,7 @@ void dKy_bg_MAxx_proc(void* bg_model_p) { C_MTXLightPerspective(sp1D8, dComIfGd_getView()->fovy, camera_p->view.aspect, 1.0f, 1.0f, #if TARGET_PC - dusk::settings::game::useWaterProjectionOffset ? -0.01f : 0.0f, 0.0f); + dusk::getSettings().game.useWaterProjectionOffset ? -0.01f : 0.0f, 0.0f); #else -0.01f, 0.0f); #endif diff --git a/src/d/d_s_name.cpp b/src/d/d_s_name.cpp index df512d8cb2..735ce4d0ca 100644 --- a/src/d/d_s_name.cpp +++ b/src/d/d_s_name.cpp @@ -301,7 +301,7 @@ void dScnName_c::FileSelectMain() { void dScnName_c::FileSelectMainNormal() { #if TARGET_PC - mShowTvSettingsScreen = !dusk::settings::game::hideTvSettingsScreen; + mShowTvSettingsScreen = !dusk::getSettings().game.hideTvSettingsScreen; #endif switch(dFs_c->isSelectEnd()) { @@ -369,7 +369,7 @@ void dScnName_c::doPreLoadSetup() { mProc = dScnName_PROC_ChangeGameScene; #if TARGET_PC - if (dusk::settings::game::disableRupeeCutscenes) { + if (dusk::getSettings().game.disableRupeeCutscenes) { return; } #endif diff --git a/src/d/d_save.cpp b/src/d/d_save.cpp index e9977bc534..3289a49c64 100644 --- a/src/d/d_save.cpp +++ b/src/d/d_save.cpp @@ -114,19 +114,19 @@ u16 dSv_player_status_a_c::getRupeeMax() const { switch (mWalletSize) { case WALLET: #if TARGET_PC - return dusk::settings::game::biggerWallets ? 500 : 300; + return dusk::getSettings().game.biggerWallets ? 500 : 300; #else return 300; #endif case BIG_WALLET: #if TARGET_PC - return dusk::settings::game::biggerWallets ? 1000 : 600; + return dusk::getSettings().game.biggerWallets ? 1000 : 600; #else return 600; #endif case GIANT_WALLET: #if TARGET_PC - return dusk::settings::game::biggerWallets ? 2000 : 1000; + return dusk::getSettings().game.biggerWallets ? 2000 : 1000; #else return 1000; #endif diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index 95fb0d598f..fe5d3e7c9a 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -184,7 +184,7 @@ namespace dusk { m_isLaunchInitialized = true; } - getTransientSettings().skipFrameRateLimit = settings::game::enableTurboKeybind && ImGui::IsKeyDown(ImGuiKey_Tab); + getTransientSettings().skipFrameRateLimit = getSettings().game.enableTurboKeybind && ImGui::IsKeyDown(ImGuiKey_Tab); if ((ImGui::IsKeyDown(ImGuiKey_LeftCtrl) || ImGui::IsKeyDown(ImGuiKey_RightCtrl)) && ImGui::IsKeyPressed(ImGuiKey_R)) diff --git a/src/dusk/imgui/ImGuiMenuEnhancements.cpp b/src/dusk/imgui/ImGuiMenuEnhancements.cpp index 537539cd02..3fbd55a8f2 100644 --- a/src/dusk/imgui/ImGuiMenuEnhancements.cpp +++ b/src/dusk/imgui/ImGuiMenuEnhancements.cpp @@ -10,45 +10,45 @@ namespace dusk { void ImGuiMenuEnhancements::draw() { if (ImGui::BeginMenu("Enhancements")) { if (ImGui::BeginMenu("Quality of Life")) { - config::ImGuiCheckbox("Quick Transform (R+Y)", settings::game::enableQuickTransform); + config::ImGuiCheckbox("Quick Transform (R+Y)", getSettings().game.enableQuickTransform); - config::ImGuiCheckbox("Bigger Wallets", settings::game::biggerWallets); + config::ImGuiCheckbox("Bigger Wallets", getSettings().game.biggerWallets); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Wallet sizes are like in the HD version (500, 1000, 2000)"); } - config::ImGuiCheckbox("No Rupee Returns", settings::game::noReturnRupees); + config::ImGuiCheckbox("No Rupee Returns", getSettings().game.noReturnRupees); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Always collect Rupees even if your Wallet is too full"); } - config::ImGuiCheckbox("Disable Rupee Cutscenes", settings::game::disableRupeeCutscenes); + config::ImGuiCheckbox("Disable Rupee Cutscenes", getSettings().game.disableRupeeCutscenes); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Rupees won't play cutscenes after you've collected them the first time"); } - config::ImGuiCheckbox("No Sword Recoil", settings::game::noSwordRecoil); + config::ImGuiCheckbox("No Sword Recoil", getSettings().game.noSwordRecoil); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Link won't recoil when his sword hits walls"); } - config::ImGuiCheckbox("Faster Climbing", settings::game::fastClimbing); + config::ImGuiCheckbox("Faster Climbing", getSettings().game.fastClimbing); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Quicker climbing on ladders and vines like the HD version"); } - config::ImGuiCheckbox("No Climbing Miss Animation", settings::game::noMissClimbing); + config::ImGuiCheckbox("No Climbing Miss Animation", getSettings().game.noMissClimbing); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Prevents Link from playing a struggle animation\n" "when using the Clawshot on vines at a weird angle"); } - config::ImGuiCheckbox("Faster Tears of Light", settings::game::fastTears); + config::ImGuiCheckbox("Faster Tears of Light", getSettings().game.fastTears); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Tears of Light dropped by Shadow Insects pop out faster like the HD version"); } - config::ImGuiCheckbox("Hide TV Settings Screen", settings::game::hideTvSettingsScreen); + config::ImGuiCheckbox("Hide TV Settings Screen", getSettings().game.hideTvSettingsScreen); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Hides the TV calibration screen shown when loading a save"); } @@ -57,20 +57,20 @@ namespace dusk { } if (ImGui::BeginMenu("Preferences")) { - config::ImGuiCheckbox("Mirror Mode", settings::game::enableMirrorMode); + config::ImGuiCheckbox("Mirror Mode", getSettings().game.enableMirrorMode); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Mirrors the world, matching the Wii version of the game"); } - config::ImGuiCheckbox("Invert Camera X Axis", settings::game::invertCameraXAxis); + config::ImGuiCheckbox("Invert Camera X Axis", getSettings().game.invertCameraXAxis); ImGui::EndMenu(); } if (ImGui::BeginMenu("Graphics")) { - config::ImGuiCheckbox("Native Bloom", settings::game::enableBloom); + config::ImGuiCheckbox("Native Bloom", getSettings().game.enableBloom); - config::ImGuiCheckbox("Water Projection Offset", settings::game::useWaterProjectionOffset); + config::ImGuiCheckbox("Water Projection Offset", getSettings().game.useWaterProjectionOffset); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Adds GC-specific -0.01 transS offset\n" "that causes ~6px ghost artifacts in water reflections"); @@ -80,12 +80,12 @@ namespace dusk { } if (ImGui::BeginMenu("Audio")) { - config::ImGuiCheckbox("No Low HP Sound", settings::game::noLowHpSound); + config::ImGuiCheckbox("No Low HP Sound", getSettings().game.noLowHpSound); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Disable the beeping sound when having low health"); } - config::ImGuiCheckbox("Non-Stop Midna's Lament", settings::game::midnasLamentNonStop); + config::ImGuiCheckbox("Non-Stop Midna's Lament", getSettings().game.midnasLamentNonStop); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Prevents enemy music while Midna's Lament is playing"); } @@ -94,9 +94,9 @@ namespace dusk { } if (ImGui::BeginMenu("Cheats")) { - config::ImGuiCheckbox("Fast Iron Boots", settings::game::enableFastIronBoots); + config::ImGuiCheckbox("Fast Iron Boots", getSettings().game.enableFastIronBoots); - config::ImGuiCheckbox("Can Transform Anywhere", settings::game::canTransformAnywhere); + config::ImGuiCheckbox("Can Transform Anywhere", getSettings().game.canTransformAnywhere); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Allows you to transform even if NPCs are looking"); } @@ -105,9 +105,9 @@ namespace dusk { } if (ImGui::BeginMenu("Difficulty")) { - config::ImGuiSliderInt("Damage Multiplier", settings::game::damageMultiplier, 1, 8, "x%d"); + config::ImGuiSliderInt("Damage Multiplier", getSettings().game.damageMultiplier, 1, 8, "x%d"); - config::ImGuiCheckbox("Instant Death", settings::game::instantDeath); + config::ImGuiCheckbox("Instant Death", getSettings().game.instantDeath); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Any hit will instantly kill you"); } @@ -116,7 +116,7 @@ namespace dusk { } if (ImGui::BeginMenu("Technical")) { - config::ImGuiCheckbox("Restore Wii 1.0 Glitches", settings::game::restoreWiiGlitches); + config::ImGuiCheckbox("Restore Wii 1.0 Glitches", getSettings().game.restoreWiiGlitches); if (ImGui::IsItemHovered()) { ImGui::SetTooltip("Restores patched glitches from Wii USA 1.0,\n" "the first released version"); diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index ba872a3b86..b2ed26b20a 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -15,8 +15,8 @@ namespace dusk { void ImGuiMenuGame::ToggleFullscreen() { - settings::video::enableFullscreen.setValue(!settings::video::enableFullscreen); - VISetWindowFullscreen(settings::video::enableFullscreen); + getSettings().video.enableFullscreen.setValue(!getSettings().video.enableFullscreen); + VISetWindowFullscreen(getSettings().video.enableFullscreen); config::Save(); } @@ -40,8 +40,8 @@ namespace dusk { if (ImGui::BeginMenu("Audio")) { ImGui::Text("Master Volume"); - config::ImGuiSliderInt("##masterVolume", settings::audio::masterVolume, 0, 100); - config::ImGuiCheckbox("Enable Reverb", settings::audio::enableReverb); + config::ImGuiSliderInt("##masterVolume", getSettings().audio.masterVolume, 0, 100); + config::ImGuiCheckbox("Enable Reverb", getSettings().audio.enableReverb); /* // TODO: Implement additional settings ImGui::Text("Main Music Volume"); @@ -61,8 +61,8 @@ namespace dusk { } */ - audio::SetMasterVolume(settings::audio::masterVolume / 100.0f); - audio::EnableReverb = settings::audio::enableReverb; + audio::SetMasterVolume(getSettings().audio.masterVolume / 100.0f); + audio::EnableReverb = getSettings().audio.enableReverb; ImGui::EndMenu(); } diff --git a/src/dusk/imgui/ImGuiMenuTools.cpp b/src/dusk/imgui/ImGuiMenuTools.cpp index 754f9a72e7..6a2fc2ede0 100644 --- a/src/dusk/imgui/ImGuiMenuTools.cpp +++ b/src/dusk/imgui/ImGuiMenuTools.cpp @@ -51,7 +51,7 @@ namespace dusk { ImGui::MenuItem("Audio Debug", hotkeys::SHOW_AUDIO_DEBUG, &m_showAudioDebug); ImGui::MenuItem("OSReport Force", nullptr, &OSReportReallyForceEnable); ImGui::Separator(); - config::ImGuiMenuItem("Enable Turbo Key", hotkeys::TURBO, settings::game::enableTurboKeybind); + config::ImGuiMenuItem("Enable Turbo Key", hotkeys::TURBO, getSettings().game.enableTurboKeybind); ImGui::EndMenu(); } diff --git a/src/dusk/io.cpp b/src/dusk/io.cpp index f930c2ceaa..50b5cab5bd 100644 --- a/src/dusk/io.cpp +++ b/src/dusk/io.cpp @@ -11,7 +11,11 @@ using namespace dusk::io; #define fseek(a, b, c) _fseeki64(a, b, c) #else #define MODE_TYPE char +#if _MSVC_VER #define MODE(val) ##val +#else +#define MODE(val) val +#endif #endif static FILE* ThrowIfNotOpen(const FileStream& file) { diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index 6bfc057a90..278f783dbf 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -1,95 +1,99 @@ #include "dusk/settings.h" #include "dusk/config.hpp" -namespace dusk::settings { -namespace video { -ConfigVar enableFullscreen("video.enableFullscreen", false); +namespace dusk { + +UserSettings g_userSettings = { + .video = { + .enableFullscreen {"video.enableFullscreen", false}, + }, + + .audio = { + .masterVolume {"audio.masterVolume", 80}, + .mainMusicVolume {"audio.mainMusicVolume", 100}, + .subMusicVolume {"audio.subMusicVolume", 100}, + .soundEffectsVolume {"audio.soundEffectsVolume", 100}, + .fanfareVolume {"audio.fanfareVolume", 100}, + .enableReverb {"audio.enableReverb", true}, + }, + + .game = { + // Quality of Life + .enableQuickTransform {"game.enableQuickTransform", false}, + .hideTvSettingsScreen {"game.hideTvSettingsScreen", false}, + .biggerWallets {"game.biggerWallets", false}, + .noReturnRupees {"game.noReturnRupees", false}, + .disableRupeeCutscenes {"game.disableRupeeCutscenes", false}, + .noSwordRecoil {"game.noSwordRecoil", false}, + .damageMultiplier {"game.damageMultiplier", 1}, + .instantDeath {"game.instantDeath", false}, + .fastClimbing {"game.fastClimbing", false}, + .noMissClimbing {"game.noMissClimbing", false}, + .fastTears {"game.fastTears", false}, + + // Preferences + .enableMirrorMode {"game.enableMirrorMode", false}, + .invertCameraXAxis {"game.invertCameraXAxis", false}, + + // Graphics + .enableBloom {"game.enableBloom", true}, + .useWaterProjectionOffset {"game.useWaterProjectionOffset", false}, + + // Audio + .noLowHpSound {"game.noLowHpSound", false}, + .midnasLamentNonStop {"game.midnasLamentNonStop", false}, + + // Cheats + .enableFastIronBoots {"game.enableFastIronBoots", false}, + .canTransformAnywhere {"game.canTransformAnywhere", false}, + + // Technical + .restoreWiiGlitches {"game.restoreWiiGlitches", false}, + + // Controls + .enableTurboKeybind {"game.enableTurboKeybind", true}, + }, +}; + +UserSettings& getSettings() { + return g_userSettings; } -namespace audio { -ConfigVar masterVolume("audio.masterVolume", 80); -ConfigVar mainMusicVolume("audio.mainMusicVolume", 100); -ConfigVar subMusicVolume("audio.subMusicVolume", 100); -ConfigVar soundEffectsVolume("audio.soundEffectsVolume", 100); -ConfigVar fanfareVolume("audio.fanfareVolume", 100); -ConfigVar enableReverb("audio.enableReverb", true); -} - -namespace game { -// Quality of Life -ConfigVar enableQuickTransform("game.enableQuickTransform", false); -ConfigVar hideTvSettingsScreen("game.hideTvSettingsScreen", false); -ConfigVar biggerWallets("game.biggerWallets", false); -ConfigVar noReturnRupees("game.noReturnRupees", false); -ConfigVar disableRupeeCutscenes("game.disableRupeeCutscenes", false); -ConfigVar noSwordRecoil("game.noSwordRecoil", false); -ConfigVar damageMultiplier("game.damageMultiplier", 1); -ConfigVar instantDeath("game.instantDeath", false); -ConfigVar fastClimbing("game.fastClimbing", false); -ConfigVar fastTears("game.fastTears", false); -ConfigVar noMissClimbing("game.noMissClimbing", false); - -// Preferences -ConfigVar enableMirrorMode("game.enableMirrorMode", false); -ConfigVar invertCameraXAxis("game.invertCameraXAxis", false); - -// Graphics -ConfigVar enableBloom("game.enableBloom", true); -ConfigVar useWaterProjectionOffset("game.useWaterProjectionOffset", false); - -// Audio -ConfigVar noLowHpSound("game.noLowHpSound", false); -ConfigVar midnasLamentNonStop("game.midnasLamentNonStop", false); - -// Cheats -ConfigVar enableFastIronBoots("game.enableFastIronBoots", false); -ConfigVar canTransformAnywhere("game.canTransformAnywhere", false); - -// Technical -ConfigVar restoreWiiGlitches("game.restoreWiiGlitches", false); - -// Controls -ConfigVar enableTurboKeybind("game.enableTurboKeybind", true); -} - -void Register() { +void registerSettings() { // Video - Register(video::enableFullscreen); + Register(g_userSettings.video.enableFullscreen); // Audio - Register(audio::masterVolume); - Register(audio::mainMusicVolume); - Register(audio::subMusicVolume); - Register(audio::soundEffectsVolume); - Register(audio::fanfareVolume); - Register(audio::enableReverb); + Register(g_userSettings.audio.masterVolume); + Register(g_userSettings.audio.mainMusicVolume); + Register(g_userSettings.audio.subMusicVolume); + Register(g_userSettings.audio.soundEffectsVolume); + Register(g_userSettings.audio.fanfareVolume); + Register(g_userSettings.audio.enableReverb); // Game - Register(game::enableQuickTransform); - Register(game::hideTvSettingsScreen); - Register(game::biggerWallets); - Register(game::noReturnRupees); - Register(game::disableRupeeCutscenes); - Register(game::noSwordRecoil); - Register(game::damageMultiplier); - Register(game::instantDeath); - Register(game::fastClimbing); - Register(game::fastTears); - Register(game::enableMirrorMode); - Register(game::invertCameraXAxis); - Register(game::enableBloom); - Register(game::useWaterProjectionOffset); - Register(game::enableFastIronBoots); - Register(game::canTransformAnywhere); - Register(game::restoreWiiGlitches); - Register(game::noMissClimbing); - Register(game::noLowHpSound); - Register(game::midnasLamentNonStop); - Register(game::enableTurboKeybind); + Register(g_userSettings.game.enableQuickTransform); + Register(g_userSettings.game.hideTvSettingsScreen); + Register(g_userSettings.game.biggerWallets); + Register(g_userSettings.game.noReturnRupees); + Register(g_userSettings.game.disableRupeeCutscenes); + Register(g_userSettings.game.noSwordRecoil); + Register(g_userSettings.game.damageMultiplier); + Register(g_userSettings.game.instantDeath); + Register(g_userSettings.game.fastClimbing); + Register(g_userSettings.game.fastTears); + Register(g_userSettings.game.enableMirrorMode); + Register(g_userSettings.game.invertCameraXAxis); + Register(g_userSettings.game.enableBloom); + Register(g_userSettings.game.useWaterProjectionOffset); + Register(g_userSettings.game.enableFastIronBoots); + Register(g_userSettings.game.canTransformAnywhere); + Register(g_userSettings.game.restoreWiiGlitches); + Register(g_userSettings.game.noMissClimbing); + Register(g_userSettings.game.noLowHpSound); + Register(g_userSettings.game.midnasLamentNonStop); + Register(g_userSettings.game.enableTurboKeybind); } -} - -namespace dusk { // Transient settings diff --git a/src/m_Do/m_Do_graphic.cpp b/src/m_Do/m_Do_graphic.cpp index 7ee50fc0ea..a7a09a8d87 100644 --- a/src/m_Do/m_Do_graphic.cpp +++ b/src/m_Do/m_Do_graphic.cpp @@ -1163,7 +1163,7 @@ void mDoGph_gInf_c::bloom_c::remove() { void mDoGph_gInf_c::bloom_c::draw() { #if TARGET_PC - if (!dusk::settings::game::enableBloom) { + if (!dusk::getSettings().game.enableBloom) { return; } #endif @@ -2117,7 +2117,7 @@ int mDoGph_Painter() { #endif #if TARGET_PC - if (dusk::settings::game::enableMirrorMode) + if (dusk::getSettings().game.enableMirrorMode) #elif PLATFORM_WII if (data_8053a730) #endif diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index ffe6bb5ab6..632d696ae9 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -279,7 +279,7 @@ static const char* CalculateConfigPath() { // PC ENTRY POINT // ========================================================================= int game_main(int argc, char* argv[]) { - dusk::settings::Register(); + dusk::registerSettings(); dusk::config::FinishRegistration(); cxxopts::ParseResult parsed_arg_options; From e7dc10aefbd2f1d91803486f1099943ecfcfea0f Mon Sep 17 00:00:00 2001 From: madeline Date: Sun, 5 Apr 2026 15:05:38 -0700 Subject: [PATCH 28/72] fix cloud, sun, moon, rain, fog, lens flare, etc, culling --- src/d/d_kankyo_rain.cpp | 57 +++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 16 deletions(-) diff --git a/src/d/d_kankyo_rain.cpp b/src/d/d_kankyo_rain.cpp index 019f30f101..c1927c5875 100644 --- a/src/d/d_kankyo_rain.cpp +++ b/src/d/d_kankyo_rain.cpp @@ -113,7 +113,12 @@ void dKyr_lenzflare_move() { cXyz vect; cXyz proj; cXyz center; + + #if TARGET_PC + mDoLib_project(lenz_packet->mPositions, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(lenz_packet->mPositions, &proj); + #endif center.x = FB_WIDTH / 2; center.y = FB_HEIGHT / 2; @@ -213,7 +218,12 @@ void dKyr_sun_move() { } cXyz proj; + + #if TARGET_PC + mDoLib_project(sun_packet->mPos, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(sun_packet->mPos, &proj); + #endif for (int i = 0; i < 5; i++) { cXyz chkpnt = proj; @@ -4111,7 +4121,11 @@ void dKyr_drawStar(Mtx drawMtx, u8** tex) { } } + #if TARGET_PC + mDoLib_project(&moon_pos, &moon_proj, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&moon_pos, &moon_proj); + #endif GXSetNumChans(1); GXSetChanCtrl(GX_COLOR0, GX_DISABLE, GX_SRC_REG, GX_SRC_REG, GX_LIGHT_NULL, GX_DF_CLAMP, GX_AF_NONE); @@ -4248,7 +4262,11 @@ void dKyr_drawStar(Mtx drawMtx, u8** tex) { sp68.y = spBC.y + star_pos.y; sp68.z = spBC.z + star_pos.z; + #if TARGET_PC + mDoLib_project(&sp68, &star_proj, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&sp68, &star_proj); + #endif moon_proj.z = 0.0f; star_proj.z = 0.0f; @@ -4630,7 +4648,11 @@ void drawVrkumo(Mtx drawMtx, GXColor& color, u8** tex) { } if (g_env_light.daytime > 105.0f && g_env_light.daytime < 240.0f && !dComIfGp_event_runCheck() && sun_packet != NULL && sun_packet->mSunAlpha > 0.0f) { + #if TARGET_PC + mDoLib_project(&sun_packet->mPos[0], &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&sun_packet->mPos[0], &proj); + #endif if (proj.x > 0.0f && proj.x < FB_WIDTH && proj.y > spC4 && proj.y < (458.0f - spC4)) { pass = 0; } @@ -4895,7 +4917,12 @@ void drawVrkumo(Mtx drawMtx, GXColor& color, u8** tex) { x = 100.0f; y = 100.0f; z = 100.0f; + + #if TARGET_PC + mDoLib_project(&spF0, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&spF0, &proj); + #endif if (proj.x > -x && proj.x < (FB_WIDTH + x) && proj.y > -y && proj.y < (458.0f + z)) { break; @@ -4945,7 +4972,12 @@ void drawVrkumo(Mtx drawMtx, GXColor& color, u8** tex) { x = 100.0f; y = 100.0f; z = 100.0f; + + #if TARGET_PC + mDoLib_project(&spE4, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&spE4, &proj); + #endif if (proj.x > -x && proj.x < (FB_WIDTH + x) && proj.y > -y && proj.y < (458.0f + z)) { break; @@ -5986,21 +6018,18 @@ static void dKyr_evil_draw2(Mtx drawMtx, u8** tex) { sp34.y = 80.0f; sp34.z = 80.0f; + #if TARGET_PC + mDoLib_project(&sp7C, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&sp7C, &proj); + #endif -#if TARGET_PC - if (!(proj.x > -sp34.x) || !(proj.x < (dComIfGd_getViewport()->width + sp34.x)) || - !(proj.y > -sp34.y) || !(proj.y < (dComIfGd_getViewport()->height + sp34.z))) - { - continue; - } -#else if (!(proj.x > -sp34.x) || !(proj.x < (FB_WIDTH + sp34.x)) || !(proj.y > -sp34.y) || !(proj.y < (458.0f + sp34.z))) { continue; } -#endif + } f32 sp40; @@ -6219,21 +6248,17 @@ void dKyr_evil_draw(Mtx drawMtx, u8** tex) { sp44.y = 80.0f; sp44.z = 80.0f; + #if TARGET_PC + mDoLib_project(&spA4, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&spA4, &proj); + #endif -#if TARGET_PC - if (!(proj.x > -sp44.x) || !(proj.x < (dComIfGd_getViewport()->width + sp44.x)) || - !(proj.y > -sp44.y) || !(proj.y < (dComIfGd_getViewport()->height + sp44.z))) - { - continue; - } -#else if (!(proj.x > -sp44.x) || !(proj.x < (FB_WIDTH + sp44.x)) || !(proj.y > -sp44.y) || !(proj.y < (458.0f + sp44.z))) { continue; } -#endif } f32 sp5C; From 0b5dcfc7ad2a53a60eb82e22a32e24238844072c Mon Sep 17 00:00:00 2001 From: madeline Date: Sun, 5 Apr 2026 16:31:57 -0700 Subject: [PATCH 29/72] fix every viewport projection issue fixes #123 fixes #115 --- src/d/actor/d_a_alink_kandelaar.inc | 5 +++++ src/d/actor/d_a_demo00.cpp | 5 +++++ src/d/actor/d_a_e_fk.cpp | 6 ++++++ src/d/actor/d_a_e_fs.cpp | 6 ++++++ src/d/actor/d_a_e_sm.cpp | 6 ++++++ src/d/actor/d_a_npc.cpp | 11 +++++------ src/d/actor/d_a_obj_ari.cpp | 6 ++++++ src/d/actor/d_a_obj_bhashi.cpp | 6 ++++++ src/d/actor/d_a_obj_cho.cpp | 6 ++++++ src/d/actor/d_a_obj_crvfence.cpp | 6 ++++++ src/d/actor/d_a_obj_crvhahen.cpp | 5 +++++ src/d/actor/d_a_obj_dan.cpp | 6 ++++++ src/d/actor/d_a_obj_gomikabe.cpp | 6 ++++++ src/d/actor/d_a_obj_hhashi.cpp | 6 ++++++ src/d/actor/d_a_obj_kamakiri.cpp | 6 ++++++ src/d/actor/d_a_obj_katatsumuri.cpp | 5 +++++ src/d/actor/d_a_obj_kuwagata.cpp | 5 +++++ src/d/actor/d_a_obj_ten.cpp | 6 ++++++ src/d/actor/d_a_obj_tombo.cpp | 6 ++++++ src/d/actor/d_a_obj_zra_freeze.cpp | 5 +++++ src/d/d_insect.cpp | 4 ++++ src/d/d_kankyo.cpp | 4 ++++ src/d/d_kankyo_debug.cpp | 5 +++++ src/d/d_msg_object.cpp | 12 ++++++++++++ src/d/d_msg_scrn_item.cpp | 11 +++++++++++ src/d/d_msg_scrn_talk.cpp | 13 ++++++++++++- 26 files changed, 161 insertions(+), 7 deletions(-) diff --git a/src/d/actor/d_a_alink_kandelaar.inc b/src/d/actor/d_a_alink_kandelaar.inc index 339ff90ce6..88c2152e03 100644 --- a/src/d/actor/d_a_alink_kandelaar.inc +++ b/src/d/actor/d_a_alink_kandelaar.inc @@ -180,7 +180,12 @@ void daAlink_c::preKandelaarDraw() { mat_p->setTevColor(2, &color); cXyz proj; + + #if TARGET_PC + mDoLib_project(&mKandelaarFlamePos, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&mKandelaarFlamePos, &proj); + #endif camera_process_class* camera_p = dComIfGp_getCamera(0); f32 trimHeight; diff --git a/src/d/actor/d_a_demo00.cpp b/src/d/actor/d_a_demo00.cpp index 99ad6c1587..871e9ebca6 100644 --- a/src/d/actor/d_a_demo00.cpp +++ b/src/d/actor/d_a_demo00.cpp @@ -1658,7 +1658,12 @@ int daDemo00_c::draw() { MTXCopy(mModel.field_0x5d4->getAnmMtx(0), mDoMtx_stack_c::get()); spb0.set(0.0f, 0.0f, 0.0f); mDoMtx_stack_c::multVec(&spb0, &sp98); + + #if TARGET_PC + mDoLib_project(&sp98, &spa4, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&sp98, &spa4); + #endif if (spa4.x >= -700.0f && spa4.x < 1600.0f && spa4.y >= -200.0f && spa4.y < 600.0f) { if (mModel.mID.field_0x18 == 0 || mModel.mID.field_0x18 == 1) { diff --git a/src/d/actor/d_a_e_fk.cpp b/src/d/actor/d_a_e_fk.cpp index 5840df0495..87734da262 100644 --- a/src/d/actor/d_a_e_fk.cpp +++ b/src/d/actor/d_a_e_fk.cpp @@ -429,7 +429,13 @@ void daE_FK_c::DamageAction() { bool daE_FK_c::checkViewArea() { Vec proj; + + #if TARGET_PC + mDoLib_project(¤t.pos, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(¤t.pos, &proj); + #endif + return (proj.x >= 0.0f && proj.x <= FB_WIDTH) && (proj.y >= 0.0f && proj.y <= FB_HEIGHT); } diff --git a/src/d/actor/d_a_e_fs.cpp b/src/d/actor/d_a_e_fs.cpp index 3ed859c686..54dd10ad81 100644 --- a/src/d/actor/d_a_e_fs.cpp +++ b/src/d/actor/d_a_e_fs.cpp @@ -463,7 +463,13 @@ static void damage_check(e_fs_class* i_this) { static bool checkViewArea(cXyz* i_pos) { Vec proj; + + #if TARGET_PC + mDoLib_project(i_pos, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(i_pos, &proj); + #endif + bool ret = false; if (proj.x >= 0.0f && proj.x <= FB_WIDTH && proj.y >= 0.0f && proj.y <= FB_HEIGHT) { ret = true; diff --git a/src/d/actor/d_a_e_sm.cpp b/src/d/actor/d_a_e_sm.cpp index b85e22e640..8894399cec 100644 --- a/src/d/actor/d_a_e_sm.cpp +++ b/src/d/actor/d_a_e_sm.cpp @@ -1362,7 +1362,13 @@ void daE_SM_c::E_SM_C_Hook() { bool daE_SM_c::CheckViewArea() { Vec vec; + + #if TARGET_PC + mDoLib_project(¤t.pos, &vec, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(¤t.pos, &vec); + #endif + bool rv = false; if (vec.x >= 0.0f && vec.x <= FB_WIDTH && vec.y >= 0.0f && vec.y <= FB_HEIGHT) { diff --git a/src/d/actor/d_a_npc.cpp b/src/d/actor/d_a_npc.cpp index b903ce8c8f..6ec2fbe7a9 100644 --- a/src/d/actor/d_a_npc.cpp +++ b/src/d/actor/d_a_npc.cpp @@ -2694,16 +2694,15 @@ BOOL daNpcT_chkActorInScreen(fopAc_ac_c* i_ActorP, f32 param_1, f32 param_2, f32 } for (int i = 0; i < 8; i++) { + #if TARGET_PC + mDoLib_project(&pos_array[i], &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&pos_array[i], &proj); -#if TARGET_PC - if (0.0f < proj.x && proj.x < mDoGph_gInf_c::getWidth() && 0.0f < proj.y && proj.y < mDoGph_gInf_c::getHeight()) { - continue; - } -#else + #endif + if (0.0f < proj.x && proj.x < FB_WIDTH && 0.0f < proj.y && proj.y < FB_HEIGHT) { continue; } -#endif return false; } diff --git a/src/d/actor/d_a_obj_ari.cpp b/src/d/actor/d_a_obj_ari.cpp index 267b0003af..3e2727e2f2 100644 --- a/src/d/actor/d_a_obj_ari.cpp +++ b/src/d/actor/d_a_obj_ari.cpp @@ -499,7 +499,13 @@ void daObjARI_c::Z_BufferChk() { cXyz vec2, vec1; vec1 = current.pos; vec1.y += 20.0f; + + #if TARGET_PC + mDoLib_project(&vec1, &vec2, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&vec1, &vec2); + #endif + f32 trim_height; camera_process_class* camera = dComIfGp_getCamera(0); if (camera != NULL) { diff --git a/src/d/actor/d_a_obj_bhashi.cpp b/src/d/actor/d_a_obj_bhashi.cpp index 00a35bc158..33595c7a77 100644 --- a/src/d/actor/d_a_obj_bhashi.cpp +++ b/src/d/actor/d_a_obj_bhashi.cpp @@ -285,7 +285,13 @@ bool Hahen_c::CheckCull() { bool Hahen_c::checkViewArea() { Vec proj; + + #if TARGET_PC + mDoLib_project(&pos, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&pos, &proj); + #endif + return (proj.x >= -50.0f && proj.x <= 658.0f) && (proj.y >= -50.0f && proj.y <= 498.0f); } diff --git a/src/d/actor/d_a_obj_cho.cpp b/src/d/actor/d_a_obj_cho.cpp index 8fbc2dbde8..27b0b8ce0e 100644 --- a/src/d/actor/d_a_obj_cho.cpp +++ b/src/d/actor/d_a_obj_cho.cpp @@ -289,7 +289,13 @@ void daObjCHO_c::Z_BufferChk() { cXyz vec2, vec1; vec1 = current.pos; vec1.y += 20.0f; + + #if TARGET_PC + mDoLib_project(&vec1, &vec2, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&vec1, &vec2); + #endif + f32 trim_height; camera_process_class* camera = dComIfGp_getCamera(0); if (camera != NULL) { diff --git a/src/d/actor/d_a_obj_crvfence.cpp b/src/d/actor/d_a_obj_crvfence.cpp index 9712205ea3..03ff2b1d6a 100644 --- a/src/d/actor/d_a_obj_crvfence.cpp +++ b/src/d/actor/d_a_obj_crvfence.cpp @@ -224,7 +224,13 @@ void daObjCRVFENCE_c::NormalAction() { bool daObjCRVFENCE_c::checkViewArea(cXyz* param_1) { Vec sp24; + + #if TARGET_PC + mDoLib_project(param_1, &sp24, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(param_1, &sp24); + #endif + bool rv = false; bool bVar1 = false; diff --git a/src/d/actor/d_a_obj_crvhahen.cpp b/src/d/actor/d_a_obj_crvhahen.cpp index 52d180f547..0b44a57ec8 100644 --- a/src/d/actor/d_a_obj_crvhahen.cpp +++ b/src/d/actor/d_a_obj_crvhahen.cpp @@ -137,7 +137,12 @@ void daObjCRVHAHEN_c::CheckCull() { bool daObjCRVHAHEN_c::checkViewArea(cXyz* i_this) { Vec proj; + + #if TARGET_PC + mDoLib_project(i_this, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(i_this, &proj); + #endif bool ret = false; diff --git a/src/d/actor/d_a_obj_dan.cpp b/src/d/actor/d_a_obj_dan.cpp index cc176b9a20..53dbf4e1e4 100644 --- a/src/d/actor/d_a_obj_dan.cpp +++ b/src/d/actor/d_a_obj_dan.cpp @@ -267,7 +267,13 @@ void daObjDAN_c::Z_BufferChk() { cXyz vec2, vec1; vec1 = current.pos; vec1.y += 20.0f; + + #if TARGET_PC + mDoLib_project(&vec1, &vec2, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&vec1, &vec2); + #endif + f32 trim_height; camera_process_class* camera = dComIfGp_getCamera(0); if (camera != NULL) { diff --git a/src/d/actor/d_a_obj_gomikabe.cpp b/src/d/actor/d_a_obj_gomikabe.cpp index 66963f0efd..a5b58a44a5 100644 --- a/src/d/actor/d_a_obj_gomikabe.cpp +++ b/src/d/actor/d_a_obj_gomikabe.cpp @@ -201,7 +201,13 @@ void daObjGOMIKABE_c::CheckCull() { bool daObjGOMIKABE_c::checkViewArea(cXyz param_1) { Vec local_24; + + #if TARGET_PC + mDoLib_project(¶m_1, &local_24, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(¶m_1, &local_24); + #endif + bool rv = false; if (local_24.x >= 0.0f && local_24.x <= FB_WIDTH && local_24.y >= 0.0f && local_24.y <= FB_HEIGHT) { rv = true; diff --git a/src/d/actor/d_a_obj_hhashi.cpp b/src/d/actor/d_a_obj_hhashi.cpp index d5ab5558b0..ea45fa5ea1 100644 --- a/src/d/actor/d_a_obj_hhashi.cpp +++ b/src/d/actor/d_a_obj_hhashi.cpp @@ -214,7 +214,13 @@ void daObjHHASHI_c::CheckCull() { bool daObjHHASHI_c::checkViewArea(int param_1) { Vec local_20; + + #if TARGET_PC + mDoLib_project(&field_0x5b0[param_1], &local_20, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&field_0x5b0[param_1], &local_20); + #endif + bool rv = false; if (local_20.x >= 0.0f && local_20.x <= FB_WIDTH && local_20.y >= 0.0f && local_20.y <= FB_HEIGHT) { rv = true; diff --git a/src/d/actor/d_a_obj_kamakiri.cpp b/src/d/actor/d_a_obj_kamakiri.cpp index 2b641d7769..daa6560e6f 100644 --- a/src/d/actor/d_a_obj_kamakiri.cpp +++ b/src/d/actor/d_a_obj_kamakiri.cpp @@ -517,7 +517,13 @@ void daObjKAM_c::Z_BufferChk() { cXyz currentOffset; currentOffset = current.pos; currentOffset.y += 20.0f; + + #if TARGET_PC + mDoLib_project(¤tOffset, ¤tProj, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(¤tOffset, ¤tProj); + #endif + camera_process_class* camera = dComIfGp_getCamera(0); f32 cameraHeight; if (camera != NULL) { diff --git a/src/d/actor/d_a_obj_katatsumuri.cpp b/src/d/actor/d_a_obj_katatsumuri.cpp index 8b85644d80..03d40a1066 100644 --- a/src/d/actor/d_a_obj_katatsumuri.cpp +++ b/src/d/actor/d_a_obj_katatsumuri.cpp @@ -611,7 +611,12 @@ void daObjKAT_c::Z_BufferChk() { cXyz curWithOff; curWithOff = current.pos; curWithOff.y += 20.0f; + + #if TARGET_PC + mDoLib_project(&curWithOff, &projected, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&curWithOff, &projected); + #endif camera_process_class* camera = dComIfGp_getCamera(0); f32 unkFloat1; diff --git a/src/d/actor/d_a_obj_kuwagata.cpp b/src/d/actor/d_a_obj_kuwagata.cpp index ddb00d443d..914e25dfb1 100644 --- a/src/d/actor/d_a_obj_kuwagata.cpp +++ b/src/d/actor/d_a_obj_kuwagata.cpp @@ -528,7 +528,12 @@ void daObjKUW_c::Z_BufferChk() { cStack_68 = current.pos; cStack_68.y += 20.0f; + + #if TARGET_PC + mDoLib_project(&cStack_68, &local_5c, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&cStack_68, &local_5c); + #endif camera_process_class* cc = dComIfGp_getCamera(0); f32 trimHeight; diff --git a/src/d/actor/d_a_obj_ten.cpp b/src/d/actor/d_a_obj_ten.cpp index fbedd6a8c9..1efe358607 100644 --- a/src/d/actor/d_a_obj_ten.cpp +++ b/src/d/actor/d_a_obj_ten.cpp @@ -593,7 +593,13 @@ void daObjTEN_c::Z_BufferChk() { cXyz cStack_68; cStack_68 = current.pos; cStack_68.y += 20.0f; + + #if TARGET_PC + mDoLib_project(&cStack_68, &local_5c, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&cStack_68, &local_5c); + #endif + camera_process_class* camera = dComIfGp_getCamera(0); f32 trimHeight; if (camera != NULL) { diff --git a/src/d/actor/d_a_obj_tombo.cpp b/src/d/actor/d_a_obj_tombo.cpp index 092b1c46c3..48db14ac92 100644 --- a/src/d/actor/d_a_obj_tombo.cpp +++ b/src/d/actor/d_a_obj_tombo.cpp @@ -504,7 +504,13 @@ void daObjTOMBO_c::Z_BufferChk() { cXyz cStack_68; cStack_68 = current.pos; cStack_68.y += 20.0f; + + #if TARGET_PC + mDoLib_project(&cStack_68, &local_5c, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&cStack_68, &local_5c); + #endif + camera_process_class* pCamera = dComIfGp_getCamera(0); f32 trimHeight; if (pCamera != NULL) { diff --git a/src/d/actor/d_a_obj_zra_freeze.cpp b/src/d/actor/d_a_obj_zra_freeze.cpp index 1525bdb572..08932c439d 100644 --- a/src/d/actor/d_a_obj_zra_freeze.cpp +++ b/src/d/actor/d_a_obj_zra_freeze.cpp @@ -38,7 +38,12 @@ BOOL daZraFreeze_c::chkActorInScreen() { mDoMtx_stack_c::transM(0.0f, 0.0f, 0.0f); PSMTXMultVecArray(mDoMtx_stack_c::get(), vec, vec, 8); for (int i = 0; i < 8; i++) { + #if TARGET_PC + mDoLib_project(&vec[i], &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&vec[i], &proj); + #endif + if (0.0f < proj.x && proj.x < FB_WIDTH && 0.0f < proj.y && proj.y < FB_HEIGHT) { continue; } diff --git a/src/d/d_insect.cpp b/src/d/d_insect.cpp index 3f1d2fae11..380f545bd3 100644 --- a/src/d/d_insect.cpp +++ b/src/d/d_insect.cpp @@ -82,7 +82,11 @@ void dInsect_c::CalcZBuffer(f32 param_0) { pos = current.pos; pos.y += 20.0f; + #if TARGET_PC + mDoLib_project(&pos, &pos_projected, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&pos, &pos_projected); + #endif if (dComIfGp_getCamera(0)) { camera_trim_height = dComIfGp_getCamera(0)->mCamera.mTrimHeight; diff --git a/src/d/d_kankyo.cpp b/src/d/d_kankyo.cpp index ec35ee8bc7..50f9d716fc 100644 --- a/src/d/d_kankyo.cpp +++ b/src/d/d_kankyo.cpp @@ -10977,7 +10977,11 @@ void dKy_depth_dist_set(void* process_p) { f32 var_f31 = sp24.abs(camera_p->view.lookat.eye); if (var_f31 < 2000.0f && var_f31 < kankyo->field_0x1268) { + #if TARGET_PC + mDoLib_project(&actor_p->eyePos, &sp30, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&actor_p->eyePos, &sp30); + #endif if ((sp30.x >= 0.0f && sp30.x < FB_WIDTH) && (sp30.y >= 0.0f && #if DEBUG diff --git a/src/d/d_kankyo_debug.cpp b/src/d/d_kankyo_debug.cpp index 7fdad26ed2..03bfeac196 100644 --- a/src/d/d_kankyo_debug.cpp +++ b/src/d/d_kankyo_debug.cpp @@ -915,7 +915,12 @@ void dKydb_dungeonlight_draw() { rot.y = 0; dDbVw_drawCubeXlu(player->current.pos, size, rot, color); + #if TARGET_PC + mDoLib_project(&g_env_light.dungeonlight[i].mPosition, &proj, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&g_env_light.dungeonlight[i].mPosition, &proj); + #endif + if (proj.x > 30.0f) { proj.x -= 30.0f; } diff --git a/src/d/d_msg_object.cpp b/src/d/d_msg_object.cpp index 8836acff10..3676639908 100644 --- a/src/d/d_msg_object.cpp +++ b/src/d/d_msg_object.cpp @@ -1464,12 +1464,24 @@ void dMsgObject_c::fukiPosCalc(bool param_1) { fopAc_ac_c* player = dComIfGp_getPlayer(0); cXyz local_3c; cXyz cStack_48; + + #if TARGET_PC + mDoLib_project(&player->eyePos, &cStack_48, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&player->eyePos, &cStack_48); + #endif + f32 temp; if ((field_0x100->pos == cXyz(0.0f, 0.0f, 0.0f))) { temp = cStack_48.y; } else { + + #if TARGET_PC + mDoLib_project(&field_0x100->pos, &local_3c, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&field_0x100->pos, &local_3c); + #endif + if (local_3c.x >= 0.0f && local_3c.x <= FB_WIDTH && local_3c.y >= 0.0f && local_3c.y <= FB_HEIGHT) { diff --git a/src/d/d_msg_scrn_item.cpp b/src/d/d_msg_scrn_item.cpp index bb4daf3927..7cba6c7b86 100644 --- a/src/d/d_msg_scrn_item.cpp +++ b/src/d/d_msg_scrn_item.cpp @@ -557,11 +557,22 @@ void dMsgScrnItem_c::fukiPosCalc(u8 param_1) { cXyz local_70; cXyz cStack_7c; f32 f3; + + #if TARGET_PC + mDoLib_project(&player->eyePos, &cStack_7c, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&player->eyePos, &cStack_7c); + #endif + if (iVar6->pos == cXyz(0.0f, 0.0f, 0.0f)) { f3 = cStack_7c.y; } else { + #if TARGET_PC + mDoLib_project(&iVar6->pos, &local_70, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&iVar6->pos, &local_70); + #endif + if (local_70.x >= 0.0f && local_70.x <= FB_WIDTH && local_70.y >= 0.0f && local_70.y <= FB_HEIGHT) { diff --git a/src/d/d_msg_scrn_talk.cpp b/src/d/d_msg_scrn_talk.cpp index 226ece0304..546e42112f 100644 --- a/src/d/d_msg_scrn_talk.cpp +++ b/src/d/d_msg_scrn_talk.cpp @@ -441,11 +441,22 @@ void dMsgScrnTalk_c::fukiPosCalc(u8 param_1) { cXyz local_70; cXyz cStack_7c; f32 f3y; + + #if TARGET_PC + mDoLib_project(&player->eyePos, &cStack_7c, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else mDoLib_project(&player->eyePos, &cStack_7c); + #endif + if (msgActor->pos == cXyz(0.0f, 0.0f, 0.0f)) { f3y = cStack_7c.y; } else { - mDoLib_project(&msgActor->pos, &local_70); + #if TARGET_PC + mDoLib_project(&msgActor->pos, &local_70, {0, 0, FB_WIDTH, FB_HEIGHT}); + #else + mDoLib_project(&msgActor->pos, &local_70,); + #endif + if (local_70.x >= 0.0f && local_70.x <= 608.0f && local_70.y >= 0.0f && local_70.y <= 448.0f) { From c41ec46c71d352201fed6a34ddf64cc4084856ea Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 6 Apr 2026 00:48:10 -0700 Subject: [PATCH 30/72] reorganize menus a bit --- src/dusk/imgui/ImGuiMenuEnhancements.cpp | 6 ++++++ src/dusk/imgui/ImGuiMenuTools.cpp | 5 +---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/dusk/imgui/ImGuiMenuEnhancements.cpp b/src/dusk/imgui/ImGuiMenuEnhancements.cpp index 3fbd55a8f2..a7a1e1d698 100644 --- a/src/dusk/imgui/ImGuiMenuEnhancements.cpp +++ b/src/dusk/imgui/ImGuiMenuEnhancements.cpp @@ -125,6 +125,12 @@ namespace dusk { ImGui::EndMenu(); } + if (ImGui::BeginMenu("Tools")) { + config::ImGuiCheckbox("Enable Turbo Key", getSettings().game.enableTurboKeybind); + + ImGui::EndMenu(); + } + ImGui::EndMenu(); } } diff --git a/src/dusk/imgui/ImGuiMenuTools.cpp b/src/dusk/imgui/ImGuiMenuTools.cpp index 6a2fc2ede0..7478adc0e5 100644 --- a/src/dusk/imgui/ImGuiMenuTools.cpp +++ b/src/dusk/imgui/ImGuiMenuTools.cpp @@ -7,7 +7,6 @@ #include "ImGuiConsole.hpp" #include "ImGuiMenuTools.hpp" -#include "ImGuiConfig.hpp" #include "d/actor/d_a_alink.h" #include "d/actor/d_a_horse.h" #include "d/d_com_inf_game.h" @@ -19,7 +18,7 @@ namespace dusk { void ImGuiMenuTools::draw() { bool isToggleDevelopmentMode = false; - if (ImGui::BeginMenu("Tools")) { + if (ImGui::BeginMenu("Debug")) { if (ImGui::Checkbox("Development Mode", &m_isDevelopmentMode)) { isToggleDevelopmentMode = true; } @@ -50,8 +49,6 @@ namespace dusk { ImGui::MenuItem("Save Editor", nullptr, &m_showSaveEditor); ImGui::MenuItem("Audio Debug", hotkeys::SHOW_AUDIO_DEBUG, &m_showAudioDebug); ImGui::MenuItem("OSReport Force", nullptr, &OSReportReallyForceEnable); - ImGui::Separator(); - config::ImGuiMenuItem("Enable Turbo Key", hotkeys::TURBO, getSettings().game.enableTurboKeybind); ImGui::EndMenu(); } From 09ea3c57f59725ffb512c208794c1f2d8ae9aaa0 Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 6 Apr 2026 07:53:46 -0700 Subject: [PATCH 31/72] runtime data asset loader --- files.cmake | 2 + include/dusk/dvd_asset.hpp | 22 ++++++++ src/d/actor/d_a_mant.cpp | 22 ++++++++ src/d/actor/d_a_player.cpp | 6 +++ src/d/actor/d_flower.inc | 35 ++++++++++++ src/d/actor/d_grass.inc | 29 ++++++++-- src/d/d_error_msg.cpp | 17 ++++++ src/dusk/dvd_asset.cpp | 106 +++++++++++++++++++++++++++++++++++++ src/m_Do/m_Do_ext.cpp | 3 ++ 9 files changed, 239 insertions(+), 3 deletions(-) create mode 100644 include/dusk/dvd_asset.hpp create mode 100644 src/dusk/dvd_asset.cpp diff --git a/files.cmake b/files.cmake index 7d07408613..e9149a1777 100644 --- a/files.cmake +++ b/files.cmake @@ -1333,6 +1333,8 @@ set(DOLPHIN_FILES set(DUSK_FILES include/dusk/endian_gx.hpp include/dusk/config.hpp + include/dusk/dvd_asset.hpp + src/dusk/dvd_asset.cpp src/d/actor/d_a_alink_dusk.cpp src/dusk/asserts.cpp src/dusk/config.cpp diff --git a/include/dusk/dvd_asset.hpp b/include/dusk/dvd_asset.hpp new file mode 100644 index 0000000000..3c36b75195 --- /dev/null +++ b/include/dusk/dvd_asset.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "dolphin/types.h" + +namespace dusk { + +/** + * Load bytes from the main DOL by GameCube virtual address + */ +bool LoadDolAsset(void* dst, u32 virtualAddress, s32 size); + +/** + * Load bytes from a REL file in the ISO filesystem + */ +void* LoadRelAsset(const char* dvdPath, s32 offset, s32 size); + +/** + * Load bytes from a REL inside RELS.arc + */ +bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, s32 offset, s32 size); + +} // namespace dusk diff --git a/src/d/actor/d_a_mant.cpp b/src/d/actor/d_a_mant.cpp index a3b48f1098..1760db60fa 100644 --- a/src/d/actor/d_a_mant.cpp +++ b/src/d/actor/d_a_mant.cpp @@ -10,11 +10,21 @@ #include "d/actor/d_a_b_gnd.h" #include "d/d_com_inf_game.h" +#if TARGET_PC +#include "dusk/dvd_asset.hpp" +static u8* l_Egnd_mantTEX_get() { static u8* p = (u8*)dusk::LoadRelAsset("/rel/Final/Release/d_a_mant.rel", 0x1C00, 0x4000); return p; } +static u8* l_Egnd_mantTEX_U_get() { static u8* p = (u8*)dusk::LoadRelAsset("/rel/Final/Release/d_a_mant.rel", 0x5C00, 0x4000); return p; } +static u8* l_Egnd_mantPAL_get() { static u8* p = (u8*)dusk::LoadRelAsset("/rel/Final/Release/d_a_mant.rel", 0x9C00, 0x60); return p; } +#define l_Egnd_mantTEX (l_Egnd_mantTEX_get()) +#define l_Egnd_mantTEX_U (l_Egnd_mantTEX_U_get()) +#define l_Egnd_mantPAL (l_Egnd_mantPAL_get()) +#else #include "assets/l_Egnd_mantTEX.h" #include "assets/l_Egnd_mantTEX_U.h" #include "assets/l_Egnd_mantPAL.h" +#endif #include "d/d_s_play.h" static u32 l_pos[507] = { @@ -239,20 +249,32 @@ static u32 l_texCoord[338] = { 0x3F800000, 0x00000000, }; +#if TARGET_PC +static u8* l_Egnd_mantDL_get() { static u8* p = (u8*)dusk::LoadRelAsset("/rel/Final/Release/d_a_mant.rel", 0xA9A0, 0x3EC); return p; } +#define l_Egnd_mantDL (l_Egnd_mantDL_get()) +#else #include "assets/l_Egnd_mantDL.h" +#endif +#if !TARGET_PC static void* pal_d = (void*)&l_Egnd_mantPAL; static void* tex_d[2] = { (void*)&l_Egnd_mantTEX, (void*)&l_Egnd_mantTEX_U, }; +#endif static char lbl_277_bss_0; void daMant_packet_c::draw() { +#if TARGET_PC + void* image = l_Egnd_mantTEX; + void* lut = l_Egnd_mantPAL; +#else void* image = tex_d[0]; void* lut = pal_d; +#endif j3dSys.reinitGX(); GXSetNumIndStages(0); diff --git a/src/d/actor/d_a_player.cpp b/src/d/actor/d_a_player.cpp index f38fe15a3b..697635d69d 100644 --- a/src/d/actor/d_a_player.cpp +++ b/src/d/actor/d_a_player.cpp @@ -368,7 +368,13 @@ JKRHeap* daPy_anmHeap_c::setAnimeHeap() { } #if !PLATFORM_WII +#if TARGET_PC +#include "dusk/dvd_asset.hpp" +static const u8* l_sightDL_get() { static u8 buf[0x89]; static bool _ = (dusk::LoadDolAsset(buf, 0x803BA0C0, 0x89), true); return buf; } +#define l_sightDL (l_sightDL_get()) +#else #include "assets/l_sightDL__d_a_player.h" +#endif void daPy_sightPacket_c::draw() { TGXTexObj texObj; diff --git a/src/d/actor/d_flower.inc b/src/d/actor/d_flower.inc index 762b1e02e9..93a7e35097 100644 --- a/src/d/actor/d_flower.inc +++ b/src/d/actor/d_flower.inc @@ -13,7 +13,13 @@ const u16 l_J_Ohana00_64TEX__width = 63; const u16 l_J_Ohana00_64TEX__height = 63; #endif +#if TARGET_PC +#include "dusk/dvd_asset.hpp" +static u8* l_J_Ohana00_64TEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x9060, 0x800), true); return buf; } +#define l_J_Ohana00_64TEX (l_J_Ohana00_64TEX_get()) +#else #include "assets/l_J_Ohana00_64TEX.h" +#endif static u8 l_flowerPos[708] = { 0xC0, 0x8C, 0x2C, 0xF7, 0x42, 0x05, 0xBC, 0xDF, 0xC1, 0xA1, 0x00, 0x70, 0xBF, 0x50, 0x51, 0xB9, @@ -104,6 +110,16 @@ static u8 l_flowerTexCoord[] = { 0x3E, 0xA7, 0x67, 0x4D, 0x3C, 0x14, 0x46, 0x74, 0x3E, 0xA7, 0x73, 0xE2, 0xBC, 0x2F, 0x46, 0xAA, 0x3E, 0xA7, 0x72, 0xD6, 0xBD, 0x2F, 0x46, 0xAA}; +#if TARGET_PC +static u8* l_J_hana00DL_get() { static u8 buf[0x150]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x9D20, 0x150), true); return buf; } +static u8* l_J_hana00_cDL_get() { static u8 buf[0xDE]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x9E80, 0xDE), true); return buf; } +static u8* l_matDL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x9F60, 0x99), true); return buf; } +static u8* l_matLight4DL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xA000, 0x99), true); return buf; } +#define l_J_hana00DL (l_J_hana00DL_get()) +#define l_J_hana00_cDL (l_J_hana00_cDL_get()) +#define l_matDL (l_matDL_get()) +#define l_matLight4DL (l_matLight4DL_get()) +#else #include "assets/l_J_hana00DL.h" #include "assets/l_J_hana00_cDL.h" @@ -113,6 +129,7 @@ l_matDL__d_a_grass(l_J_Ohana00_64TEX) #include "assets/l_matLight4DL.h" l_matLight4DL(l_J_Ohana00_64TEX) +#endif #if TARGET_PC const u16 l_J_Ohana01_64128_0419TEX__width = 64; @@ -122,7 +139,12 @@ const u16 l_J_Ohana01_64128_0419TEX__width = 63; const u16 l_J_Ohana01_64128_0419TEX__height = 127; #endif +#if TARGET_PC +static u8* l_J_Ohana01_64128_0419TEX_get() { static u8 buf[0x1000]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xA0A0, 0x1000), true); return buf; } +#define l_J_Ohana01_64128_0419TEX (l_J_Ohana01_64128_0419TEX_get()) +#else #include "assets/l_J_Ohana01_64128_0419TEX.h" +#endif static u8 l_flowerPos2[1224] = { 0x40, 0x25, 0x9F, 0x34, 0x42, 0xC2, 0x95, 0x72, 0xC1, 0x22, 0x34, 0x78, 0x41, 0x4D, 0xF9, 0x63, @@ -249,6 +271,18 @@ static u8 l_flowerTexCoord2[] = { 0x40, 0x1B, 0x7D, 0x52, 0x3F, 0x97, 0xF6, 0xBA, 0x40, 0x04, 0x26, 0x74, 0x3F, 0x80, 0x3F, 0x79, 0x40, 0x1B, 0x7D, 0x52, 0x3F, 0x80, 0x3F, 0x79, 0x40, 0x1B, 0x7D, 0x52, 0x3F, 0x51, 0x10, 0x6F}; +#if TARGET_PC +static u8* l_J_hana01DL_get() { static u8 buf[0x138]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xB7C0, 0x138), true); return buf; } +static u8* l_J_hana01_c_00DL_get() { static u8 buf[0xDE]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xB900, 0xDE), true); return buf; } +static u8* l_J_hana01_c_01DL_get() { static u8 buf[0x128]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xB9E0, 0x128), true); return buf; } +static u8* l_mat2DL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xBB20, 0x99), true); return buf; } +static u8* l_mat2Light4DL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xBBC0, 0x99), true); return buf; } +#define l_J_hana01DL (l_J_hana01DL_get()) +#define l_J_hana01_c_00DL (l_J_hana01_c_00DL_get()) +#define l_J_hana01_c_01DL (l_J_hana01_c_01DL_get()) +#define l_mat2DL (l_mat2DL_get()) +#define l_mat2Light4DL (l_mat2Light4DL_get()) +#else #include "assets/l_J_hana01DL.h" #include "assets/l_J_hana01_c_00DL.h" @@ -260,6 +294,7 @@ l_mat2DL__d_a_grass(l_J_Ohana01_64128_0419TEX) #include "assets/l_mat2Light4DL.h" l_mat2Light4DL(l_J_Ohana01_64128_0419TEX) +#endif void dFlower_data_c::WorkCo(fopAc_ac_c* i_hitActor, u32 i_massFlg, int i_roomNo) { cXyz sp8; diff --git a/src/d/actor/d_grass.inc b/src/d/actor/d_grass.inc index 6351cc75fc..3645488b0f 100644 --- a/src/d/actor/d_grass.inc +++ b/src/d/actor/d_grass.inc @@ -13,11 +13,19 @@ const u16 l_M_Hijiki00TEX__width = 31; const u16 l_M_Hijiki00TEX__height = 31; -#include "assets/l_M_kusa05_RGBATEX.h" // ALIGN 32 - const u16 l_M_kusa05_RGBATEX__width = 31; const u16 l_M_kusa05_RGBATEX__height = 31; -#include "assets/l_M_Hijiki00TEX.h" // ALIGN 32 + +#if TARGET_PC +#include "dusk/dvd_asset.hpp" +static u8* l_M_kusa05_RGBATEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x7680, 0x800), true); return buf; } +static u8* l_M_Hijiki00TEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x7E80, 0x800), true); return buf; } +#define l_M_kusa05_RGBATEX (l_M_kusa05_RGBATEX_get()) +#define l_M_Hijiki00TEX (l_M_Hijiki00TEX_get()) +#else +#include "assets/l_M_kusa05_RGBATEX.h" // ALIGN 32 +#include "assets/l_M_Hijiki00TEX.h" // ALIGN 32 +#endif static u8 l_pos[960] = { 0x3F, 0x4A, 0x56, 0xEF, 0xC2, 0x20, 0x00, 0x00, 0x41, 0xFB, 0x17, 0xE4, 0x41, 0xAA, 0xBB, 0xEA, @@ -102,6 +110,20 @@ static u8 l_texCoord[160] = { 0x3F, 0x94, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0xBD, 0xC0, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, }; +#if TARGET_PC +static u8* l_M_Kusa_9qDL_get() { static u8 buf[0xCB]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8B00, 0xCB), true); return buf; } +static u8* l_M_Kusa_9q_cDL_get() { static u8 buf[0xCB]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8BE0, 0xCB), true); return buf; } +static u8* l_M_TenGusaDL_get() { static u8 buf[0xD4]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8CC0, 0xD4), true); return buf; } +static u8* l_Tengusa_matDL_get() { static u8 buf[0xA8]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8DA0, 0xA8), true); return buf; } +static u8* l_kusa9q_matDL_get() { static u8 buf[0xA8]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8E60, 0xA8), true); return buf; } +static u8* l_kusa9q_l4_matDL_get() { static u8 buf[0xA8]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8F20, 0xA8), true); return buf; } +#define l_M_Kusa_9qDL (l_M_Kusa_9qDL_get()) +#define l_M_Kusa_9q_cDL (l_M_Kusa_9q_cDL_get()) +#define l_M_TenGusaDL (l_M_TenGusaDL_get()) +#define l_Tengusa_matDL (l_Tengusa_matDL_get()) +#define l_kusa9q_matDL (l_kusa9q_matDL_get()) +#define l_kusa9q_l4_matDL (l_kusa9q_l4_matDL_get()) +#else #include "assets/l_M_Kusa_9qDL.h" #include "assets/l_M_Kusa_9q_cDL.h" @@ -117,6 +139,7 @@ l_kusa9q_matDL(l_M_kusa05_RGBATEX) #include "assets/l_kusa9q_l4_matDL.h" l_kusa9q_l4_matDL(l_M_kusa05_RGBATEX) +#endif void dGrass_data_c::WorkCo(fopAc_ac_c* i_hitActor, u32 i_massFlg, int i_roomNo) { cXyz sp18; diff --git a/src/d/d_error_msg.cpp b/src/d/d_error_msg.cpp index faa40ae543..f1d63b5a1f 100644 --- a/src/d/d_error_msg.cpp +++ b/src/d/d_error_msg.cpp @@ -15,6 +15,22 @@ #include "m_Do/m_Do_Reset.h" #include "m_Do/m_Do_graphic.h" +#if TARGET_PC +#include "dusk/dvd_asset.hpp" +static const u8* black_tex_get() { static u8 buf[0x40]; static bool _ = (dusk::LoadDolAsset(buf, 0x8037B140, 0x40), true); return buf; } +static const u8* msg_data_get() { static u8 buf[0x260]; static bool _ = (dusk::LoadDolAsset(buf, 0x8037B180, 0x260), true); return buf; } +static const u8* font_data_get() { static u8 buf[0x12260]; static bool _ = (dusk::LoadDolAsset(buf, 0x8037B3E0, 0x12260), true); return buf; } +#define black_tex (black_tex_get()) +#define msg_data (msg_data_get()) +#define font_data (font_data_get()) +#if VERSION == VERSION_GCN_PAL +// TODO: find addreses for pal languages +#define msg_data_ge ((const u8*)nullptr) +#define msg_data_fr ((const u8*)nullptr) +#define msg_data_sp ((const u8*)nullptr) +#define msg_data_it ((const u8*)nullptr) +#endif +#else #include "assets/black_tex.h" #include "assets/msg_data.h" #if VERSION == VERSION_GCN_PAL @@ -24,6 +40,7 @@ #include "assets/msg_data_it.h" #endif #include "assets/font_data.h" +#endif #define MSG_READING_DISC 0 #define MSG_COVER_OPEN 1 diff --git a/src/dusk/dvd_asset.cpp b/src/dusk/dvd_asset.cpp new file mode 100644 index 0000000000..bfa30cc941 --- /dev/null +++ b/src/dusk/dvd_asset.cpp @@ -0,0 +1,106 @@ +#include "dusk/dvd_asset.hpp" +#include "dusk/logging.h" +#include "dusk/endian.h" +#include "aurora/dvd.h" +#include "DynamicLink.h" +#include "JSystem/JKernel/JKRArchive.h" +#include "JSystem/JKernel/JKRDvdRipper.h" + +#include + +namespace dusk { + +static const u8* s_dolData = nullptr; // pointer to dol data +static size_t s_dolSize = 0; +struct DolSection { u32 fileOffset, vaddr, size; }; +static DolSection s_dolSections[18]; // 7 text + 11 data +static int s_dolSectionCount = 0; + +static bool EnsureDolParsed() { + if (s_dolData) return true; + + s32 sz = 0; + const u8* p = aurora_dvd_get_dol(sz); + if (!p || sz < 256) { + DuskLog.fatal("dvd_asset: aurora_dvd_get_dol failed (size={})", sz); return false; + } + + s_dolData = p; + s_dolSize = sz; + + const BE(u32)* hdr = (const BE(u32)*)s_dolData; + s_dolSectionCount = 0; + + // 0x00: text file offsets 0x12: text vaddrs 0x24: text sizes + for (int i = 0; i < 7; i++) { + u32 off = hdr[0x00+i], addr = hdr[0x12+i], sz = hdr[0x24+i]; + if (sz > 0 && off > 0) { + s_dolSections[s_dolSectionCount++] = {off, addr, sz}; + } + } + // 0x07: data file offsets 0x19: data vaddrs 0x2B: data sizes + for (int i = 0; i < 11; i++) { + u32 off = hdr[0x07+i], addr = hdr[0x19+i], sz = hdr[0x2B+i]; + if (sz > 0 && off > 0) { + s_dolSections[s_dolSectionCount++] = {off, addr, sz}; + } + } + + return true; +} + +static s32 DolVaToFileOffset(u32 va) { + if (!EnsureDolParsed()) return -1; + for (int i = 0; i < s_dolSectionCount; i++) { + const auto& sec = s_dolSections[i]; + if (va >= sec.vaddr && va < sec.vaddr + sec.size) { + return static_cast(sec.fileOffset + (va - sec.vaddr)); + } + } + DuskLog.fatal("dvd_asset: VA 0x{:08X} not found in any DOL section", va); + return -1; +} + +bool LoadDolAsset(void* dst, u32 virtualAddress, s32 size) { + s32 fileOffset = DolVaToFileOffset(virtualAddress); + if (fileOffset < 0) { + return false; + } + + if (size <= 0 || (size_t)(fileOffset + size) > s_dolSize) { + DuskLog.fatal("dvd_asset: DOL read out of range (offset={:#x} size={:#x} dolSize={})", fileOffset, size, s_dolSize); + return false; + } + + std::memcpy(dst, s_dolData + fileOffset, size); + return true; +} + +void* LoadRelAsset(const char* dvdPath, s32 offset, s32 size) { + void* p = JKRDvdRipper::loadToMainRAM(dvdPath, nullptr, EXPAND_SWITCH_UNKNOWN1, (u32)size, nullptr, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, (u32)offset, nullptr, nullptr); + if (!p) DuskLog.fatal("dvd_asset: failed to load {} (offset={:#x} size={:#x})", dvdPath, offset, size); + return p; +} + +bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, s32 offset, s32 size) { + // On TARGET_PC, cDyl_InitCallback skips DynamicModuleControl::initialize() due to static linking + // Mount RELS.arc on first use so sArchive is available + static bool s_mountAttempted = false; + if (!DynamicModuleControl::sArchive && !s_mountAttempted) { + s_mountAttempted = true; DynamicModuleControl::initialize(); + } + + if (!DynamicModuleControl::sArchive) { + DuskLog.fatal("dvd_asset: RELS archive not mounted"); return false; + } + + const u8* rel = static_cast(DynamicModuleControl::sArchive->getResource(memType, relFileName)); + if (!rel) { + DuskLog.fatal("dvd_asset: {} not found in RELS archive", relFileName); return false; + } + + std::memcpy(dst, rel + offset, size); + return true; +} + +} // namespace dusk diff --git a/src/m_Do/m_Do_ext.cpp b/src/m_Do/m_Do_ext.cpp index d744d048ba..0593815b1d 100644 --- a/src/m_Do/m_Do_ext.cpp +++ b/src/m_Do/m_Do_ext.cpp @@ -2873,7 +2873,10 @@ void mDoExt_3DlineMat1_c::update(int param_0, f32 param_1, GXColor& param_2, u16 sp_38++; } } + +#if !TARGET_PC #include "assets/l_mat2DL__d_a_grass.h" +#endif void mDoExt_3DlineMat2_c::setMaterial() { j3dSys.reinitGX(); From 7af15e98bc04bbab767ad32865c27b7fa8198e4f Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 6 Apr 2026 07:55:10 -0700 Subject: [PATCH 32/72] remove includes --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a074ea869..448a58a45e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,7 +100,6 @@ set(GAME_COMPILE_DEFS TARGET_PC AVOID_UB=1 VERSION=0 set(GAME_INCLUDE_DIRS include src - assets/${DUSK_TP_VERSION} libs/JSystem/include libs extern/aurora/include/dolphin From 31ccc912b7a99bada7671bcb7e6f05102b611dd7 Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 6 Apr 2026 07:57:00 -0700 Subject: [PATCH 33/72] walk that one on back --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index 448a58a45e..3a074ea869 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,6 +100,7 @@ set(GAME_COMPILE_DEFS TARGET_PC AVOID_UB=1 VERSION=0 set(GAME_INCLUDE_DIRS include src + assets/${DUSK_TP_VERSION} libs/JSystem/include libs extern/aurora/include/dolphin From ad8d35ee5e9ababcc193da3c586fe47708435892 Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 6 Apr 2026 08:49:24 -0700 Subject: [PATCH 34/72] address review --- include/dusk/dvd_asset.hpp | 4 ++-- src/d/actor/d_a_mant.cpp | 8 ++++---- src/d/actor/d_flower.inc | 10 +++++----- src/dusk/dvd_asset.cpp | 39 ++++++++++++++++++++++++++++---------- 4 files changed, 40 insertions(+), 21 deletions(-) diff --git a/include/dusk/dvd_asset.hpp b/include/dusk/dvd_asset.hpp index 3c36b75195..014c683d44 100644 --- a/include/dusk/dvd_asset.hpp +++ b/include/dusk/dvd_asset.hpp @@ -10,9 +10,9 @@ namespace dusk { bool LoadDolAsset(void* dst, u32 virtualAddress, s32 size); /** - * Load bytes from a REL file in the ISO filesystem + * Load bytes from a REL file in the ISO filesystem, dst must be 32-byte aligned */ -void* LoadRelAsset(const char* dvdPath, s32 offset, s32 size); +bool LoadRelAsset(void* dst, const char* dvdPath, s32 offset, s32 size); /** * Load bytes from a REL inside RELS.arc diff --git a/src/d/actor/d_a_mant.cpp b/src/d/actor/d_a_mant.cpp index 1760db60fa..bcd7f05986 100644 --- a/src/d/actor/d_a_mant.cpp +++ b/src/d/actor/d_a_mant.cpp @@ -12,9 +12,9 @@ #if TARGET_PC #include "dusk/dvd_asset.hpp" -static u8* l_Egnd_mantTEX_get() { static u8* p = (u8*)dusk::LoadRelAsset("/rel/Final/Release/d_a_mant.rel", 0x1C00, 0x4000); return p; } -static u8* l_Egnd_mantTEX_U_get() { static u8* p = (u8*)dusk::LoadRelAsset("/rel/Final/Release/d_a_mant.rel", 0x5C00, 0x4000); return p; } -static u8* l_Egnd_mantPAL_get() { static u8* p = (u8*)dusk::LoadRelAsset("/rel/Final/Release/d_a_mant.rel", 0x9C00, 0x60); return p; } +static u8* l_Egnd_mantTEX_get() { alignas(32) static u8 buf[0x4000]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", 0x1C00, 0x4000), true); return buf; } +static u8* l_Egnd_mantTEX_U_get() { alignas(32) static u8 buf[0x4000]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", 0x5C00, 0x4000), true); return buf; } +static u8* l_Egnd_mantPAL_get() { alignas(32) static u8 buf[0x60]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", 0x9C00, 0x60), true); return buf; } #define l_Egnd_mantTEX (l_Egnd_mantTEX_get()) #define l_Egnd_mantTEX_U (l_Egnd_mantTEX_U_get()) #define l_Egnd_mantPAL (l_Egnd_mantPAL_get()) @@ -250,7 +250,7 @@ static u32 l_texCoord[338] = { }; #if TARGET_PC -static u8* l_Egnd_mantDL_get() { static u8* p = (u8*)dusk::LoadRelAsset("/rel/Final/Release/d_a_mant.rel", 0xA9A0, 0x3EC); return p; } +static u8* l_Egnd_mantDL_get() { alignas(32) static u8 buf[0x3EC]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", 0xA9A0, 0x3EC), true); return buf; } #define l_Egnd_mantDL (l_Egnd_mantDL_get()) #else #include "assets/l_Egnd_mantDL.h" diff --git a/src/d/actor/d_flower.inc b/src/d/actor/d_flower.inc index 93a7e35097..de6ac7c1dc 100644 --- a/src/d/actor/d_flower.inc +++ b/src/d/actor/d_flower.inc @@ -619,9 +619,9 @@ void dFlower_packet_c::draw() { } if (sp4C <= 2) { - GXCallDisplayList(&l_matLight4DL, 0x80); + GXCallDisplayList(l_matLight4DL, 0x80); } else { - GXCallDisplayList(&l_matDL, 0x80); + GXCallDisplayList(l_matDL, 0x80); } GXSetTevColorS10(GX_TEVREG0, sp80); @@ -677,9 +677,9 @@ void dFlower_packet_c::draw() { #endif if (!cLib_checkBit(sp44->m_state, 8)) { - GXCallDisplayList(&l_J_hana00DL, 0x140); + GXCallDisplayList(l_J_hana00DL, 0x140); } else { - GXCallDisplayList(&l_J_hana00_cDL, 0xC0); + GXCallDisplayList(l_J_hana00_cDL, 0xC0); } } } @@ -826,7 +826,7 @@ void dFlower_packet_c::draw() { if (!cLib_checkBit(sp34->m_state, 0x10)) { GXCallDisplayList(mp_Jhana01DL, m_Jhana01DL_size); } else { - GXCallDisplayList(&l_J_hana01_c_00DL, 0xC0); + GXCallDisplayList(l_J_hana01_c_00DL, 0xC0); } } else { GXCallDisplayList(mp_Jhana01_cDL, m_Jhana01_cDL_size); diff --git a/src/dusk/dvd_asset.cpp b/src/dusk/dvd_asset.cpp index bfa30cc941..9bcea14077 100644 --- a/src/dusk/dvd_asset.cpp +++ b/src/dusk/dvd_asset.cpp @@ -12,7 +12,22 @@ namespace dusk { static const u8* s_dolData = nullptr; // pointer to dol data static size_t s_dolSize = 0; -struct DolSection { u32 fileOffset, vaddr, size; }; + +struct DolHeader { + BE(u32) textOffset[7]; + BE(u32) dataOffset[11]; + BE(u32) textAddr[7]; + BE(u32) dataAddr[11]; + BE(u32) textSize[7]; + BE(u32) dataSize[11]; +}; + +struct DolSection { + u32 fileOffset; + u32 vaddr; + u32 size; +}; + static DolSection s_dolSections[18]; // 7 text + 11 data static int s_dolSectionCount = 0; @@ -22,25 +37,29 @@ static bool EnsureDolParsed() { s32 sz = 0; const u8* p = aurora_dvd_get_dol(sz); if (!p || sz < 256) { - DuskLog.fatal("dvd_asset: aurora_dvd_get_dol failed (size={})", sz); return false; + DuskLog.fatal("dvd_asset: aurora_dvd_get_dol failed (size={})", sz); + return false; } s_dolData = p; s_dolSize = sz; - const BE(u32)* hdr = (const BE(u32)*)s_dolData; + const auto* hdr = (const DolHeader*)s_dolData; s_dolSectionCount = 0; - // 0x00: text file offsets 0x12: text vaddrs 0x24: text sizes for (int i = 0; i < 7; i++) { - u32 off = hdr[0x00+i], addr = hdr[0x12+i], sz = hdr[0x24+i]; + u32 off = hdr->textOffset[i]; + u32 addr = hdr->textAddr[i]; + u32 sz = hdr->textSize[i]; if (sz > 0 && off > 0) { s_dolSections[s_dolSectionCount++] = {off, addr, sz}; } } - // 0x07: data file offsets 0x19: data vaddrs 0x2B: data sizes + for (int i = 0; i < 11; i++) { - u32 off = hdr[0x07+i], addr = hdr[0x19+i], sz = hdr[0x2B+i]; + u32 off = hdr->dataOffset[i]; + u32 addr = hdr->dataAddr[i]; + u32 sz = hdr->dataSize[i]; if (sz > 0 && off > 0) { s_dolSections[s_dolSectionCount++] = {off, addr, sz}; } @@ -76,10 +95,10 @@ bool LoadDolAsset(void* dst, u32 virtualAddress, s32 size) { return true; } -void* LoadRelAsset(const char* dvdPath, s32 offset, s32 size) { - void* p = JKRDvdRipper::loadToMainRAM(dvdPath, nullptr, EXPAND_SWITCH_UNKNOWN1, (u32)size, nullptr, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, (u32)offset, nullptr, nullptr); +bool LoadRelAsset(void* dst, const char* dvdPath, s32 offset, s32 size) { + void* p = JKRDvdRipper::loadToMainRAM(dvdPath, (u8*)dst, EXPAND_SWITCH_UNKNOWN1, (u32)size, nullptr, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, (u32)offset, nullptr, nullptr); if (!p) DuskLog.fatal("dvd_asset: failed to load {} (offset={:#x} size={:#x})", dvdPath, offset, size); - return p; + return p != nullptr; } bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, s32 offset, s32 size) { From fa978591c11867971ee41afcc7261681ba68942c Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 6 Apr 2026 08:58:52 -0700 Subject: [PATCH 35/72] update include directories --- CMakeLists.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a074ea869..a237daaacc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,9 +104,7 @@ set(GAME_INCLUDE_DIRS libs/JSystem/include libs extern/aurora/include/dolphin - extern - ${CMAKE_SOURCE_DIR}/build/${DUSK_TP_VERSION}/include - build/${DUSK_TP_VERSION}/include) + extern) set(GAME_LIBS aurora::core aurora::gx aurora::gd aurora::si aurora::vi aurora::pad aurora::mtx aurora::os aurora::dvd aurora::card freeverb cxxopts::cxxopts absl::flat_hash_map nlohmann_json::nlohmann_json) From af6a1ff004a86cd9b5b6ef865cf05cc7020f7b26 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Mon, 6 Apr 2026 13:21:04 -0400 Subject: [PATCH 36/72] fix building --- src/dusk/imgui/ImGuiMenuGame.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index 3ecfab2490..6ae32ce1a4 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -37,7 +37,7 @@ namespace dusk { } if (ImGui::MenuItem("Default Window Size")) { - getSettings().video.enableFullscreen = false; + getSettings().video.enableFullscreen.setValue(false); VISetWindowFullscreen(false); VISetWindowSize(FB_WIDTH * 2, FB_HEIGHT * 2); VICenterWindow(); From 4f28c4ed10382ef2e0933aa337df7ec0318ce094 Mon Sep 17 00:00:00 2001 From: Lurs <2795933+Lurs@users.noreply.github.com> Date: Mon, 6 Apr 2026 09:21:26 +0200 Subject: [PATCH 37/72] double heaps to fix Midna's eye (#106) and various other error messages I got. Also updating aurora. --- extern/aurora | 2 +- libs/JSystem/src/J3DGraphLoader/J3DModelLoader.cpp | 2 +- src/d/actor/d_a_alink_swindow.inc | 3 +++ src/d/actor/d_a_player.cpp | 7 +++---- src/d/d_k_wmark.cpp | 4 ++++ src/d/d_kankyo.cpp | 4 ++++ src/f_op/f_op_actor_mng.cpp | 3 +++ 7 files changed, 19 insertions(+), 6 deletions(-) diff --git a/extern/aurora b/extern/aurora index b17da31593..5a23bcbd5e 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit b17da315932b85d7d708eaf3e44914f70045a44e +Subproject commit 5a23bcbd5e758c3a854ebda2c0bd8332b346e1ff diff --git a/libs/JSystem/src/J3DGraphLoader/J3DModelLoader.cpp b/libs/JSystem/src/J3DGraphLoader/J3DModelLoader.cpp index 72a48007c0..3d064e33de 100644 --- a/libs/JSystem/src/J3DGraphLoader/J3DModelLoader.cpp +++ b/libs/JSystem/src/J3DGraphLoader/J3DModelLoader.cpp @@ -242,7 +242,7 @@ void J3DModelLoader::setupBBoardInfo() { J3DMaterial* mesh = mpModelData->getJointNodePointer(i)->getMesh(); if (mesh != NULL) { u32 shape_index = mesh->getShape()->getIndex(); - u16* index_table = JSUConvertOffsetToPtr(mpShapeBlock, + BE(u16)* index_table = JSUConvertOffsetToPtr(mpShapeBlock, (uintptr_t)mpShapeBlock->mpIndexTable); J3DShapeInitData* shape_init_data = JSUConvertOffsetToPtr(mpShapeBlock, diff --git a/src/d/actor/d_a_alink_swindow.inc b/src/d/actor/d_a_alink_swindow.inc index cf3593dfce..81c7a1ca18 100644 --- a/src/d/actor/d_a_alink_swindow.inc +++ b/src/d/actor/d_a_alink_swindow.inc @@ -40,6 +40,9 @@ void daAlink_c::setOriginalHeap(JKRExpHeap** i_ppheap, u32 i_size) { u32 var_r29 = 0x90; u32 var_r28 = 0x10; u32 size = ROUND(i_size, 16); +#if TARGET_PC + size *= 2; +#endif JKRHeap* parent = mDoExt_getGameHeap(); JKRExpHeap* heap = JKRExpHeap::create(size + (var_r29 + var_r28), parent, true); diff --git a/src/d/actor/d_a_player.cpp b/src/d/actor/d_a_player.cpp index f38fe15a3b..43646380b3 100644 --- a/src/d/actor/d_a_player.cpp +++ b/src/d/actor/d_a_player.cpp @@ -237,11 +237,7 @@ void* daPy_anmHeap_c::mallocBuffer() { return mBuffer; } -#if TARGET_PC void daPy_anmHeap_c::createHeap(daPy_anmHeap_c::daAlinkHEAP_TYPE i_heapType, const char* name) { -#else -void daPy_anmHeap_c::createHeap(daPy_anmHeap_c::daAlinkHEAP_TYPE i_heapType, const char* name) { -#endif u32 size; if (i_heapType == 4) { @@ -255,6 +251,9 @@ void daPy_anmHeap_c::createHeap(daPy_anmHeap_c::daAlinkHEAP_TYPE i_heapType, con } else { size = 0xA0; } +#if TARGET_PC + size *= 2; +#endif char* tmpWork; mDoExt_transAnmBas* tmpTransBas; diff --git a/src/d/d_k_wmark.cpp b/src/d/d_k_wmark.cpp index 379b55f532..3894e965c3 100644 --- a/src/d/d_k_wmark.cpp +++ b/src/d/d_k_wmark.cpp @@ -33,7 +33,11 @@ int dkWmark_c::create() { mColorType = this->parameters; } +#if TARGET_PC + mpHeap = mDoExt_createSolidHeapFromGameToCurrent(0x1100, 0x20); +#else mpHeap = mDoExt_createSolidHeapFromGameToCurrent(0x880, 0x20); +#endif if (mpHeap != NULL) { JKRHEAP_NAME(mpHeap, "dkWmark_c::mpHeap"); J3DModelData* modelData = (J3DModelData*)dComIfG_getObjectRes("Alink", 0x23); diff --git a/src/d/d_kankyo.cpp b/src/d/d_kankyo.cpp index 50f9d716fc..9326555777 100644 --- a/src/d/d_kankyo.cpp +++ b/src/d/d_kankyo.cpp @@ -1175,7 +1175,11 @@ static void undwater_init() { J3DModelData* modelData2 = (J3DModelData*)dComIfG_getObjectRes("Always", 0x1D); JUT_ASSERT(1867, modelData2 != NULL); +#if TARGET_PC + g_env_light.undwater_ef_heap = mDoExt_createSolidHeapFromGameToCurrent(0xC00, 0x20); +#else g_env_light.undwater_ef_heap = mDoExt_createSolidHeapFromGameToCurrent(0x600, 0x20); +#endif JKRHEAP_NAME(g_env_light.undwater_ef_heap, "g_env_light.undwater_ef_heap"); if (g_env_light.undwater_ef_heap != NULL) { diff --git a/src/f_op/f_op_actor_mng.cpp b/src/f_op/f_op_actor_mng.cpp index 36217076bf..dca07f98ba 100644 --- a/src/f_op/f_op_actor_mng.cpp +++ b/src/f_op/f_op_actor_mng.cpp @@ -730,6 +730,9 @@ u8 var_r30 = fopAcM::HeapAdjustEntry; #endif u32 size = i_size & 0xFFFFFF; +#if TARGET_PC + size *= 2; +#endif bool result = fopAcM_entrySolidHeap_(i_actor, i_heapCallback, size); #if DEBUG fopAcM::HeapDummyCheck = var_r29; From 83a9df4016f18204e419a22737fb904d7a911bac Mon Sep 17 00:00:00 2001 From: Lurs <2795933+Lurs@users.noreply.github.com> Date: Mon, 6 Apr 2026 21:13:23 +0200 Subject: [PATCH 38/72] Fix "[NEW] JKRHeap (d_a_bg Anms) FULL! Fallback to malloc for size XXX" errors/warnings --- src/d/d_stage.cpp | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/d/d_stage.cpp b/src/d/d_stage.cpp index 057bcdf4ff..f3cdfed17b 100644 --- a/src/d/d_stage.cpp +++ b/src/d/d_stage.cpp @@ -393,13 +393,7 @@ static void dummy1(dStage_roomControl_c* roomControl) { JKRExpHeap* dStage_roomControl_c::createMemoryBlock(int i_blockIdx, u32 i_heapSize) { #if TARGET_PC - // Cave of Ordeals crashes around floor 29 due to no free heap space - // Increasing the size here avoids that, though its ugly. maybe TODO a better fix - if (strcmp(dComIfGp_getStartStageName(), "D_SB01") == 0) { - u32 prev = i_heapSize; - i_heapSize *= 2; - DuskLog.warn("Doubling heap size for D_SB01... ({}) -> ({})", prev, i_heapSize); - } + i_heapSize *= 2; #endif if (mMemoryBlock[i_blockIdx] == NULL) { From 168d8192546d6755978695a29c3c598b3b4f93b0 Mon Sep 17 00:00:00 2001 From: Lurs <2795933+Lurs@users.noreply.github.com> Date: Mon, 6 Apr 2026 22:09:50 +0200 Subject: [PATCH 39/72] Fix "[ERROR] memory free error!!" message while leaving options menu --- src/d/d_menu_window.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/d/d_menu_window.cpp b/src/d/d_menu_window.cpp index 3e173049bd..e9131462c3 100644 --- a/src/d/d_menu_window.cpp +++ b/src/d/d_menu_window.cpp @@ -1507,7 +1507,11 @@ void dMw_c::checkMemSize() { OS_REPORT("memory check ===> diff ==> %d, start ==> %d, now ==> %d\n", diff, mMemSize, now_size); +#if TARGET_PC + if (diff > 0x40) { +#else if (diff > 0x20) { +#endif OSReport_Error("memory free error!!\n"); } mMemSize = 0; From 3d66c127abf477cfd6b742755420e15d305ed693 Mon Sep 17 00:00:00 2001 From: Lurs <2795933+Lurs@users.noreply.github.com> Date: Mon, 6 Apr 2026 23:08:34 +0200 Subject: [PATCH 40/72] Use HEAP_SIZE() --- src/d/d_k_wmark.cpp | 7 ++----- src/d/d_kankyo.cpp | 7 ++----- 2 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/d/d_k_wmark.cpp b/src/d/d_k_wmark.cpp index 3894e965c3..b93ab14211 100644 --- a/src/d/d_k_wmark.cpp +++ b/src/d/d_k_wmark.cpp @@ -6,6 +6,7 @@ #include "d/dolzel.h" // IWYU pragma: keep #include "d/d_k_wmark.h" +#include "dusk/memory.h" #include "JSystem/J3DGraphBase/J3DMaterial.h" #include "SSystem/SComponent/c_math.h" #include "d/actor/d_a_player.h" @@ -33,11 +34,7 @@ int dkWmark_c::create() { mColorType = this->parameters; } -#if TARGET_PC - mpHeap = mDoExt_createSolidHeapFromGameToCurrent(0x1100, 0x20); -#else - mpHeap = mDoExt_createSolidHeapFromGameToCurrent(0x880, 0x20); -#endif + mpHeap = mDoExt_createSolidHeapFromGameToCurrent(HEAP_SIZE(0x880, 0x1100), 0x20); if (mpHeap != NULL) { JKRHEAP_NAME(mpHeap, "dkWmark_c::mpHeap"); J3DModelData* modelData = (J3DModelData*)dComIfG_getObjectRes("Alink", 0x23); diff --git a/src/d/d_kankyo.cpp b/src/d/d_kankyo.cpp index 9326555777..1652f3c2a0 100644 --- a/src/d/d_kankyo.cpp +++ b/src/d/d_kankyo.cpp @@ -1,6 +1,7 @@ #include "d/dolzel.h" // IWYU pragma: keep #include "d/d_kankyo.h" +#include "dusk/memory.h" #ifdef __REVOLUTION_SDK__ #include #else @@ -1175,11 +1176,7 @@ static void undwater_init() { J3DModelData* modelData2 = (J3DModelData*)dComIfG_getObjectRes("Always", 0x1D); JUT_ASSERT(1867, modelData2 != NULL); -#if TARGET_PC - g_env_light.undwater_ef_heap = mDoExt_createSolidHeapFromGameToCurrent(0xC00, 0x20); -#else - g_env_light.undwater_ef_heap = mDoExt_createSolidHeapFromGameToCurrent(0x600, 0x20); -#endif + g_env_light.undwater_ef_heap = mDoExt_createSolidHeapFromGameToCurrent(HEAP_SIZE(0x600, 0xC00), 0x20); JKRHEAP_NAME(g_env_light.undwater_ef_heap, "g_env_light.undwater_ef_heap"); if (g_env_light.undwater_ef_heap != NULL) { From 5c247bcb15011f3130c9c42e4e2a21184a4e9316 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Mon, 6 Apr 2026 23:15:56 +0200 Subject: [PATCH 41/72] Fix cCcS layout being interpreted inconsistently across TUs Fixes #245 Might be the cause of #176 too but I wasn't able to repro that in either case, so can't confirm. --- include/SSystem/SComponent/c_cc_s.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/SSystem/SComponent/c_cc_s.h b/include/SSystem/SComponent/c_cc_s.h index 62815fb3b6..525781279b 100644 --- a/include/SSystem/SComponent/c_cc_s.h +++ b/include/SSystem/SComponent/c_cc_s.h @@ -15,7 +15,7 @@ public: /* 0x0400 */ cCcD_Obj* mpObjTg[0x300]; /* 0x1000 */ cCcD_Obj* mpObjCo[0x100]; /* 0x1400 */ cCcD_Obj* mpObj[0x500]; -#if DEBUG +#if TARGET_PC || DEBUG /* 0x2800 */ u32 m_debug_code; #endif /* 0x2800 */ u16 mObjAtCount; From 185c70bd1004ea37a360084acdc90033704ad967 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Mon, 6 Apr 2026 19:08:10 -0400 Subject: [PATCH 42/72] Accelerate saving, copying & erasing save files --- src/d/d_file_select.cpp | 4 ++++ src/d/d_menu_save.cpp | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/src/d/d_file_select.cpp b/src/d/d_file_select.cpp index c739b39db2..f63403d886 100644 --- a/src/d/d_file_select.cpp +++ b/src/d/d_file_select.cpp @@ -70,7 +70,11 @@ dFs_HIO_c::dFs_HIO_c() { select_icon_appear_frames = 5; appear_display_wait_frames = 15; field_0x000d = 15; + #if TARGET_PC + card_wait_frames = 0; + #else card_wait_frames = 90; + #endif test_frame_counts[0] = 1.11f; test_frame_counts[1] = 1.11f; test_frame_counts[2] = 1.11f; diff --git a/src/d/d_menu_save.cpp b/src/d/d_menu_save.cpp index 7ecc41f823..eb7b6a35b8 100644 --- a/src/d/d_menu_save.cpp +++ b/src/d/d_menu_save.cpp @@ -56,7 +56,11 @@ static dMs_HIO_c g_msHIO; dMs_HIO_c::dMs_HIO_c() { mDisplayWaitFrames = 15; + #if TARGET_PC + mCardWaitFrames = 0; + #else mCardWaitFrames = 90; + #endif mEffectDispFrames = 5; mCharSwitchFrames = 5; mSelectIcon = 5; From 2dbcf13c097b081fc3e144a88d4bcf2c56623216 Mon Sep 17 00:00:00 2001 From: Jeffrey Crowell Date: Mon, 6 Apr 2026 20:33:27 -0400 Subject: [PATCH 43/72] use "Cmd" instead of "Ctrl" for hotkeys on Apple (#239) --- include/dusk/hotkeys.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/include/dusk/hotkeys.h b/include/dusk/hotkeys.h index c40f35925f..6e98d62521 100644 --- a/include/dusk/hotkeys.h +++ b/include/dusk/hotkeys.h @@ -3,7 +3,11 @@ namespace dusk::hotkeys { +#if __APPLE__ +constexpr const char* DO_RESET = "Cmd+R"; +#else constexpr const char* DO_RESET = "Ctrl+R"; +#endif constexpr const char* TOGGLE_FULLSCREEN = "F11"; From 287cd21f715b2ea46dae18a9635bae23169e1dd3 Mon Sep 17 00:00:00 2001 From: CraftyBoss Date: Mon, 6 Apr 2026 17:43:23 -0700 Subject: [PATCH 44/72] update aurora --- extern/aurora | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/extern/aurora b/extern/aurora index 50163edfe7..5a23bcbd5e 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 50163edfe76694f6c920bbd74febf1dd22a35618 +Subproject commit 5a23bcbd5e758c3a854ebda2c0bd8332b346e1ff From e4de461e7aa2fd54c42290b7e945c925e604439b Mon Sep 17 00:00:00 2001 From: CraftyBoss Date: Mon, 6 Apr 2026 18:26:33 -0700 Subject: [PATCH 45/72] fast spinner cheat impl just makes it so holding R while on the spinner increases its speed to 60 units --- include/dusk/settings.h | 1 + src/dusk/imgui/ImGuiMenuEnhancements.cpp | 5 +++++ src/dusk/settings.cpp | 2 ++ src/f_ap/f_ap_game.cpp | 10 ++++++++++ 4 files changed, 18 insertions(+) diff --git a/include/dusk/settings.h b/include/dusk/settings.h index cf4d79f6ac..0cb3ba60b7 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -58,6 +58,7 @@ struct UserSettings { // Cheats ConfigVar enableFastIronBoots; ConfigVar canTransformAnywhere; + ConfigVar fastSpinner; // Technical ConfigVar restoreWiiGlitches; diff --git a/src/dusk/imgui/ImGuiMenuEnhancements.cpp b/src/dusk/imgui/ImGuiMenuEnhancements.cpp index a7a1e1d698..e9404e2476 100644 --- a/src/dusk/imgui/ImGuiMenuEnhancements.cpp +++ b/src/dusk/imgui/ImGuiMenuEnhancements.cpp @@ -101,6 +101,11 @@ namespace dusk { ImGui::SetTooltip("Allows you to transform even if NPCs are looking"); } + config::ImGuiCheckbox("Fast Spinner", getSettings().game.fastSpinner); + if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("Speeds up Spinner movement when holding R."); + } + ImGui::EndMenu(); } diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index 278f783dbf..32c6a5beb4 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -46,6 +46,7 @@ UserSettings g_userSettings = { // Cheats .enableFastIronBoots {"game.enableFastIronBoots", false}, .canTransformAnywhere {"game.canTransformAnywhere", false}, + .fastSpinner {"game.fastSpinner", false}, // Technical .restoreWiiGlitches {"game.restoreWiiGlitches", false}, @@ -93,6 +94,7 @@ void registerSettings() { Register(g_userSettings.game.noLowHpSound); Register(g_userSettings.game.midnasLamentNonStop); Register(g_userSettings.game.enableTurboKeybind); + Register(g_userSettings.game.fastSpinner); } // Transient settings diff --git a/src/f_ap/f_ap_game.cpp b/src/f_ap/f_ap_game.cpp index 1cbbb7449f..b1edb7fa23 100644 --- a/src/f_ap/f_ap_game.cpp +++ b/src/f_ap/f_ap_game.cpp @@ -738,6 +738,16 @@ void fapGm_Execute() { dynamic_cast(link)->handleQuickTransform(); } } + + if (dusk::getSettings().game.fastSpinner && mDoCPd_c::getHoldR(PAD_1)) { + if (const auto link = g_dComIfG_gameInfo.play.getPlayer(0)) { + auto spinnerActor = (fopAc_ac_c*)dynamic_cast(link)->getSpinnerActor(); + if (spinnerActor) { + if (spinnerActor->speedF < 60.f) + spinnerActor->speedF += 2.f; + } + } + } #endif fpcM_Management(NULL, fapGm_After); From 8fac510140f6f58255aeaf1f02d4cee02fb3d147 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Mon, 6 Apr 2026 21:25:50 -0600 Subject: [PATCH 46/72] Update aurora & fixes for OS header changes --- extern/aurora | 2 +- libs/JSystem/src/JUtility/JUTException.cpp | 16 ++++++++++++++++ src/dusk/OSContext.cpp | 9 ++------- src/dusk/OSThread.cpp | 6 +++--- src/dusk/stubs.cpp | 4 ++-- src/m_Do/m_Do_machine.cpp | 2 ++ 6 files changed, 26 insertions(+), 13 deletions(-) diff --git a/extern/aurora b/extern/aurora index 5a23bcbd5e..854ce1c178 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 5a23bcbd5e758c3a854ebda2c0bd8332b346e1ff +Subproject commit 854ce1c178756ca307137c81afc3cc626fce5fb3 diff --git a/libs/JSystem/src/JUtility/JUTException.cpp b/libs/JSystem/src/JUtility/JUTException.cpp index 509acbfb3e..514ec6dd8a 100644 --- a/libs/JSystem/src/JUtility/JUTException.cpp +++ b/libs/JSystem/src/JUtility/JUTException.cpp @@ -101,6 +101,9 @@ JUTException* JUTException::create(JUTDirectPrint* directPrint) { OSMessage JUTException::sMessageBuffer[1] = {0}; void* JUTException::run() { +#ifdef TARGET_PC + return NULL; +#else u32 msr = PPCMfmsr(); msr &= ~0x0900; PPCMtmsr(msr); @@ -132,6 +135,7 @@ void* JUTException::run() { sErrorManager->mDirectPrint->changeFrameBuffer(mFrameMemory); sErrorManager->printContext(error, context, r24, r23); } +#endif } void* JUTException::sConsoleBuffer; @@ -145,6 +149,7 @@ u32 JUTException::msr; u32 JUTException::fpscr; void JUTException::errorHandler(OSError error, OSContext* context, u32 param_3, u32 param_4) { +#ifndef TARGET_PC msr = PPCMfmsr(); fpscr = context->fpscr; OSFillFPUContext(context); @@ -165,6 +170,7 @@ void JUTException::errorHandler(OSError error, OSContext* context, u32 param_3, OSSendMessage(&sMessageQueue, &exCallbackObject, OS_MESSAGE_BLOCK); OSEnableScheduler(); OSYieldThread(); +#endif } void JUTException::panic_f_va(char const* file, int line, char const* format, va_list args) { @@ -234,6 +240,7 @@ void JUTException::showFloatSub(int index, f32 value) { } void JUTException::showFloat(OSContext* context) { +#ifndef TARGET_PC if (!sConsole) { return; } @@ -251,6 +258,7 @@ void JUTException::showFloat(OSContext* context) { sConsole->print(" "); showFloatSub(21, context->fpr[21]); sConsole->print("\n"); +#endif } bool JUTException::searchPartialModule(u32 address, u32* module_id, u32* section_id, @@ -333,6 +341,7 @@ void JUTException::showStack(OSContext* context) { } void JUTException::showMainInfo(u16 error, OSContext* context, u32 dsisr, u32 dar) { +#ifndef TARGET_PC if (!sConsole) { return; } @@ -391,9 +400,11 @@ void JUTException::showMainInfo(u16 error, OSContext* context, u32 dsisr, u32 da } sConsole->print_f("SRR0: %08XH SRR1:%08XH\n", context->srr0, context->srr1); sConsole->print_f("DSISR: %08XH DAR: %08XH\n", dsisr, dar); +#endif } void JUTException::showGPR(OSContext* context) { +#ifndef TARGET_PC if (!sConsole) { return; } @@ -404,6 +415,7 @@ void JUTException::showGPR(OSContext* context) { context->gpr[i + 11], i + 22, context->gpr[i + 22]); } sConsole->print_f("R%02d:%08XH R%02d:%08XH\n", 10, context->gpr[10], 21, context->gpr[21]); +#endif } bool JUTException::showMapInfo_subroutine(u32 address, bool begin_with_newline) { @@ -454,6 +466,7 @@ bool JUTException::showMapInfo_subroutine(u32 address, bool begin_with_newline) } void JUTException::showGPRMap(OSContext* context) { +#ifndef TARGET_PC if (!sConsole) { return; } @@ -480,9 +493,11 @@ void JUTException::showGPRMap(OSContext* context) { if (!found_address_register) { sConsole->print(" no register which seem to address.\n"); } +#endif } void JUTException::showSRR0Map(OSContext* context) { +#ifndef TARGET_PC if (!sConsole) { return; } @@ -497,6 +512,7 @@ void JUTException::showSRR0Map(OSContext* context) { } JUTConsoleManager::getManager()->drawDirect(true); } +#endif } void JUTException::printDebugInfo(JUTException::EInfoPage page, OSError error, OSContext* context, diff --git a/src/dusk/OSContext.cpp b/src/dusk/OSContext.cpp index 9aa6932e52..d2bb1803ea 100644 --- a/src/dusk/OSContext.cpp +++ b/src/dusk/OSContext.cpp @@ -23,16 +23,11 @@ void OSSetCurrentContext(OSContext* context) { } void OSClearContext(OSContext* context) { - if (!context) return; - context->mode = 0; - context->state = 0; + // No-op on PC } void OSInitContext(OSContext* context, u32 pc, u32 newsp) { - if (!context) return; - memset(context, 0, sizeof(OSContext)); - context->srr0 = pc; - context->gpr[1] = newsp; + // No-op on PC } void OSDumpContext(OSContext* context) { diff --git a/src/dusk/OSThread.cpp b/src/dusk/OSThread.cpp index ea9c568eef..af339e8656 100644 --- a/src/dusk/OSThread.cpp +++ b/src/dusk/OSThread.cpp @@ -101,7 +101,7 @@ static thread_local OSThread* tls_currentThread = nullptr; static OSThread sDefaultThread; static u8 sDefaultStack[64 * 1024]; -static u32 sDefaultStackEnd = OS_THREAD_STACK_MAGIC; +static u8 sDefaultStackEnd = OS_THREAD_STACK_MAGIC; // Global interrupt mutex (coarse-grained lock replacing interrupt disable) // Lazy-initialized to avoid DLL static init crashes @@ -237,7 +237,7 @@ int OSCreateThread(OSThread* thread, void* (*func)(void*), void* param, // Stack (stack points to TOP on GameCube) thread->stackBase = (u8*)stack; - thread->stackEnd = (u32*)((uintptr_t)stack - stackSize); + thread->stackEnd = (u8*)((uintptr_t)stack - stackSize); *thread->stackEnd = OS_THREAD_STACK_MAGIC; OSClearContext(&thread->context); @@ -496,7 +496,7 @@ void OSDetachThread(OSThread* thread) { OSWakeupThread(&thread->queueJoin); } -int OSJoinThread(OSThread* thread, void* val) { +BOOL OSJoinThread(OSThread* thread, void** val) { if (!thread) return 0; if (!(thread->attr & OS_THREAD_ATTR_DETACH)) { diff --git a/src/dusk/stubs.cpp b/src/dusk/stubs.cpp index 2cb385966e..e655ed6d7d 100644 --- a/src/dusk/stubs.cpp +++ b/src/dusk/stubs.cpp @@ -94,7 +94,7 @@ static void ClearMsgQueueMap() { map.clear(); } -void OSInitMessageQueue(OSMessageQueue* mq, void* msgArray, s32 msgCount) { +void OSInitMessageQueue(OSMessageQueue* mq, OSMessage* msgArray, s32 msgCount) { if (!mq) return; mq->queueSend.head = mq->queueSend.tail = nullptr; mq->queueReceive.head = mq->queueReceive.tail = nullptr; @@ -128,7 +128,7 @@ int OSSendMessage(OSMessageQueue* mq, void* msg, s32 flags) { return 1; } -int OSReceiveMessage(OSMessageQueue* mq, void* msg, s32 flags) { +BOOL OSReceiveMessage(OSMessageQueue* mq, OSMessage* msg, s32 flags) { if (!mq) return 0; PCMessageQueueData& data = GetMsgQueueData(mq); diff --git a/src/m_Do/m_Do_machine.cpp b/src/m_Do/m_Do_machine.cpp index d5258b6f98..fdab588957 100644 --- a/src/m_Do/m_Do_machine.cpp +++ b/src/m_Do/m_Do_machine.cpp @@ -592,6 +592,7 @@ void myExceptionCallback(u16, OSContext*, u32, u32) { VIFlush(); } +#ifndef TARGET_PC static void fault_callback_scroll(u16, OSContext* p_context, u32, u32) { JUTException* manager = JUTException::getManager(); JUTConsole* exConsole = manager->getConsole(); @@ -714,6 +715,7 @@ static void fault_callback_scroll(u16, OSContext* p_context, u32, u32) { } while (true); } while (true); } +#endif static void dummy_string() { DEAD_STRING("\x1B[32m%-24s = size=%d KB\n\x1B[m"); From 4e12f7bb9537bdcc635adc46aa1c23d4f84004f1 Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 6 Apr 2026 20:35:54 -0700 Subject: [PATCH 47/72] fix basically all known audio bugs fixes #148 fixes #146 fixes #130 --- libs/JSystem/src/JAudio2/JASSeqParser.cpp | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/libs/JSystem/src/JAudio2/JASSeqParser.cpp b/libs/JSystem/src/JAudio2/JASSeqParser.cpp index 7b417f2c82..376ec22b4c 100644 --- a/libs/JSystem/src/JAudio2/JASSeqParser.cpp +++ b/libs/JSystem/src/JAudio2/JASSeqParser.cpp @@ -884,6 +884,19 @@ s32 JASSeqParser::cmdPrintf(JASTrack* param_0, u32* param_1) { s32 JASSeqParser::execNoteOnGate(JASTrack* param_0, u32 param_1, u32 param_2, u32 param_3, u32 param_4) { JASSeqCtrl* seqCtrl = param_0->getSeqCtrl(); + + int r31 = 0; + +#if TARGET_PC + // CodeWarrior on PPC allocates MSB-first for bit fields i think, which is stupid + // so in reality these are stored in bit 6 and 7 not but 0 and 1, do this to get around it + if (param_4 & 0x40) { + r31 |= 2; + } + if (param_4 & 0x80) { + r31 |= 1; + } +#else // likely fake match, this may use some actual union defined somewhere else union { u8 val; @@ -893,13 +906,13 @@ s32 JASSeqParser::execNoteOnGate(JASTrack* param_0, u32 param_1, u32 param_2, u3 } bits; } tmp; tmp.val = param_4; - int r31 = 0; if (tmp.bits.bit1) { r31 |= 2; } if (tmp.bits.bit0) { r31 |= 1; } +#endif if (param_3 == 0) { r31 |= 4; } From 9a158720441d569c96fbf78330d6e2c842eb939b Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 6 Apr 2026 07:53:46 -0700 Subject: [PATCH 48/72] runtime data asset loader --- files.cmake | 2 + include/dusk/dvd_asset.hpp | 22 ++++++++ src/d/actor/d_a_mant.cpp | 22 ++++++++ src/d/actor/d_a_player.cpp | 6 +++ src/d/actor/d_flower.inc | 35 ++++++++++++ src/d/actor/d_grass.inc | 29 ++++++++-- src/d/d_error_msg.cpp | 17 ++++++ src/dusk/dvd_asset.cpp | 106 +++++++++++++++++++++++++++++++++++++ src/m_Do/m_Do_ext.cpp | 3 ++ 9 files changed, 239 insertions(+), 3 deletions(-) create mode 100644 include/dusk/dvd_asset.hpp create mode 100644 src/dusk/dvd_asset.cpp diff --git a/files.cmake b/files.cmake index 7d07408613..e9149a1777 100644 --- a/files.cmake +++ b/files.cmake @@ -1333,6 +1333,8 @@ set(DOLPHIN_FILES set(DUSK_FILES include/dusk/endian_gx.hpp include/dusk/config.hpp + include/dusk/dvd_asset.hpp + src/dusk/dvd_asset.cpp src/d/actor/d_a_alink_dusk.cpp src/dusk/asserts.cpp src/dusk/config.cpp diff --git a/include/dusk/dvd_asset.hpp b/include/dusk/dvd_asset.hpp new file mode 100644 index 0000000000..3c36b75195 --- /dev/null +++ b/include/dusk/dvd_asset.hpp @@ -0,0 +1,22 @@ +#pragma once + +#include "dolphin/types.h" + +namespace dusk { + +/** + * Load bytes from the main DOL by GameCube virtual address + */ +bool LoadDolAsset(void* dst, u32 virtualAddress, s32 size); + +/** + * Load bytes from a REL file in the ISO filesystem + */ +void* LoadRelAsset(const char* dvdPath, s32 offset, s32 size); + +/** + * Load bytes from a REL inside RELS.arc + */ +bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, s32 offset, s32 size); + +} // namespace dusk diff --git a/src/d/actor/d_a_mant.cpp b/src/d/actor/d_a_mant.cpp index a3b48f1098..1760db60fa 100644 --- a/src/d/actor/d_a_mant.cpp +++ b/src/d/actor/d_a_mant.cpp @@ -10,11 +10,21 @@ #include "d/actor/d_a_b_gnd.h" #include "d/d_com_inf_game.h" +#if TARGET_PC +#include "dusk/dvd_asset.hpp" +static u8* l_Egnd_mantTEX_get() { static u8* p = (u8*)dusk::LoadRelAsset("/rel/Final/Release/d_a_mant.rel", 0x1C00, 0x4000); return p; } +static u8* l_Egnd_mantTEX_U_get() { static u8* p = (u8*)dusk::LoadRelAsset("/rel/Final/Release/d_a_mant.rel", 0x5C00, 0x4000); return p; } +static u8* l_Egnd_mantPAL_get() { static u8* p = (u8*)dusk::LoadRelAsset("/rel/Final/Release/d_a_mant.rel", 0x9C00, 0x60); return p; } +#define l_Egnd_mantTEX (l_Egnd_mantTEX_get()) +#define l_Egnd_mantTEX_U (l_Egnd_mantTEX_U_get()) +#define l_Egnd_mantPAL (l_Egnd_mantPAL_get()) +#else #include "assets/l_Egnd_mantTEX.h" #include "assets/l_Egnd_mantTEX_U.h" #include "assets/l_Egnd_mantPAL.h" +#endif #include "d/d_s_play.h" static u32 l_pos[507] = { @@ -239,20 +249,32 @@ static u32 l_texCoord[338] = { 0x3F800000, 0x00000000, }; +#if TARGET_PC +static u8* l_Egnd_mantDL_get() { static u8* p = (u8*)dusk::LoadRelAsset("/rel/Final/Release/d_a_mant.rel", 0xA9A0, 0x3EC); return p; } +#define l_Egnd_mantDL (l_Egnd_mantDL_get()) +#else #include "assets/l_Egnd_mantDL.h" +#endif +#if !TARGET_PC static void* pal_d = (void*)&l_Egnd_mantPAL; static void* tex_d[2] = { (void*)&l_Egnd_mantTEX, (void*)&l_Egnd_mantTEX_U, }; +#endif static char lbl_277_bss_0; void daMant_packet_c::draw() { +#if TARGET_PC + void* image = l_Egnd_mantTEX; + void* lut = l_Egnd_mantPAL; +#else void* image = tex_d[0]; void* lut = pal_d; +#endif j3dSys.reinitGX(); GXSetNumIndStages(0); diff --git a/src/d/actor/d_a_player.cpp b/src/d/actor/d_a_player.cpp index 43646380b3..d6f7c54a49 100644 --- a/src/d/actor/d_a_player.cpp +++ b/src/d/actor/d_a_player.cpp @@ -367,7 +367,13 @@ JKRHeap* daPy_anmHeap_c::setAnimeHeap() { } #if !PLATFORM_WII +#if TARGET_PC +#include "dusk/dvd_asset.hpp" +static const u8* l_sightDL_get() { static u8 buf[0x89]; static bool _ = (dusk::LoadDolAsset(buf, 0x803BA0C0, 0x89), true); return buf; } +#define l_sightDL (l_sightDL_get()) +#else #include "assets/l_sightDL__d_a_player.h" +#endif void daPy_sightPacket_c::draw() { TGXTexObj texObj; diff --git a/src/d/actor/d_flower.inc b/src/d/actor/d_flower.inc index 762b1e02e9..93a7e35097 100644 --- a/src/d/actor/d_flower.inc +++ b/src/d/actor/d_flower.inc @@ -13,7 +13,13 @@ const u16 l_J_Ohana00_64TEX__width = 63; const u16 l_J_Ohana00_64TEX__height = 63; #endif +#if TARGET_PC +#include "dusk/dvd_asset.hpp" +static u8* l_J_Ohana00_64TEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x9060, 0x800), true); return buf; } +#define l_J_Ohana00_64TEX (l_J_Ohana00_64TEX_get()) +#else #include "assets/l_J_Ohana00_64TEX.h" +#endif static u8 l_flowerPos[708] = { 0xC0, 0x8C, 0x2C, 0xF7, 0x42, 0x05, 0xBC, 0xDF, 0xC1, 0xA1, 0x00, 0x70, 0xBF, 0x50, 0x51, 0xB9, @@ -104,6 +110,16 @@ static u8 l_flowerTexCoord[] = { 0x3E, 0xA7, 0x67, 0x4D, 0x3C, 0x14, 0x46, 0x74, 0x3E, 0xA7, 0x73, 0xE2, 0xBC, 0x2F, 0x46, 0xAA, 0x3E, 0xA7, 0x72, 0xD6, 0xBD, 0x2F, 0x46, 0xAA}; +#if TARGET_PC +static u8* l_J_hana00DL_get() { static u8 buf[0x150]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x9D20, 0x150), true); return buf; } +static u8* l_J_hana00_cDL_get() { static u8 buf[0xDE]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x9E80, 0xDE), true); return buf; } +static u8* l_matDL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x9F60, 0x99), true); return buf; } +static u8* l_matLight4DL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xA000, 0x99), true); return buf; } +#define l_J_hana00DL (l_J_hana00DL_get()) +#define l_J_hana00_cDL (l_J_hana00_cDL_get()) +#define l_matDL (l_matDL_get()) +#define l_matLight4DL (l_matLight4DL_get()) +#else #include "assets/l_J_hana00DL.h" #include "assets/l_J_hana00_cDL.h" @@ -113,6 +129,7 @@ l_matDL__d_a_grass(l_J_Ohana00_64TEX) #include "assets/l_matLight4DL.h" l_matLight4DL(l_J_Ohana00_64TEX) +#endif #if TARGET_PC const u16 l_J_Ohana01_64128_0419TEX__width = 64; @@ -122,7 +139,12 @@ const u16 l_J_Ohana01_64128_0419TEX__width = 63; const u16 l_J_Ohana01_64128_0419TEX__height = 127; #endif +#if TARGET_PC +static u8* l_J_Ohana01_64128_0419TEX_get() { static u8 buf[0x1000]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xA0A0, 0x1000), true); return buf; } +#define l_J_Ohana01_64128_0419TEX (l_J_Ohana01_64128_0419TEX_get()) +#else #include "assets/l_J_Ohana01_64128_0419TEX.h" +#endif static u8 l_flowerPos2[1224] = { 0x40, 0x25, 0x9F, 0x34, 0x42, 0xC2, 0x95, 0x72, 0xC1, 0x22, 0x34, 0x78, 0x41, 0x4D, 0xF9, 0x63, @@ -249,6 +271,18 @@ static u8 l_flowerTexCoord2[] = { 0x40, 0x1B, 0x7D, 0x52, 0x3F, 0x97, 0xF6, 0xBA, 0x40, 0x04, 0x26, 0x74, 0x3F, 0x80, 0x3F, 0x79, 0x40, 0x1B, 0x7D, 0x52, 0x3F, 0x80, 0x3F, 0x79, 0x40, 0x1B, 0x7D, 0x52, 0x3F, 0x51, 0x10, 0x6F}; +#if TARGET_PC +static u8* l_J_hana01DL_get() { static u8 buf[0x138]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xB7C0, 0x138), true); return buf; } +static u8* l_J_hana01_c_00DL_get() { static u8 buf[0xDE]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xB900, 0xDE), true); return buf; } +static u8* l_J_hana01_c_01DL_get() { static u8 buf[0x128]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xB9E0, 0x128), true); return buf; } +static u8* l_mat2DL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xBB20, 0x99), true); return buf; } +static u8* l_mat2Light4DL_get() { static u8 buf[0x99]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0xBBC0, 0x99), true); return buf; } +#define l_J_hana01DL (l_J_hana01DL_get()) +#define l_J_hana01_c_00DL (l_J_hana01_c_00DL_get()) +#define l_J_hana01_c_01DL (l_J_hana01_c_01DL_get()) +#define l_mat2DL (l_mat2DL_get()) +#define l_mat2Light4DL (l_mat2Light4DL_get()) +#else #include "assets/l_J_hana01DL.h" #include "assets/l_J_hana01_c_00DL.h" @@ -260,6 +294,7 @@ l_mat2DL__d_a_grass(l_J_Ohana01_64128_0419TEX) #include "assets/l_mat2Light4DL.h" l_mat2Light4DL(l_J_Ohana01_64128_0419TEX) +#endif void dFlower_data_c::WorkCo(fopAc_ac_c* i_hitActor, u32 i_massFlg, int i_roomNo) { cXyz sp8; diff --git a/src/d/actor/d_grass.inc b/src/d/actor/d_grass.inc index 6351cc75fc..3645488b0f 100644 --- a/src/d/actor/d_grass.inc +++ b/src/d/actor/d_grass.inc @@ -13,11 +13,19 @@ const u16 l_M_Hijiki00TEX__width = 31; const u16 l_M_Hijiki00TEX__height = 31; -#include "assets/l_M_kusa05_RGBATEX.h" // ALIGN 32 - const u16 l_M_kusa05_RGBATEX__width = 31; const u16 l_M_kusa05_RGBATEX__height = 31; -#include "assets/l_M_Hijiki00TEX.h" // ALIGN 32 + +#if TARGET_PC +#include "dusk/dvd_asset.hpp" +static u8* l_M_kusa05_RGBATEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x7680, 0x800), true); return buf; } +static u8* l_M_Hijiki00TEX_get() { static u8 buf[0x800]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x7E80, 0x800), true); return buf; } +#define l_M_kusa05_RGBATEX (l_M_kusa05_RGBATEX_get()) +#define l_M_Hijiki00TEX (l_M_Hijiki00TEX_get()) +#else +#include "assets/l_M_kusa05_RGBATEX.h" // ALIGN 32 +#include "assets/l_M_Hijiki00TEX.h" // ALIGN 32 +#endif static u8 l_pos[960] = { 0x3F, 0x4A, 0x56, 0xEF, 0xC2, 0x20, 0x00, 0x00, 0x41, 0xFB, 0x17, 0xE4, 0x41, 0xAA, 0xBB, 0xEA, @@ -102,6 +110,20 @@ static u8 l_texCoord[160] = { 0x3F, 0x94, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, 0xBD, 0xC0, 0x00, 0x00, 0x3F, 0x80, 0x00, 0x00, }; +#if TARGET_PC +static u8* l_M_Kusa_9qDL_get() { static u8 buf[0xCB]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8B00, 0xCB), true); return buf; } +static u8* l_M_Kusa_9q_cDL_get() { static u8 buf[0xCB]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8BE0, 0xCB), true); return buf; } +static u8* l_M_TenGusaDL_get() { static u8 buf[0xD4]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8CC0, 0xD4), true); return buf; } +static u8* l_Tengusa_matDL_get() { static u8 buf[0xA8]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8DA0, 0xA8), true); return buf; } +static u8* l_kusa9q_matDL_get() { static u8 buf[0xA8]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8E60, 0xA8), true); return buf; } +static u8* l_kusa9q_l4_matDL_get() { static u8 buf[0xA8]; static bool _ = (dusk::LoadArchivedRelAsset(buf, 'AMEM', "d_a_grass.rel", 0x8F20, 0xA8), true); return buf; } +#define l_M_Kusa_9qDL (l_M_Kusa_9qDL_get()) +#define l_M_Kusa_9q_cDL (l_M_Kusa_9q_cDL_get()) +#define l_M_TenGusaDL (l_M_TenGusaDL_get()) +#define l_Tengusa_matDL (l_Tengusa_matDL_get()) +#define l_kusa9q_matDL (l_kusa9q_matDL_get()) +#define l_kusa9q_l4_matDL (l_kusa9q_l4_matDL_get()) +#else #include "assets/l_M_Kusa_9qDL.h" #include "assets/l_M_Kusa_9q_cDL.h" @@ -117,6 +139,7 @@ l_kusa9q_matDL(l_M_kusa05_RGBATEX) #include "assets/l_kusa9q_l4_matDL.h" l_kusa9q_l4_matDL(l_M_kusa05_RGBATEX) +#endif void dGrass_data_c::WorkCo(fopAc_ac_c* i_hitActor, u32 i_massFlg, int i_roomNo) { cXyz sp18; diff --git a/src/d/d_error_msg.cpp b/src/d/d_error_msg.cpp index faa40ae543..f1d63b5a1f 100644 --- a/src/d/d_error_msg.cpp +++ b/src/d/d_error_msg.cpp @@ -15,6 +15,22 @@ #include "m_Do/m_Do_Reset.h" #include "m_Do/m_Do_graphic.h" +#if TARGET_PC +#include "dusk/dvd_asset.hpp" +static const u8* black_tex_get() { static u8 buf[0x40]; static bool _ = (dusk::LoadDolAsset(buf, 0x8037B140, 0x40), true); return buf; } +static const u8* msg_data_get() { static u8 buf[0x260]; static bool _ = (dusk::LoadDolAsset(buf, 0x8037B180, 0x260), true); return buf; } +static const u8* font_data_get() { static u8 buf[0x12260]; static bool _ = (dusk::LoadDolAsset(buf, 0x8037B3E0, 0x12260), true); return buf; } +#define black_tex (black_tex_get()) +#define msg_data (msg_data_get()) +#define font_data (font_data_get()) +#if VERSION == VERSION_GCN_PAL +// TODO: find addreses for pal languages +#define msg_data_ge ((const u8*)nullptr) +#define msg_data_fr ((const u8*)nullptr) +#define msg_data_sp ((const u8*)nullptr) +#define msg_data_it ((const u8*)nullptr) +#endif +#else #include "assets/black_tex.h" #include "assets/msg_data.h" #if VERSION == VERSION_GCN_PAL @@ -24,6 +40,7 @@ #include "assets/msg_data_it.h" #endif #include "assets/font_data.h" +#endif #define MSG_READING_DISC 0 #define MSG_COVER_OPEN 1 diff --git a/src/dusk/dvd_asset.cpp b/src/dusk/dvd_asset.cpp new file mode 100644 index 0000000000..bfa30cc941 --- /dev/null +++ b/src/dusk/dvd_asset.cpp @@ -0,0 +1,106 @@ +#include "dusk/dvd_asset.hpp" +#include "dusk/logging.h" +#include "dusk/endian.h" +#include "aurora/dvd.h" +#include "DynamicLink.h" +#include "JSystem/JKernel/JKRArchive.h" +#include "JSystem/JKernel/JKRDvdRipper.h" + +#include + +namespace dusk { + +static const u8* s_dolData = nullptr; // pointer to dol data +static size_t s_dolSize = 0; +struct DolSection { u32 fileOffset, vaddr, size; }; +static DolSection s_dolSections[18]; // 7 text + 11 data +static int s_dolSectionCount = 0; + +static bool EnsureDolParsed() { + if (s_dolData) return true; + + s32 sz = 0; + const u8* p = aurora_dvd_get_dol(sz); + if (!p || sz < 256) { + DuskLog.fatal("dvd_asset: aurora_dvd_get_dol failed (size={})", sz); return false; + } + + s_dolData = p; + s_dolSize = sz; + + const BE(u32)* hdr = (const BE(u32)*)s_dolData; + s_dolSectionCount = 0; + + // 0x00: text file offsets 0x12: text vaddrs 0x24: text sizes + for (int i = 0; i < 7; i++) { + u32 off = hdr[0x00+i], addr = hdr[0x12+i], sz = hdr[0x24+i]; + if (sz > 0 && off > 0) { + s_dolSections[s_dolSectionCount++] = {off, addr, sz}; + } + } + // 0x07: data file offsets 0x19: data vaddrs 0x2B: data sizes + for (int i = 0; i < 11; i++) { + u32 off = hdr[0x07+i], addr = hdr[0x19+i], sz = hdr[0x2B+i]; + if (sz > 0 && off > 0) { + s_dolSections[s_dolSectionCount++] = {off, addr, sz}; + } + } + + return true; +} + +static s32 DolVaToFileOffset(u32 va) { + if (!EnsureDolParsed()) return -1; + for (int i = 0; i < s_dolSectionCount; i++) { + const auto& sec = s_dolSections[i]; + if (va >= sec.vaddr && va < sec.vaddr + sec.size) { + return static_cast(sec.fileOffset + (va - sec.vaddr)); + } + } + DuskLog.fatal("dvd_asset: VA 0x{:08X} not found in any DOL section", va); + return -1; +} + +bool LoadDolAsset(void* dst, u32 virtualAddress, s32 size) { + s32 fileOffset = DolVaToFileOffset(virtualAddress); + if (fileOffset < 0) { + return false; + } + + if (size <= 0 || (size_t)(fileOffset + size) > s_dolSize) { + DuskLog.fatal("dvd_asset: DOL read out of range (offset={:#x} size={:#x} dolSize={})", fileOffset, size, s_dolSize); + return false; + } + + std::memcpy(dst, s_dolData + fileOffset, size); + return true; +} + +void* LoadRelAsset(const char* dvdPath, s32 offset, s32 size) { + void* p = JKRDvdRipper::loadToMainRAM(dvdPath, nullptr, EXPAND_SWITCH_UNKNOWN1, (u32)size, nullptr, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, (u32)offset, nullptr, nullptr); + if (!p) DuskLog.fatal("dvd_asset: failed to load {} (offset={:#x} size={:#x})", dvdPath, offset, size); + return p; +} + +bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, s32 offset, s32 size) { + // On TARGET_PC, cDyl_InitCallback skips DynamicModuleControl::initialize() due to static linking + // Mount RELS.arc on first use so sArchive is available + static bool s_mountAttempted = false; + if (!DynamicModuleControl::sArchive && !s_mountAttempted) { + s_mountAttempted = true; DynamicModuleControl::initialize(); + } + + if (!DynamicModuleControl::sArchive) { + DuskLog.fatal("dvd_asset: RELS archive not mounted"); return false; + } + + const u8* rel = static_cast(DynamicModuleControl::sArchive->getResource(memType, relFileName)); + if (!rel) { + DuskLog.fatal("dvd_asset: {} not found in RELS archive", relFileName); return false; + } + + std::memcpy(dst, rel + offset, size); + return true; +} + +} // namespace dusk diff --git a/src/m_Do/m_Do_ext.cpp b/src/m_Do/m_Do_ext.cpp index d744d048ba..0593815b1d 100644 --- a/src/m_Do/m_Do_ext.cpp +++ b/src/m_Do/m_Do_ext.cpp @@ -2873,7 +2873,10 @@ void mDoExt_3DlineMat1_c::update(int param_0, f32 param_1, GXColor& param_2, u16 sp_38++; } } + +#if !TARGET_PC #include "assets/l_mat2DL__d_a_grass.h" +#endif void mDoExt_3DlineMat2_c::setMaterial() { j3dSys.reinitGX(); From 28cb1be2f5205849a7bf15243122dbda03e67a5f Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 6 Apr 2026 07:55:10 -0700 Subject: [PATCH 49/72] remove includes --- CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a9d283dfa..e50a0b8cbb 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,7 +100,6 @@ set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0 set(GAME_INCLUDE_DIRS include src - assets/${DUSK_TP_VERSION} libs/JSystem/include libs extern/aurora/include/dolphin From c7caf8a5ad76e2ea0453b8b82a7b36af25489e73 Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 6 Apr 2026 07:57:00 -0700 Subject: [PATCH 50/72] walk that one on back --- CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index e50a0b8cbb..3a9d283dfa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -100,6 +100,7 @@ set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0 set(GAME_INCLUDE_DIRS include src + assets/${DUSK_TP_VERSION} libs/JSystem/include libs extern/aurora/include/dolphin From 4f1d0f19e05eccb824fd315114dadcdf67fb8ec9 Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 6 Apr 2026 08:49:24 -0700 Subject: [PATCH 51/72] address review --- include/dusk/dvd_asset.hpp | 4 ++-- src/d/actor/d_a_mant.cpp | 8 ++++---- src/d/actor/d_flower.inc | 10 +++++----- src/dusk/dvd_asset.cpp | 39 ++++++++++++++++++++++++++++---------- 4 files changed, 40 insertions(+), 21 deletions(-) diff --git a/include/dusk/dvd_asset.hpp b/include/dusk/dvd_asset.hpp index 3c36b75195..014c683d44 100644 --- a/include/dusk/dvd_asset.hpp +++ b/include/dusk/dvd_asset.hpp @@ -10,9 +10,9 @@ namespace dusk { bool LoadDolAsset(void* dst, u32 virtualAddress, s32 size); /** - * Load bytes from a REL file in the ISO filesystem + * Load bytes from a REL file in the ISO filesystem, dst must be 32-byte aligned */ -void* LoadRelAsset(const char* dvdPath, s32 offset, s32 size); +bool LoadRelAsset(void* dst, const char* dvdPath, s32 offset, s32 size); /** * Load bytes from a REL inside RELS.arc diff --git a/src/d/actor/d_a_mant.cpp b/src/d/actor/d_a_mant.cpp index 1760db60fa..bcd7f05986 100644 --- a/src/d/actor/d_a_mant.cpp +++ b/src/d/actor/d_a_mant.cpp @@ -12,9 +12,9 @@ #if TARGET_PC #include "dusk/dvd_asset.hpp" -static u8* l_Egnd_mantTEX_get() { static u8* p = (u8*)dusk::LoadRelAsset("/rel/Final/Release/d_a_mant.rel", 0x1C00, 0x4000); return p; } -static u8* l_Egnd_mantTEX_U_get() { static u8* p = (u8*)dusk::LoadRelAsset("/rel/Final/Release/d_a_mant.rel", 0x5C00, 0x4000); return p; } -static u8* l_Egnd_mantPAL_get() { static u8* p = (u8*)dusk::LoadRelAsset("/rel/Final/Release/d_a_mant.rel", 0x9C00, 0x60); return p; } +static u8* l_Egnd_mantTEX_get() { alignas(32) static u8 buf[0x4000]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", 0x1C00, 0x4000), true); return buf; } +static u8* l_Egnd_mantTEX_U_get() { alignas(32) static u8 buf[0x4000]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", 0x5C00, 0x4000), true); return buf; } +static u8* l_Egnd_mantPAL_get() { alignas(32) static u8 buf[0x60]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", 0x9C00, 0x60), true); return buf; } #define l_Egnd_mantTEX (l_Egnd_mantTEX_get()) #define l_Egnd_mantTEX_U (l_Egnd_mantTEX_U_get()) #define l_Egnd_mantPAL (l_Egnd_mantPAL_get()) @@ -250,7 +250,7 @@ static u32 l_texCoord[338] = { }; #if TARGET_PC -static u8* l_Egnd_mantDL_get() { static u8* p = (u8*)dusk::LoadRelAsset("/rel/Final/Release/d_a_mant.rel", 0xA9A0, 0x3EC); return p; } +static u8* l_Egnd_mantDL_get() { alignas(32) static u8 buf[0x3EC]; static bool _ = (dusk::LoadRelAsset(buf, "/rel/Final/Release/d_a_mant.rel", 0xA9A0, 0x3EC), true); return buf; } #define l_Egnd_mantDL (l_Egnd_mantDL_get()) #else #include "assets/l_Egnd_mantDL.h" diff --git a/src/d/actor/d_flower.inc b/src/d/actor/d_flower.inc index 93a7e35097..de6ac7c1dc 100644 --- a/src/d/actor/d_flower.inc +++ b/src/d/actor/d_flower.inc @@ -619,9 +619,9 @@ void dFlower_packet_c::draw() { } if (sp4C <= 2) { - GXCallDisplayList(&l_matLight4DL, 0x80); + GXCallDisplayList(l_matLight4DL, 0x80); } else { - GXCallDisplayList(&l_matDL, 0x80); + GXCallDisplayList(l_matDL, 0x80); } GXSetTevColorS10(GX_TEVREG0, sp80); @@ -677,9 +677,9 @@ void dFlower_packet_c::draw() { #endif if (!cLib_checkBit(sp44->m_state, 8)) { - GXCallDisplayList(&l_J_hana00DL, 0x140); + GXCallDisplayList(l_J_hana00DL, 0x140); } else { - GXCallDisplayList(&l_J_hana00_cDL, 0xC0); + GXCallDisplayList(l_J_hana00_cDL, 0xC0); } } } @@ -826,7 +826,7 @@ void dFlower_packet_c::draw() { if (!cLib_checkBit(sp34->m_state, 0x10)) { GXCallDisplayList(mp_Jhana01DL, m_Jhana01DL_size); } else { - GXCallDisplayList(&l_J_hana01_c_00DL, 0xC0); + GXCallDisplayList(l_J_hana01_c_00DL, 0xC0); } } else { GXCallDisplayList(mp_Jhana01_cDL, m_Jhana01_cDL_size); diff --git a/src/dusk/dvd_asset.cpp b/src/dusk/dvd_asset.cpp index bfa30cc941..9bcea14077 100644 --- a/src/dusk/dvd_asset.cpp +++ b/src/dusk/dvd_asset.cpp @@ -12,7 +12,22 @@ namespace dusk { static const u8* s_dolData = nullptr; // pointer to dol data static size_t s_dolSize = 0; -struct DolSection { u32 fileOffset, vaddr, size; }; + +struct DolHeader { + BE(u32) textOffset[7]; + BE(u32) dataOffset[11]; + BE(u32) textAddr[7]; + BE(u32) dataAddr[11]; + BE(u32) textSize[7]; + BE(u32) dataSize[11]; +}; + +struct DolSection { + u32 fileOffset; + u32 vaddr; + u32 size; +}; + static DolSection s_dolSections[18]; // 7 text + 11 data static int s_dolSectionCount = 0; @@ -22,25 +37,29 @@ static bool EnsureDolParsed() { s32 sz = 0; const u8* p = aurora_dvd_get_dol(sz); if (!p || sz < 256) { - DuskLog.fatal("dvd_asset: aurora_dvd_get_dol failed (size={})", sz); return false; + DuskLog.fatal("dvd_asset: aurora_dvd_get_dol failed (size={})", sz); + return false; } s_dolData = p; s_dolSize = sz; - const BE(u32)* hdr = (const BE(u32)*)s_dolData; + const auto* hdr = (const DolHeader*)s_dolData; s_dolSectionCount = 0; - // 0x00: text file offsets 0x12: text vaddrs 0x24: text sizes for (int i = 0; i < 7; i++) { - u32 off = hdr[0x00+i], addr = hdr[0x12+i], sz = hdr[0x24+i]; + u32 off = hdr->textOffset[i]; + u32 addr = hdr->textAddr[i]; + u32 sz = hdr->textSize[i]; if (sz > 0 && off > 0) { s_dolSections[s_dolSectionCount++] = {off, addr, sz}; } } - // 0x07: data file offsets 0x19: data vaddrs 0x2B: data sizes + for (int i = 0; i < 11; i++) { - u32 off = hdr[0x07+i], addr = hdr[0x19+i], sz = hdr[0x2B+i]; + u32 off = hdr->dataOffset[i]; + u32 addr = hdr->dataAddr[i]; + u32 sz = hdr->dataSize[i]; if (sz > 0 && off > 0) { s_dolSections[s_dolSectionCount++] = {off, addr, sz}; } @@ -76,10 +95,10 @@ bool LoadDolAsset(void* dst, u32 virtualAddress, s32 size) { return true; } -void* LoadRelAsset(const char* dvdPath, s32 offset, s32 size) { - void* p = JKRDvdRipper::loadToMainRAM(dvdPath, nullptr, EXPAND_SWITCH_UNKNOWN1, (u32)size, nullptr, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, (u32)offset, nullptr, nullptr); +bool LoadRelAsset(void* dst, const char* dvdPath, s32 offset, s32 size) { + void* p = JKRDvdRipper::loadToMainRAM(dvdPath, (u8*)dst, EXPAND_SWITCH_UNKNOWN1, (u32)size, nullptr, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, (u32)offset, nullptr, nullptr); if (!p) DuskLog.fatal("dvd_asset: failed to load {} (offset={:#x} size={:#x})", dvdPath, offset, size); - return p; + return p != nullptr; } bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, s32 offset, s32 size) { From 530aa48a8f0fb1ab0d721a03d1b3074adfb6269f Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 6 Apr 2026 08:58:52 -0700 Subject: [PATCH 52/72] update include directories --- CMakeLists.txt | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 3a9d283dfa..164d5aa893 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -104,9 +104,7 @@ set(GAME_INCLUDE_DIRS libs/JSystem/include libs extern/aurora/include/dolphin - extern - ${CMAKE_SOURCE_DIR}/build/${DUSK_TP_VERSION}/include - build/${DUSK_TP_VERSION}/include) + extern) set(GAME_LIBS aurora::core aurora::gx aurora::gd aurora::si aurora::vi aurora::pad aurora::mtx aurora::os aurora::dvd aurora::card freeverb cxxopts::cxxopts absl::flat_hash_map nlohmann_json::nlohmann_json) From 6a537ab90d13b3f81c1f380415af383716a9de14 Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 6 Apr 2026 20:52:38 -0700 Subject: [PATCH 53/72] use the new thing in aurora --- src/dusk/dvd_asset.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dusk/dvd_asset.cpp b/src/dusk/dvd_asset.cpp index 9bcea14077..3aa25be94b 100644 --- a/src/dusk/dvd_asset.cpp +++ b/src/dusk/dvd_asset.cpp @@ -1,7 +1,7 @@ #include "dusk/dvd_asset.hpp" #include "dusk/logging.h" #include "dusk/endian.h" -#include "aurora/dvd.h" +#include "dolphin/dvd.h" #include "DynamicLink.h" #include "JSystem/JKernel/JKRArchive.h" #include "JSystem/JKernel/JKRDvdRipper.h" @@ -35,9 +35,9 @@ static bool EnsureDolParsed() { if (s_dolData) return true; s32 sz = 0; - const u8* p = aurora_dvd_get_dol(sz); + const u8* p = DVDGetDOLLocation(sz); if (!p || sz < 256) { - DuskLog.fatal("dvd_asset: aurora_dvd_get_dol failed (size={})", sz); + DuskLog.fatal("dvd_asset: DVDGetDOLLocation failed (size={})", sz); return false; } From aa3b16323046201dcf6d31e2a418fe2cac4be623 Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 6 Apr 2026 21:06:04 -0700 Subject: [PATCH 54/72] use updated aurora signature --- src/dusk/dvd_asset.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/dusk/dvd_asset.cpp b/src/dusk/dvd_asset.cpp index 3aa25be94b..b9e0729be9 100644 --- a/src/dusk/dvd_asset.cpp +++ b/src/dusk/dvd_asset.cpp @@ -35,7 +35,7 @@ static bool EnsureDolParsed() { if (s_dolData) return true; s32 sz = 0; - const u8* p = DVDGetDOLLocation(sz); + const u8* p = DVDGetDOLLocation(&sz); if (!p || sz < 256) { DuskLog.fatal("dvd_asset: DVDGetDOLLocation failed (size={})", sz); return false; From e7254fc7929828017461748523906186301f90ef Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 6 Apr 2026 21:31:29 -0700 Subject: [PATCH 55/72] update readme --- README.md | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 200913770a..59f12abc2a 100644 --- a/README.md +++ b/README.md @@ -37,25 +37,24 @@ sudo dnf groupinstall "Development Tools" "Development Libraries" ``` #### Setup -1. Clone and initialize the Dusk repository +Clone and initialize the Dusk repository ```sh git clone --recursive https://github.com/TakaRikka/dusk.git cd dusk git pull git submodule update --recursive ``` -2. Generate assets -```sh -cp /path/to/GZ2E01.iso orig/GZ2E01/. -python3 ./configure.py -ninja -``` #### Building **Visual Studio (Recommended for Windows)** ```sh cmake -B build/dusk -G "Visual Studio 17 2022" -A x64 # Win32 for 32bit ``` + +**Visual Studio Code with ninja** + +Project has support for the CMakeTools extension with variants and has a debug launch target + **ninja (Windows/macOS/Linux)** ```sh cmake -B build/dusk -GNinja From 1ec2357b7df2fc261a4507a5016c85748282ed40 Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 6 Apr 2026 21:51:40 -0700 Subject: [PATCH 56/72] disable all drawing in d_error_msg and remove need for assets --- src/d/d_error_msg.cpp | 32 +++++++------------------------- 1 file changed, 7 insertions(+), 25 deletions(-) diff --git a/src/d/d_error_msg.cpp b/src/d/d_error_msg.cpp index f1d63b5a1f..efd2512c11 100644 --- a/src/d/d_error_msg.cpp +++ b/src/d/d_error_msg.cpp @@ -15,22 +15,7 @@ #include "m_Do/m_Do_Reset.h" #include "m_Do/m_Do_graphic.h" -#if TARGET_PC -#include "dusk/dvd_asset.hpp" -static const u8* black_tex_get() { static u8 buf[0x40]; static bool _ = (dusk::LoadDolAsset(buf, 0x8037B140, 0x40), true); return buf; } -static const u8* msg_data_get() { static u8 buf[0x260]; static bool _ = (dusk::LoadDolAsset(buf, 0x8037B180, 0x260), true); return buf; } -static const u8* font_data_get() { static u8 buf[0x12260]; static bool _ = (dusk::LoadDolAsset(buf, 0x8037B3E0, 0x12260), true); return buf; } -#define black_tex (black_tex_get()) -#define msg_data (msg_data_get()) -#define font_data (font_data_get()) -#if VERSION == VERSION_GCN_PAL -// TODO: find addreses for pal languages -#define msg_data_ge ((const u8*)nullptr) -#define msg_data_fr ((const u8*)nullptr) -#define msg_data_sp ((const u8*)nullptr) -#define msg_data_it ((const u8*)nullptr) -#endif -#else +#if !TARGET_PC #include "assets/black_tex.h" #include "assets/msg_data.h" #if VERSION == VERSION_GCN_PAL @@ -66,6 +51,7 @@ struct BMG_INF1 : JUTDataBlockHeader { #endif static void messageSet(u32 status, bool i_drawBg) { + #if !TARGET_PC BMG_INF1* inf1; const char* msg_p; @@ -194,9 +180,11 @@ static void messageSet(u32 status, bool i_drawBg) { tpane.draw(x, y + 10.0f, FB_WIDTH, HBIND_LEFT); #endif #endif + #endif } void dDvdErrorMsg_c::draw(s32 status) { + #if !TARGET_PC JUtility::TColor backColor = g_clearColor; JFWDisplay::getManager()->setClearColor(backColor); mDoGph_gInf_c::beginRender(); @@ -224,6 +212,7 @@ void dDvdErrorMsg_c::draw(s32 status) { mDoGph_gInf_c::endRender(); JFWDisplay::getManager()->resetFader(); + #endif } bool dDvdErrorMsg_c::execute() { @@ -254,16 +243,12 @@ bool dDvdErrorMsg_c::execute() { static u8 l_captureAlpha = 0xFF; static void drawCapture(u8 alpha) { + #if !TARGET_PC static bool l_texCopied = false; if (!l_texCopied) { -#if TARGET_PC - GXSetTexCopySrc(0, 0, mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight()); - GXSetTexCopyDst(mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight(), (GXTexFmt)mDoGph_gInf_c::getFrameBufferTimg()->format, GX_TRUE); -#else GXSetTexCopySrc(0, 0, FB_WIDTH, FB_HEIGHT); GXSetTexCopyDst(FB_WIDTH / 2, FB_HEIGHT / 2, (GXTexFmt)mDoGph_gInf_c::getFrameBufferTimg()->format, GX_TRUE); -#endif GXCopyTex(mDoGph_gInf_c::getFrameBufferTex(), GX_FALSE); l_texCopied = true; } @@ -273,9 +258,6 @@ static void drawCapture(u8 alpha) { GXSetAlphaUpdate(GX_FALSE); j3dSys.drawInit(); -#ifdef TARGET_PC - mDoGph_gInf_c::getFrameBufferTexObj()->reset(); -#endif GXInitTexObj(mDoGph_gInf_c::getFrameBufferTexObj(), mDoGph_gInf_c::getFrameBufferTex(), FB_WIDTH / 2, FB_HEIGHT / 2, (GXTexFmt)mDoGph_gInf_c::getFrameBufferTimg()->format, GX_CLAMP, GX_CLAMP, GX_FALSE); GXInitTexObjLOD(mDoGph_gInf_c::getFrameBufferTexObj(), GX_LINEAR, GX_LINEAR, 0.0f, 0.0f, 0.0f, GX_FALSE, GX_FALSE, GX_ANISO_1); GXLoadTexObj(mDoGph_gInf_c::getFrameBufferTexObj(), GX_TEXMAP0); @@ -315,6 +297,7 @@ static void drawCapture(u8 alpha) { mDoGph_drawFilterQuad(1, 1); mDoGph_gInf_c::endRender(); JFWDisplay::getManager()->resetFader(); + #endif } bool dShutdownErrorMsg_c::execute() { @@ -342,6 +325,5 @@ bool dShutdownErrorMsg_c::execute() { mDoRst_reset(1, 1, 1); } } - return true; } From 12af5b212f16d2efbdacf8a0816b685aa72d6e53 Mon Sep 17 00:00:00 2001 From: Luke Street Date: Mon, 6 Apr 2026 23:07:48 -0600 Subject: [PATCH 57/72] Add vsync toggle & honor fullscreen setting --- extern/aurora | 2 +- include/dusk/settings.h | 1 + src/dusk/imgui/ImGuiMenuGame.cpp | 9 +++++++++ src/dusk/settings.cpp | 2 ++ src/m_Do/m_Do_main.cpp | 2 ++ 5 files changed, 15 insertions(+), 1 deletion(-) diff --git a/extern/aurora b/extern/aurora index 854ce1c178..f5c5917832 160000 --- a/extern/aurora +++ b/extern/aurora @@ -1 +1 @@ -Subproject commit 854ce1c178756ca307137c81afc3cc626fce5fb3 +Subproject commit f5c59178322c31b42676f49dd24e760e3b014f24 diff --git a/include/dusk/settings.h b/include/dusk/settings.h index 0cb3ba60b7..2436be70f5 100644 --- a/include/dusk/settings.h +++ b/include/dusk/settings.h @@ -15,6 +15,7 @@ struct UserSettings { struct { // Video ConfigVar enableFullscreen; + ConfigVar enableVsync; } video; struct { diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index 6ae32ce1a4..f200f734d4 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -14,6 +14,8 @@ #include "m_Do/m_Do_controller_pad.h" #include "m_Do/m_Do_graphic.h" +#include + namespace dusk { void ImGuiMenuGame::ToggleFullscreen() { getSettings().video.enableFullscreen.setValue(!getSettings().video.enableFullscreen); @@ -36,6 +38,13 @@ namespace dusk { ToggleFullscreen(); } + bool vsync = getSettings().video.enableVsync; + if (ImGui::Checkbox("Enable Vsync", &vsync)) { + getSettings().video.enableVsync.setValue(vsync); + aurora_enable_vsync(vsync); + config::Save(); + } + if (ImGui::MenuItem("Default Window Size")) { getSettings().video.enableFullscreen.setValue(false); VISetWindowFullscreen(false); diff --git a/src/dusk/settings.cpp b/src/dusk/settings.cpp index 32c6a5beb4..d923a2b00e 100644 --- a/src/dusk/settings.cpp +++ b/src/dusk/settings.cpp @@ -6,6 +6,7 @@ namespace dusk { UserSettings g_userSettings = { .video = { .enableFullscreen {"video.enableFullscreen", false}, + .enableVsync {"video.enableVsync", true}, }, .audio = { @@ -63,6 +64,7 @@ UserSettings& getSettings() { void registerSettings() { // Video Register(g_userSettings.video.enableFullscreen); + Register(g_userSettings.video.enableVsync); // Audio Register(g_userSettings.audio.masterVolume); diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index 51f74eef00..9cb7e41764 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -319,6 +319,8 @@ int game_main(int argc, char* argv[]) { AuroraConfig config{}; config.appName = dusk::AppName; config.configPath = configPath; + config.vsync = dusk::getSettings().video.enableVsync; + config.startFullscreen = dusk::getSettings().video.enableFullscreen; config.windowPosX = -1; config.windowPosY = -1; config.windowWidth = FB_WIDTH * 2; From ccf0a9a9be010999c54511f2248b13ece70d0a7b Mon Sep 17 00:00:00 2001 From: TakaRikka Date: Mon, 6 Apr 2026 22:47:55 -0700 Subject: [PATCH 58/72] fix flowers --- src/d/actor/d_flower.inc | 40 +++++++++++++++++++++++++++++++++------- 1 file changed, 33 insertions(+), 7 deletions(-) diff --git a/src/d/actor/d_flower.inc b/src/d/actor/d_flower.inc index 762b1e02e9..662e7679db 100644 --- a/src/d/actor/d_flower.inc +++ b/src/d/actor/d_flower.inc @@ -521,6 +521,32 @@ dFlower_packet_c::dFlower_packet_c() { unused += 0x2000; } +#if TARGET_LITTLE_ENDIAN + static bool initialized = false; + if (!initialized) { + for (int i = 0; i < (ARRAY_SIZE(l_flowerPos) / sizeof(Vec)); i++) { + be_swap(((Vec*)l_flowerPos)[i]); + } + for (int i = 0; i < (ARRAY_SIZE(l_flowerTexCoord) / sizeof(Vec)); i++) { + be_swap(((Vec*)l_flowerTexCoord)[i]); + } + for (int i = 0; i < (ARRAY_SIZE(l_flowerPos2) / sizeof(Vec)); i++) { + be_swap(((Vec*)l_flowerPos2)[i]); + } + for (int i = 0; i < (ARRAY_SIZE(l_flowerTexCoord2) / sizeof(Vec)); i++) { + be_swap(((Vec*)l_flowerTexCoord2)[i]); + } + for (int i = 0; i < (ARRAY_SIZE(l_flowerNormal) / sizeof(Vec)); i++) { + be_swap(((Vec*)l_flowerNormal)[i]); + } + for (int i = 0; i < (ARRAY_SIZE(l_flowerNormal2) / sizeof(Vec)); i++) { + be_swap(((Vec*)l_flowerNormal2)[i]); + } + + initialized = true; + } +#endif + #if TARGET_PC GXInitTexObj(&mTexObj_l_J_Ohana00_64TEX, l_J_Ohana00_64TEX, l_J_Ohana00_64TEX__width, l_J_Ohana00_64TEX__height, GX_TF_CMPR, GX_MIRROR, GX_MIRROR, GX_FALSE @@ -553,10 +579,10 @@ void dFlower_packet_c::draw() { GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_NRM, GX_NRM_XYZ, GX_F32, 0); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_CLR0, GX_CLR_RGBA, GX_RGBA8, 0); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_TEX0, GX_TEX_ST, GX_F32, 0); - GXSETARRAY(GX_VA_POS, &l_flowerPos, sizeof(l_flowerPos), 0xC, false); - GXSETARRAY(GX_VA_NRM, &l_flowerNormal, sizeof(l_flowerNormal), 0xC, false); - GXSETARRAY(GX_VA_CLR0, &l_flowerColor, sizeof(l_flowerColor), 4, false); - GXSETARRAY(GX_VA_TEX0, &l_flowerTexCoord, sizeof(l_flowerTexCoord), 8, false); + GXSETARRAY(GX_VA_POS, &l_flowerPos, sizeof(l_flowerPos), sizeof(Vec), true); + GXSETARRAY(GX_VA_NRM, &l_flowerNormal, sizeof(l_flowerNormal), sizeof(Vec), true); + GXSETARRAY(GX_VA_CLR0, &l_flowerColor, sizeof(l_flowerColor), sizeof(GXColor), true); + GXSETARRAY(GX_VA_TEX0, &l_flowerTexCoord, sizeof(l_flowerTexCoord), 8, true); GXColor sp64; dFlower_room_c* sp5C = m_room; @@ -652,9 +678,9 @@ void dFlower_packet_c::draw() { sp5C++; } - GXSETARRAY(GX_VA_POS, mp_pos, sizeof(l_flowerPos2), 0xC, true); - GXSETARRAY(GX_VA_NRM, &l_flowerNormal2, sizeof(l_flowerNormal2), 0xC, false); - GXSETARRAY(GX_VA_CLR0, mp_colors, sizeof(l_flowerColor2), 4, true); + GXSETARRAY(GX_VA_POS, mp_pos, sizeof(l_flowerPos2), sizeof(Vec), true); + GXSETARRAY(GX_VA_NRM, &l_flowerNormal2, sizeof(l_flowerNormal2), sizeof(Vec), true); + GXSETARRAY(GX_VA_CLR0, mp_colors, sizeof(l_flowerColor2), sizeof(GXColor), true); GXSETARRAY(GX_VA_TEX0, mp_texCoords, sizeof(l_flowerTexCoord2), 8, true); sp5C = m_room; From fd244d268c103cdf7f87357499db8a2d0461d928 Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 6 Apr 2026 23:20:58 -0700 Subject: [PATCH 59/72] adjust dol sightDL address based on version --- src/d/actor/d_a_player.cpp | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/d/actor/d_a_player.cpp b/src/d/actor/d_a_player.cpp index d6f7c54a49..f56a8399cd 100644 --- a/src/d/actor/d_a_player.cpp +++ b/src/d/actor/d_a_player.cpp @@ -369,7 +369,24 @@ JKRHeap* daPy_anmHeap_c::setAnimeHeap() { #if !PLATFORM_WII #if TARGET_PC #include "dusk/dvd_asset.hpp" -static const u8* l_sightDL_get() { static u8 buf[0x89]; static bool _ = (dusk::LoadDolAsset(buf, 0x803BA0C0, 0x89), true); return buf; } +static const u8* l_sightDL_get() { + static u8 buf[0x89]; + static bool _ = ( + dusk::LoadDolAsset( + buf, + #if VERSION_GCN_PAL + 0x803BBDA0, + #elif VERSION_GCN_JPN + 0x803B4220, + #elif VERSION_GCN_USA + 0x803BA0C0, + #endif + 0x89 + ), + true + ); + return buf; +} #define l_sightDL (l_sightDL_get()) #else #include "assets/l_sightDL__d_a_player.h" From 6063b366086f16dc00b3a93b1c2c151ee9556db7 Mon Sep 17 00:00:00 2001 From: madeline Date: Mon, 6 Apr 2026 23:21:29 -0700 Subject: [PATCH 60/72] correctly this time --- src/d/actor/d_a_player.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/d/actor/d_a_player.cpp b/src/d/actor/d_a_player.cpp index f56a8399cd..4c8b31c4c6 100644 --- a/src/d/actor/d_a_player.cpp +++ b/src/d/actor/d_a_player.cpp @@ -374,11 +374,11 @@ static const u8* l_sightDL_get() { static bool _ = ( dusk::LoadDolAsset( buf, - #if VERSION_GCN_PAL + #if VERSION == VERSION_GCN_PAL 0x803BBDA0, - #elif VERSION_GCN_JPN + #elif VERSION == VERSION_GCN_JPN 0x803B4220, - #elif VERSION_GCN_USA + #elif VERSION == VERSION_GCN_USA 0x803BA0C0, #endif 0x89 From 678321294c15b6eaf27cfc3d9610f9efe1a43190 Mon Sep 17 00:00:00 2001 From: madeline Date: Tue, 7 Apr 2026 05:59:03 -0700 Subject: [PATCH 61/72] fix the mf map regions being ass --- src/d/d_meter2_info.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/d/d_meter2_info.cpp b/src/d/d_meter2_info.cpp index 820e65dc0d..7307755c04 100644 --- a/src/d/d_meter2_info.cpp +++ b/src/d/d_meter2_info.cpp @@ -1639,7 +1639,7 @@ u8 dMeter2Info_getPixel(f32 i_posX, f32 i_posY, f32 param_2, f32 param_3, f32 i_ JUT_ASSERT(3074, *pixel < i_resTimg->numColors); - u16* palette_p = (u16*)((uintptr_t)i_resTimg + i_resTimg->paletteOffset); + BE(u16)* palette_p = (BE(u16)*)((uintptr_t)i_resTimg + i_resTimg->paletteOffset); u16 var_r24 = (u16)palette_p[*pixel]; if (var_r24 & 0x8000) { return 1; From c8bbfbc8368d6ad036e0c810d4695ca13cc0998f Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Tue, 7 Apr 2026 15:41:56 +0200 Subject: [PATCH 62/72] Fix Argorok Peahat camera init race condition Fixes #264 --- src/d/actor/d_a_e_ph.cpp | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/d/actor/d_a_e_ph.cpp b/src/d/actor/d_a_e_ph.cpp index dc20cb2361..df22c6cb66 100644 --- a/src/d/actor/d_a_e_ph.cpp +++ b/src/d/actor/d_a_e_ph.cpp @@ -1154,6 +1154,18 @@ int daE_PH_c::create() { int phase_state = dComIfG_resLoad(&mPhase, "E_PH"); if (phase_state == cPhs_COMPLEATE_e) { + +#if TARGET_PC + // Due to our loads being so much faster, peahats can initialize *before* the camera. + // This breaks the peahat used for camera focus during transition to phase 2 of Argorok. + // as it caches incorrect camera parameters in its init. + if (auto cam = dComIfGp_getCamera(0)) { + if (cam->phase_request.mpHandlerTable != nullptr) { + return cPhs_INIT_e; + } + } +#endif + mAction = fopAcM_GetParam(this) & 0xF; if (dComIfGs_isZoneSwitch(2, fopAcM_GetRoomNo(this)) && mAction == 4) { @@ -1256,6 +1268,10 @@ int daE_PH_c::create() { if (mAction == 5) { dCamera_c* camera_p = dCam_getBody(); mCamFovY = camera_p->Fovy(); + if (mCamFovY < 1) { + OSReport("GUH"); + mCamFovY = 10; + } mCamCenter = camera_p->Center(); mCamCenterTarget = mCamCenter; From 3229afa0b123acab6543a5df8dbde4984dc1e406 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Tue, 7 Apr 2026 15:44:37 +0200 Subject: [PATCH 63/72] More TU debug consistency Thought this was the cause of #264. Didn't end up being the case but figure it's still best to fix it. --- CMakeLists.txt | 4 ++-- include/d/d_camera.h | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 164d5aa893..66c86bb5f4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -137,8 +137,8 @@ add_library(game_base OBJECT ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${JSYSTEM_FILES src/dusk/imgui/ImGuiStubLog.cpp src/dusk/imgui/ImGuiAudio.cpp) -target_compile_definitions(game_debug PRIVATE ${GAME_COMPILE_DEFS} $<$:DEBUG=1>) -target_compile_definitions(game_base PRIVATE ${GAME_COMPILE_DEFS} NDEBUG=1 NDEBUG_DEFINED=1 DEBUG_DEFINED=0) +target_compile_definitions(game_debug PRIVATE ${GAME_COMPILE_DEFS} $<$:DEBUG=1> $<$:PARTIAL_DEBUG=1>) +target_compile_definitions(game_base PRIVATE ${GAME_COMPILE_DEFS} NDEBUG=1 NDEBUG_DEFINED=1 DEBUG_DEFINED=0 $<$:PARTIAL_DEBUG=1>) # only apply PCH to game_base since not all headers are necessarily validated with DEBUG=1 target_precompile_headers(game_base PRIVATE "$<$:${CMAKE_SOURCE_DIR}/include/dusk_pch.hpp>") diff --git a/include/d/d_camera.h b/include/d/d_camera.h index 37b634d18f..85e930c395 100644 --- a/include/d/d_camera.h +++ b/include/d/d_camera.h @@ -1154,7 +1154,7 @@ public: static engine_fn engine_tbl[]; /* 0x000 */ camera_class* field_0x0; -#if DEBUG +#if PARTIAL_DEBUG || DEBUG // Ensure struct layout consistent in all TUs. cXyz dbg_field_0x04[16]; s8 dbg_field_0xc4[0x10]; u32 dbg_field_0xd4; From 8e70468d027cbd1c65c2759a06aaf6f6e3798a41 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Tue, 7 Apr 2026 15:45:09 +0200 Subject: [PATCH 64/72] Guh --- src/d/actor/d_a_e_ph.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/d/actor/d_a_e_ph.cpp b/src/d/actor/d_a_e_ph.cpp index df22c6cb66..3213c2716e 100644 --- a/src/d/actor/d_a_e_ph.cpp +++ b/src/d/actor/d_a_e_ph.cpp @@ -1268,10 +1268,6 @@ int daE_PH_c::create() { if (mAction == 5) { dCamera_c* camera_p = dCam_getBody(); mCamFovY = camera_p->Fovy(); - if (mCamFovY < 1) { - OSReport("GUH"); - mCamFovY = 10; - } mCamCenter = camera_p->Center(); mCamCenterTarget = mCamCenter; From d51e6e617bb5ef973255f159eda079cc68571841 Mon Sep 17 00:00:00 2001 From: madeline Date: Tue, 7 Apr 2026 07:14:39 -0700 Subject: [PATCH 65/72] fix crashes on window resize --- src/d/d_menu_window.cpp | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/d/d_menu_window.cpp b/src/d/d_menu_window.cpp index e9131462c3..7fd5ea31a2 100644 --- a/src/d/d_menu_window.cpp +++ b/src/d/d_menu_window.cpp @@ -32,7 +32,7 @@ public: if (getDrawFlag() == 1) { setDrawFlag(); dComIfGp_onPauseFlag(); - + #if TARGET_PC GXSetTexCopySrc(0, 0, mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight()); #else @@ -46,17 +46,23 @@ public: #endif GXCopyTex(mDoGph_gInf_c::getFrameBufferTex(), GX_FALSE); GXPixModeSync(); - } else { - TGXTexObj tex; #if TARGET_PC - GXInitTexObj(&tex, mDoGph_gInf_c::getFrameBufferTex(), mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight(), + // init mTexObj at capture time so the gpu ref survives window resizes + GXInitTexObj(&mTexObj, mDoGph_gInf_c::getFrameBufferTex(), mDoGph_gInf_c::getWidth(), mDoGph_gInf_c::getHeight(), (GXTexFmt)mDoGph_gInf_c::getFrameBufferTimg()->format, GX_CLAMP, GX_CLAMP, GX_FALSE); + GXInitTexObjLOD(&mTexObj, GX_LINEAR, GX_LINEAR, 0.0f, 0.0f, 0.0f, GX_FALSE, GX_FALSE, GX_ANISO_1); +#endif + } else { +#if TARGET_PC + // reuse the persistent mTexObj + GXLoadTexObj(&mTexObj, GX_TEXMAP0); #else + TGXTexObj tex; GXInitTexObj(&tex, mDoGph_gInf_c::getFrameBufferTex(), FB_WIDTH / 2, FB_HEIGHT / 2, (GXTexFmt)mDoGph_gInf_c::getFrameBufferTimg()->format, GX_CLAMP, GX_CLAMP, GX_FALSE); -#endif GXInitTexObjLOD(&tex, GX_LINEAR, GX_LINEAR, 0.0f, 0.0f, 0.0f, GX_FALSE, GX_FALSE, GX_ANISO_1); GXLoadTexObj(&tex, GX_TEXMAP0); +#endif GXSetNumChans(0); GXSetNumTexGens(1); GXSetTexCoordGen2(GX_TEXCOORD0, GX_TG_MTX2x4, GX_TG_TEX0, 60, GX_FALSE, 125); @@ -119,6 +125,9 @@ private: /* 0x4 */ u8 mFlag; /* 0x5 */ u8 mAlpha; /* 0x6 */ u8 mTopFlag; +#if TARGET_PC + TGXTexObj mTexObj; +#endif }; BOOL dMw_UP_TRIGGER() { From ee5ab7978e2b5420acbf97a7c5be6729c5e1e4d9 Mon Sep 17 00:00:00 2001 From: MelonSpeedruns Date: Tue, 7 Apr 2026 13:56:23 -0400 Subject: [PATCH 66/72] Fixes audio volume at boot if changed (#270) * Fixes audio volume at boot if changed * Update Settings refactor for settings we want to update in the future * remove unused include --------- Co-authored-by: MelonSpeedruns --- include/dusk/audio/DuskAudioSystem.h | 2 ++ src/dusk/audio/DuskAudioSystem.cpp | 6 ++++++ src/dusk/imgui/ImGuiConsole.cpp | 9 ++++++++- src/dusk/imgui/ImGuiConsole.hpp | 1 + src/dusk/imgui/ImGuiMenuGame.cpp | 3 --- 5 files changed, 17 insertions(+), 4 deletions(-) diff --git a/include/dusk/audio/DuskAudioSystem.h b/include/dusk/audio/DuskAudioSystem.h index 1b31db6e7c..724776f5f1 100644 --- a/include/dusk/audio/DuskAudioSystem.h +++ b/include/dusk/audio/DuskAudioSystem.h @@ -8,6 +8,8 @@ namespace dusk::audio { */ void Initialize(); + void SetEnableReverb(bool value); + void SetMasterVolume(f32 value); u32 GetResetCount(int channelIdx); diff --git a/src/dusk/audio/DuskAudioSystem.cpp b/src/dusk/audio/DuskAudioSystem.cpp index c7313749c2..7b464e4f0e 100644 --- a/src/dusk/audio/DuskAudioSystem.cpp +++ b/src/dusk/audio/DuskAudioSystem.cpp @@ -76,6 +76,12 @@ void dusk::audio::SetMasterVolume(const f32 value) { MasterVolume = value; } +void dusk::audio::SetEnableReverb(const bool value) { + JASCriticalSection section; + + EnableReverb = value; +} + void SDLCALL GetNewAudio( void*, SDL_AudioStream*, diff --git a/src/dusk/imgui/ImGuiConsole.cpp b/src/dusk/imgui/ImGuiConsole.cpp index fe5d3e7c9a..4329849800 100644 --- a/src/dusk/imgui/ImGuiConsole.cpp +++ b/src/dusk/imgui/ImGuiConsole.cpp @@ -15,6 +15,7 @@ #include "JSystem/JUtility/JUTGamePad.h" #include "dusk/config.hpp" #include "dusk/settings.h" +#include "dusk/audio/DuskAudioSystem.h" #if _WIN32 #define NOMINMAX @@ -178,13 +179,19 @@ namespace dusk { ImGuiConsole::ImGuiConsole() {} + void ImGuiConsole::UpdateSettings() { + dusk::audio::SetMasterVolume(dusk::getSettings().audio.masterVolume / 100.0f); + dusk::audio::SetEnableReverb(dusk::getSettings().audio.enableReverb); + getTransientSettings().skipFrameRateLimit = getSettings().game.enableTurboKeybind && ImGui::IsKeyDown(ImGuiKey_Tab); + } + void ImGuiConsole::PreDraw() { if (!m_isLaunchInitialized) { m_toasts.emplace_back("Press F1 to toggle menu"s, 5.f); m_isLaunchInitialized = true; } - getTransientSettings().skipFrameRateLimit = getSettings().game.enableTurboKeybind && ImGui::IsKeyDown(ImGuiKey_Tab); + UpdateSettings(); if ((ImGui::IsKeyDown(ImGuiKey_LeftCtrl) || ImGui::IsKeyDown(ImGuiKey_RightCtrl)) && ImGui::IsKeyPressed(ImGuiKey_R)) diff --git a/src/dusk/imgui/ImGuiConsole.hpp b/src/dusk/imgui/ImGuiConsole.hpp index 27032ed39b..2ab61a0ffb 100644 --- a/src/dusk/imgui/ImGuiConsole.hpp +++ b/src/dusk/imgui/ImGuiConsole.hpp @@ -14,6 +14,7 @@ namespace dusk { class ImGuiConsole { public: ImGuiConsole(); + void UpdateSettings(); void PreDraw(); void PostDraw(); diff --git a/src/dusk/imgui/ImGuiMenuGame.cpp b/src/dusk/imgui/ImGuiMenuGame.cpp index f200f734d4..1608209bac 100644 --- a/src/dusk/imgui/ImGuiMenuGame.cpp +++ b/src/dusk/imgui/ImGuiMenuGame.cpp @@ -78,9 +78,6 @@ namespace dusk { } */ - audio::SetMasterVolume(getSettings().audio.masterVolume / 100.0f); - audio::EnableReverb = getSettings().audio.enableReverb; - ImGui::EndMenu(); } From 63ade15e2cc3e4090727c0ff23c3dae3676ee7fc Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Tue, 7 Apr 2026 20:06:29 +0200 Subject: [PATCH 67/72] Cleanly shut down JKRDecomp thread Properly join the thread to ensure it's shut down before we try to exit. Fixes #268 --- include/m_Do/m_Do_machine.h | 3 +++ .../include/JSystem/JFramework/JFWSystem.h | 3 +++ .../JSystem/include/JSystem/JKernel/JKRAram.h | 3 +++ .../include/JSystem/JKernel/JKRDecomp.h | 3 +++ libs/JSystem/src/JFramework/JFWSystem.cpp | 6 ++++++ libs/JSystem/src/JKernel/JKRAram.cpp | 6 ++++++ libs/JSystem/src/JKernel/JKRDecomp.cpp | 21 +++++++++++++------ src/m_Do/m_Do_machine.cpp | 6 ++++++ src/m_Do/m_Do_main.cpp | 2 ++ 9 files changed, 47 insertions(+), 6 deletions(-) diff --git a/include/m_Do/m_Do_machine.h b/include/m_Do/m_Do_machine.h index 53c47c07a7..eeea7e77ce 100644 --- a/include/m_Do/m_Do_machine.h +++ b/include/m_Do/m_Do_machine.h @@ -15,6 +15,9 @@ void my_SysPrintHeap(char const*, void*, u32); void mDoMch_HeapCheckAll(); void mDoMch_HeapFreeFillAll(); int mDoMch_Create(); +#if TARGET_PC +void mDoMch_Destroy(); +#endif extern GXRenderModeObj g_ntscZeldaProg; diff --git a/libs/JSystem/include/JSystem/JFramework/JFWSystem.h b/libs/JSystem/include/JSystem/JFramework/JFWSystem.h index bb4dfa01cd..288b5f03d8 100644 --- a/libs/JSystem/include/JSystem/JFramework/JFWSystem.h +++ b/libs/JSystem/include/JSystem/JFramework/JFWSystem.h @@ -33,6 +33,9 @@ struct JFWSystem { static void firstInit(); static void init(); +#if TARGET_PC + static void shutdown(); +#endif static JUTConsole* getSystemConsole() { return systemConsole; } static JKRExpHeap* getSystemHeap() { return systemHeap; } diff --git a/libs/JSystem/include/JSystem/JKernel/JKRAram.h b/libs/JSystem/include/JSystem/JKernel/JKRAram.h index 9c8ebd88d1..dd3bf54f9c 100644 --- a/libs/JSystem/include/JSystem/JKernel/JKRAram.h +++ b/libs/JSystem/include/JSystem/JKernel/JKRAram.h @@ -39,6 +39,9 @@ public: public: static JKRAram* create(u32, u32, s32, s32, s32); +#if TARGET_PC + static void destroy(); +#endif static void checkOkAddress(u8*, u32, JKRAramBlock*, u32); static void changeGroupIdIfNeed(u8*, int); static JKRAramBlock* mainRamToAram(u8*, u32, u32, JKRExpandSwitch, u32, JKRHeap*, int, u32*); diff --git a/libs/JSystem/include/JSystem/JKernel/JKRDecomp.h b/libs/JSystem/include/JSystem/JKernel/JKRDecomp.h index 9131ecfbaa..2e7ce0ef1c 100644 --- a/libs/JSystem/include/JSystem/JKernel/JKRDecomp.h +++ b/libs/JSystem/include/JSystem/JKernel/JKRDecomp.h @@ -48,6 +48,9 @@ private: public: static JKRDecomp* create(s32); +#if TARGET_PC + static void destroy(); +#endif static JKRDecompCommand* prepareCommand(u8*, u8*, u32, u32, JKRDecompCommand::AsyncCallback); static void sendCommand(JKRDecompCommand*); static bool sync(JKRDecompCommand*, int); diff --git a/libs/JSystem/src/JFramework/JFWSystem.cpp b/libs/JSystem/src/JFramework/JFWSystem.cpp index b4effd547a..d6322f34c9 100644 --- a/libs/JSystem/src/JFramework/JFWSystem.cpp +++ b/libs/JSystem/src/JFramework/JFWSystem.cpp @@ -116,3 +116,9 @@ void JFWSystem::init() { void* buffer = systemHeap->alloc(CSetUpParam::exConsoleBufferSize, 4); JUTException::createConsole(buffer, CSetUpParam::exConsoleBufferSize); } + +#if TARGET_PC +void JFWSystem::shutdown() { + JKRAram::destroy(); +} +#endif diff --git a/libs/JSystem/src/JKernel/JKRAram.cpp b/libs/JSystem/src/JKernel/JKRAram.cpp index 32afe1cef4..2770328afa 100644 --- a/libs/JSystem/src/JKernel/JKRAram.cpp +++ b/libs/JSystem/src/JKernel/JKRAram.cpp @@ -42,6 +42,12 @@ JKRAram* JKRAram::create(u32 aram_audio_buffer_size, u32 aram_audio_graph_size, return sAramObject; } +#if TARGET_PC +void JKRAram::destroy() { + JKRDecomp::destroy(); +} +#endif + OSMessage JKRAram::sMessageBuffer[4] = { NULL, NULL, diff --git a/libs/JSystem/src/JKernel/JKRDecomp.cpp b/libs/JSystem/src/JKernel/JKRDecomp.cpp index 776823531d..a97edea0a3 100644 --- a/libs/JSystem/src/JKernel/JKRDecomp.cpp +++ b/libs/JSystem/src/JKernel/JKRDecomp.cpp @@ -20,6 +20,15 @@ JKRDecomp* JKRDecomp::create(s32 priority) { return sDecompObject; } +#if TARGET_PC +void JKRDecomp::destroy() { + if (sDecompObject) { + OSSendMessage(&sMessageQueue, nullptr, OS_MESSAGE_NOBLOCK); + OSJoinThread(sDecompObject->getThreadRecord(), nullptr); + } +} +#endif + OSMessage JKRDecomp::sMessageBuffer[8] = {0}; OSMessageQueue JKRDecomp::sMessageQueue = {0}; @@ -34,15 +43,15 @@ void* JKRDecomp::run() { OSInitMessageQueue(&sMessageQueue, sMessageBuffer, 8); for (;;) { OSMessage message; -#ifdef TARGET_PC - if (!OSReceiveMessage(&sMessageQueue, &message, OS_MESSAGE_BLOCK)) { - break; - } -#else OSReceiveMessage(&sMessageQueue, &message, OS_MESSAGE_BLOCK); -#endif JKRDecompCommand* command = (JKRDecompCommand*)message; +#if TARGET_PC + if (!command) { + break; + } +#endif + decode(command->mSrcBuffer, command->mDstBuffer, command->mSrcLength, command->mDstLength); if (command->field_0x20 != 0) { diff --git a/src/m_Do/m_Do_machine.cpp b/src/m_Do/m_Do_machine.cpp index fdab588957..6b186a77e6 100644 --- a/src/m_Do/m_Do_machine.cpp +++ b/src/m_Do/m_Do_machine.cpp @@ -1010,3 +1010,9 @@ int mDoMch_Create() { return 1; } + +#if TARGET_PC +void mDoMch_Destroy() { + JFWSystem::shutdown(); +} +#endif diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index 9cb7e41764..8742436c4e 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -366,6 +366,8 @@ int game_main(int argc, char* argv[]) { fflush(stdout); fflush(stderr); + mDoMch_Destroy(); + // Notifies all CVs and causes threads to exit OSResetSystem(OS_RESET_SHUTDOWN, 0, 0); From 1a22cc02c07209b5999b24b5674bfd99c7255252 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Tue, 7 Apr 2026 20:12:52 +0200 Subject: [PATCH 68/72] Fix movie running at uncapped FPS Fixes #267 --- src/d/actor/d_a_movie_player.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/d/actor/d_a_movie_player.cpp b/src/d/actor/d_a_movie_player.cpp index 4573684b2f..c3074ac877 100644 --- a/src/d/actor/d_a_movie_player.cpp +++ b/src/d/actor/d_a_movie_player.cpp @@ -4473,7 +4473,9 @@ int daMP_c::daMP_c_Get_arg_movieNo() { int daMP_c::daMP_c_Init() { JUT_ASSERT(9469, m_myObj == NULL); +#if !TARGET_PC // We don't properly simulate retrace interval so this doesn't work. mDoGph_gInf_c::setFrameRate(1); +#endif daMP_Fail_alloc = FALSE; int demoNo = daMP_c_Get_arg_demoNo(); From 8aa6ce950c2d6fb2e246a79d4998808b98501cfb Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Tue, 7 Apr 2026 20:36:44 +0200 Subject: [PATCH 69/72] Fix bigger wallet type display in collection screen Fixes https://github.com/TwilitRealm/dusk/issues/223 --- include/d/d_menu_collect.h | 4 ++++ src/d/d_menu_collect.cpp | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+) diff --git a/include/d/d_menu_collect.h b/include/d/d_menu_collect.h index 587fd5c103..55d5373c71 100644 --- a/include/d/d_menu_collect.h +++ b/include/d/d_menu_collect.h @@ -50,7 +50,11 @@ public: void changeShield(); void changeClothe(); void setArrowMaxNum(u8); +#if TARGET_PC + void setWalletSizeNum(u16); +#else void setWalletMaxNum(u16); +#endif void setSmellType(); void setHeartPiece(); void setPohMaxNum(u8); diff --git a/src/d/d_menu_collect.cpp b/src/d/d_menu_collect.cpp index ed5586e866..72a390a0cc 100644 --- a/src/d/d_menu_collect.cpp +++ b/src/d/d_menu_collect.cpp @@ -590,6 +590,15 @@ void dMenu_Collect2D_c::screenSet() { field_0x184[4][2] = 0x196; field_0x184[5][2] = 0x195; field_0x184[6][2] = 0; +#if TARGET_PC // Since we allow changing wallet sizes, do something more robust. + if (dComIfGs_getWalletSize() == WALLET) { + field_0x184[0][3] = 0x199; + } else if (dComIfGs_getWalletSize() == BIG_WALLET) { + field_0x184[0][3] = 0x19a; + } else { + field_0x184[0][3] = 0x19b; + } +#else if (dComIfGs_getRupeeMax() == WALLET_MAX) { field_0x184[0][3] = 0x199; } else if (dComIfGs_getRupeeMax() == BIG_WALLET_MAX) { @@ -597,6 +606,7 @@ void dMenu_Collect2D_c::screenSet() { } else { field_0x184[0][3] = 0x19b; } +#endif if (dComIfGs_getArrowMax() == QUIVER_MAX) { field_0x184[1][3] = 0x1b9; } else if (dComIfGs_getArrowMax() == BIG_QUIVER_MAX) { @@ -757,7 +767,11 @@ void dMenu_Collect2D_c::screenSet() { setItemNameString(mCursorX, mCursorY); cursorPosSet(); setArrowMaxNum(dComIfGs_getArrowMax()); +#if TARGET_PC + setWalletSizeNum(dComIfGs_getWalletSize()); +#else setWalletMaxNum(dComIfGs_getRupeeMax()); +#endif setSmellType(); setHeartPiece(); setPohMaxNum(dComIfGs_getPohSpiritNum()); @@ -1242,6 +1256,27 @@ void dMenu_Collect2D_c::setArrowMaxNum(u8 param_0) { } } +#if TARGET_PC +void dMenu_Collect2D_c::setWalletSizeNum(u16 i_walletSize) { + switch (i_walletSize) { + case WALLET: + mpScreen->search(MULTI_CHAR('item_1_0'))->show(); + mpScreen->search(MULTI_CHAR('item_1_1'))->hide(); + mpScreen->search(MULTI_CHAR('item_1_2'))->hide(); + break; + case BIG_WALLET: + mpScreen->search(MULTI_CHAR('item_1_0'))->hide(); + mpScreen->search(MULTI_CHAR('item_1_1'))->show(); + mpScreen->search(MULTI_CHAR('item_1_2'))->hide(); + break; + case GIANT_WALLET: + mpScreen->search(MULTI_CHAR('item_1_0'))->hide(); + mpScreen->search(MULTI_CHAR('item_1_1'))->hide(); + mpScreen->search(MULTI_CHAR('item_1_2'))->show(); + break; + } +} +#else void dMenu_Collect2D_c::setWalletMaxNum(u16 i_walletSize) { switch (i_walletSize) { case 300: @@ -1261,6 +1296,7 @@ void dMenu_Collect2D_c::setWalletMaxNum(u16 i_walletSize) { break; } } +#endif void dMenu_Collect2D_c::setSmellType() { static const u64 smell_tag[5] = { From 74942f3c76891e8b2081ce6192e11837bc48f154 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Tue, 7 Apr 2026 21:43:38 +0200 Subject: [PATCH 70/72] Fix JUTResFont performance Just store the GXTexObjs in a separately allocated hashmap, so they can be persisted cross-frame. Easy. Fixes #227 --- .../include/JSystem/JUtility/JUTResFont.h | 8 ++++ libs/JSystem/src/JUtility/JUTResFont.cpp | 45 +++++++++++++++++-- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/libs/JSystem/include/JSystem/JUtility/JUTResFont.h b/libs/JSystem/include/JSystem/JUtility/JUTResFont.h index 09d3303da0..8709822d7b 100644 --- a/libs/JSystem/include/JSystem/JUtility/JUTResFont.h +++ b/libs/JSystem/include/JSystem/JUtility/JUTResFont.h @@ -18,6 +18,10 @@ struct BlockHeader { BE(u32) size; }; +#if TARGET_PC +struct GlyphTextures; +#endif + /** * @ingroup jsystem-jutility * @@ -64,7 +68,11 @@ public: // some types uncertain, may need to be fixed /* 0x1C */ int mWidth; /* 0x20 */ int mHeight; +#if TARGET_PC + GlyphTextures* mGlyphTextures; +#else /* 0x24 */ TGXTexObj mTexObj; +#endif /* 0x44 */ int mTexPageIdx; /* 0x48 */ const ResFONT* mResFont; /* 0x4C */ ResFONT::INF1* mInf1Ptr; diff --git a/libs/JSystem/src/JUtility/JUTResFont.cpp b/libs/JSystem/src/JUtility/JUTResFont.cpp index e6410defdc..10443d6404 100644 --- a/libs/JSystem/src/JUtility/JUTResFont.cpp +++ b/libs/JSystem/src/JUtility/JUTResFont.cpp @@ -6,19 +6,39 @@ #include "JSystem/JUtility/JUTAssert.h" #include "JSystem/JUtility/JUTConsole.h" #include +#include "absl/container/node_hash_map.h" + +#if TARGET_PC +struct GlyphTextures { + absl::node_hash_map textures; +}; +#endif JUTResFont::JUTResFont() { +#if TARGET_PC + mGlyphTextures = new GlyphTextures(); +#endif initialize_state(); JUTFont::initialize_state(); } JUTResFont::JUTResFont(const ResFONT* pFont, JKRHeap* pHeap) { +#if TARGET_PC + mGlyphTextures = new GlyphTextures(); +#endif initialize_state(); JUTFont::initialize_state(); initiate(pFont, pHeap); } JUTResFont::~JUTResFont() { +#if TARGET_PC + for (auto& pair : mGlyphTextures->textures) { + pair.second.reset(); + } + delete mGlyphTextures; +#endif + if (mValid) { delete_and_initialize(); JUTFont::initialize_state(); @@ -414,12 +434,30 @@ void JUTResFont::loadImage(int code, GXTexMapID id){ mWidth = cellCol * cellW; mHeight = cellRow * cellH; +#if TARGET_PC + const auto found = mGlyphTextures->textures.find(code); + GXTexObj* texObj; + if (found == mGlyphTextures->textures.end()) { + texObj = &mGlyphTextures->textures[code]; + void* pImg = &mpGlyphBlocks[i]->data[pageIdx * mpGlyphBlocks[i]->textureSize]; + GXInitTexObj(texObj, pImg, mpGlyphBlocks[i]->textureWidth, + mpGlyphBlocks[i]->textureHeight, (GXTexFmt)(u16)mpGlyphBlocks[i]->textureFormat, + GX_CLAMP, GX_CLAMP, 0); + + GXInitTexObjLOD(texObj, GX_LINEAR, GX_LINEAR, 0.0f, 0.0f, 0.0f, 0U, 0U, GX_ANISO_1); + } else { + texObj = &found->second; + } + + GXLoadTexObj(texObj, id); + + // Gets used by some other code. + mTexPageIdx = pageIdx; + field_0x66 = i; +#else if (pageIdx != mTexPageIdx || i != field_0x66) { void* pImg = &mpGlyphBlocks[i]->data[pageIdx * mpGlyphBlocks[i]->textureSize]; -#ifdef TARGET_PC - mTexObj.reset(); -#endif GXInitTexObj(&mTexObj, pImg, mpGlyphBlocks[i]->textureWidth, mpGlyphBlocks[i]->textureHeight, (GXTexFmt)(u16)mpGlyphBlocks[i]->textureFormat, GX_CLAMP, GX_CLAMP, 0); @@ -430,6 +468,7 @@ void JUTResFont::loadImage(int code, GXTexMapID id){ } GXLoadTexObj(&mTexObj, id); +#endif } } From 8f77ca72b1c4fc370e31d23181aca6b3bc6ab33b Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Tue, 7 Apr 2026 22:17:48 +0200 Subject: [PATCH 71/72] Fix Aurora draw call display in performance overlay It was getting reset at the start of the frame... Just cache the values. --- include/dusk/dusk.h | 6 ++++++ src/dusk/imgui/ImGuiMenuTools.cpp | 27 ++++++++++++++------------- src/m_Do/m_Do_main.cpp | 2 ++ 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/include/dusk/dusk.h b/include/dusk/dusk.h index 7fc2a23070..832b656160 100644 --- a/include/dusk/dusk.h +++ b/include/dusk/dusk.h @@ -3,7 +3,13 @@ #include +#include "aurora/gfx.h" + extern AuroraInfo auroraInfo; extern const char* configPath; +namespace dusk { + extern AuroraStats lastFrameAuroraStats; +} + #endif // DUSK_DUSK_H diff --git a/src/dusk/imgui/ImGuiMenuTools.cpp b/src/dusk/imgui/ImGuiMenuTools.cpp index 7478adc0e5..4a455672a9 100644 --- a/src/dusk/imgui/ImGuiMenuTools.cpp +++ b/src/dusk/imgui/ImGuiMenuTools.cpp @@ -10,6 +10,7 @@ #include "d/actor/d_a_alink.h" #include "d/actor/d_a_horse.h" #include "d/d_com_inf_game.h" +#include "dusk/dusk.h" #include "m_Do/m_Do_main.h" namespace dusk { @@ -109,31 +110,31 @@ namespace dusk { } hasPrevious = true; - AuroraStats const* stats = aurora_get_stats(); + const auto& stats = lastFrameAuroraStats; ImGuiStringViewText( - fmt::format(FMT_STRING("Queued pipelines: {}\n"), stats->queuedPipelines)); + fmt::format(FMT_STRING("Queued pipelines: {}\n"), stats.queuedPipelines)); ImGuiStringViewText( - fmt::format(FMT_STRING("Done pipelines: {}\n"), stats->createdPipelines)); + fmt::format(FMT_STRING("Done pipelines: {}\n"), stats.createdPipelines)); ImGuiStringViewText( - fmt::format(FMT_STRING("Draw call count: {}\n"), stats->drawCallCount)); + fmt::format(FMT_STRING("Draw call count: {}\n"), stats.drawCallCount)); ImGuiStringViewText(fmt::format(FMT_STRING("Merged draw calls: {}\n"), - stats->mergedDrawCallCount)); + stats.mergedDrawCallCount)); ImGuiStringViewText(fmt::format(FMT_STRING("Vertex size: {}\n"), - BytesToString(stats->lastVertSize))); + BytesToString(stats.lastVertSize))); ImGuiStringViewText(fmt::format(FMT_STRING("Uniform size: {}\n"), - BytesToString(stats->lastUniformSize))); + BytesToString(stats.lastUniformSize))); ImGuiStringViewText(fmt::format(FMT_STRING("Index size: {}\n"), - BytesToString(stats->lastIndexSize))); + BytesToString(stats.lastIndexSize))); ImGuiStringViewText(fmt::format(FMT_STRING("Storage size: {}\n"), - BytesToString(stats->lastStorageSize))); + BytesToString(stats.lastStorageSize))); ImGuiStringViewText(fmt::format(FMT_STRING("Tex upload size: {}\n"), - BytesToString(stats->lastTextureUploadSize))); + BytesToString(stats.lastTextureUploadSize))); ImGuiStringViewText(fmt::format( FMT_STRING("Total: {}\n"), - BytesToString(stats->lastVertSize + stats->lastUniformSize + - stats->lastIndexSize + stats->lastStorageSize + - stats->lastTextureUploadSize))); + BytesToString(stats.lastVertSize + stats.lastUniformSize + + stats.lastIndexSize + stats.lastStorageSize + + stats.lastTextureUploadSize))); // TODO: persist to config ShowCornerContextMenu(m_debugOverlayCorner, m_cameraOverlayCorner); diff --git a/src/m_Do/m_Do_main.cpp b/src/m_Do/m_Do_main.cpp index 8742436c4e..e42e6ea98b 100644 --- a/src/m_Do/m_Do_main.cpp +++ b/src/m_Do/m_Do_main.cpp @@ -110,6 +110,7 @@ s32 LOAD_COPYDATE(void*) { } AuroraInfo auroraInfo; +AuroraStats dusk::lastFrameAuroraStats; const char* configPath; void main01(void) { @@ -182,6 +183,7 @@ void main01(void) { VIWaitForRetrace(); #if TARGET_PC + dusk::lastFrameAuroraStats = *aurora_get_stats(); if (!aurora_begin_frame()) { DuskLog.debug("aurora_begin_frame returned false, skipping draw this frame"); continue; From 2b45b01fcc122b91f7be39ed2510bfd4f637a224 Mon Sep 17 00:00:00 2001 From: PJB3005 Date: Tue, 7 Apr 2026 22:37:57 +0200 Subject: [PATCH 72/72] Fix minimap "don't render" code not always working due to rounding errors Significant performance boost in some areas like Gerudo Desert when map isn't visible. --- src/d/d_meter_map.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/d/d_meter_map.cpp b/src/d/d_meter_map.cpp index 6b78e2242b..b5900a4be5 100644 --- a/src/d/d_meter_map.cpp +++ b/src/d/d_meter_map.cpp @@ -596,7 +596,8 @@ void dMeterMap_c::_draw() { #if TARGET_PC // Optimization: don't draw map if it's off-screen/invisible. // Especially useful in debug builds on Hyrule field etc., it's slow! - if ((!mMapIsInside && mSlidePositionOffset == getDispPosOutSide_OffsetX()) || mMapAlpha == 0) { + // That +3 is an arbitrary bias to avoid rounding issues causing this to fail. + if ((!mMapIsInside && mSlidePositionOffset <= getDispPosOutSide_OffsetX() + 3) || mMapAlpha == 0) { return; } #endif