mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-05-25 15:05:06 -04:00
Merge remote-tracking branch 'origin/main' into feature/dynamic-aspect-ratio
This commit is contained in:
+7
-1
@@ -71,6 +71,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)
|
||||
|
||||
@@ -103,7 +109,7 @@ set(GAME_INCLUDE_DIRS
|
||||
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)
|
||||
aurora::card freeverb cxxopts::cxxopts absl::flat_hash_map nlohmann_json::nlohmann_json)
|
||||
|
||||
if (DUSK_MOVIE_SUPPORT_REAL)
|
||||
if (TARGET libjpeg-turbo::turbojpeg-static)
|
||||
|
||||
@@ -1332,17 +1332,22 @@ set(DOLPHIN_FILES
|
||||
|
||||
set(DUSK_FILES
|
||||
include/dusk/endian_gx.hpp
|
||||
include/dusk/config.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/settings.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/ImGuiEngine.cpp
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,122 @@
|
||||
#ifndef DUSK_CONFIG_HPP
|
||||
#define DUSK_CONFIG_HPP
|
||||
|
||||
#include <stdexcept>
|
||||
#include "nlohmann/json.hpp"
|
||||
#include "config_var.hpp"
|
||||
|
||||
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.
|
||||
*/
|
||||
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<ConfigValue T>
|
||||
class ConfigImpl : public ConfigImplBase {
|
||||
// Just downcasting the references...
|
||||
void loadFromJson(ConfigVarBase& cVar, const nlohmann::json& jsonValue) const final {
|
||||
assert(typeid(cVar) == typeid(ConfigVar<T>));
|
||||
loadFromJson(dynamic_cast<ConfigVar<T>&>(cVar), jsonValue);
|
||||
}
|
||||
|
||||
void loadFromArg(ConfigVarBase& cVar, std::string_view stringValue) const final {
|
||||
assert(typeid(cVar) == typeid(ConfigVar<T>));
|
||||
loadFromArg(dynamic_cast<ConfigVar<T>&>(cVar), stringValue);
|
||||
}
|
||||
|
||||
[[nodiscard]] nlohmann::json dumpToJson(const ConfigVarBase& cVar) const final {
|
||||
assert(typeid(cVar) == typeid(ConfigVar<T>));
|
||||
return dumpToJson(dynamic_cast<const ConfigVar<T>&>(cVar));
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief Load a JSON value into a CVar at the Value layer.
|
||||
*/
|
||||
static void loadFromJson(ConfigVar<T>& cVar, const nlohmann::json& jsonValue);
|
||||
|
||||
/**
|
||||
* \brief Load a simple launch argument into the CVar at the Override layer.
|
||||
*/
|
||||
static void loadFromArg(ConfigVar<T>& cVar, std::string_view stringValue);
|
||||
|
||||
/**
|
||||
* \brief Dump the value contained in the CVar to JSON.
|
||||
*/
|
||||
[[nodiscard]] static nlohmann::json dumpToJson(const ConfigVar<T>& 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 <ConfigValue T>
|
||||
const ConfigImplBase* GetConfigImpl() {
|
||||
static ConfigImpl<T> config;
|
||||
return &config;
|
||||
}
|
||||
|
||||
} // namespace dusk::config
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,235 @@
|
||||
#ifndef DUSK_CONFIG_VAR_HPP
|
||||
#define DUSK_CONFIG_VAR_HPP
|
||||
|
||||
#include "dolphin/types.h"
|
||||
#include <type_traits>
|
||||
#include <cstdlib>
|
||||
#include <string>
|
||||
|
||||
/**
|
||||
* 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<T>,
|
||||
* 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 <typename T>
|
||||
concept ConfigValueInteger =
|
||||
std::is_same_v<T, s8>
|
||||
|| std::is_same_v<T, u8>
|
||||
|| std::is_same_v<T, s16>
|
||||
|| std::is_same_v<T, u16>
|
||||
|| std::is_same_v<T, s32>
|
||||
|| std::is_same_v<T, u32>
|
||||
|| std::is_same_v<T, s64>
|
||||
|| std::is_same_v<T, u64>;
|
||||
|
||||
/**
|
||||
* \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 <typename T>
|
||||
concept ConfigValue =
|
||||
!std::is_const_v<T>
|
||||
&& !std::is_volatile_v<T>
|
||||
&& (std::is_same_v<T, bool>
|
||||
|| ConfigValueInteger<T>
|
||||
|| std::is_same_v<T, f32>
|
||||
|| std::is_same_v<T, f64>
|
||||
|| std::is_same_v<T, std::string>
|
||||
|| (std::is_enum_v<T> && ConfigValueInteger<std::underlying_type_t<T>>));
|
||||
|
||||
template <ConfigValue T>
|
||||
const ConfigImplBase* GetConfigImpl();
|
||||
|
||||
/**
|
||||
* \brief A CVar storing values.
|
||||
*
|
||||
* @tparam T The type of value stored in the CVar.
|
||||
*/
|
||||
template <ConfigValue T>
|
||||
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 <typename... Args>
|
||||
explicit ConfigVar(const char* name, Args&&... arg)
|
||||
: ConfigVarBase(name, GetConfigImpl<T>()), defaultValue(std::forward<Args>(arg)...),
|
||||
value(), overrideValue() {}
|
||||
|
||||
/**
|
||||
* \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();
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
operator const T&() {
|
||||
return getValue();
|
||||
}
|
||||
|
||||
/**
|
||||
* \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
|
||||
@@ -4,5 +4,6 @@
|
||||
#include <aurora/aurora.h>
|
||||
|
||||
extern AuroraInfo auroraInfo;
|
||||
extern const char* configPath;
|
||||
|
||||
#endif // DUSK_DUSK_H
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
#ifndef DUSK_IO_HPP
|
||||
#define DUSK_IO_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
// 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<u8> 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<u8> 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
|
||||
+34
-28
@@ -1,8 +1,12 @@
|
||||
#ifndef DUSK_CONFIG_H
|
||||
#define DUSK_CONFIG_H
|
||||
|
||||
#include "dusk/config_var.hpp"
|
||||
|
||||
namespace dusk {
|
||||
|
||||
using namespace config;
|
||||
|
||||
// Persistent user settings
|
||||
|
||||
struct UserSettings {
|
||||
@@ -10,61 +14,63 @@ struct UserSettings {
|
||||
|
||||
struct {
|
||||
// Video
|
||||
bool enableFullscreen;
|
||||
ConfigVar<bool> enableFullscreen;
|
||||
} video;
|
||||
|
||||
struct {
|
||||
// Audio
|
||||
int masterVolume;
|
||||
int mainMusicVolume;
|
||||
int subMusicVolume;
|
||||
int soundEffectsVolume;
|
||||
int fanfareVolume;
|
||||
bool enableReverb;
|
||||
ConfigVar<int> masterVolume;
|
||||
ConfigVar<int> mainMusicVolume;
|
||||
ConfigVar<int> subMusicVolume;
|
||||
ConfigVar<int> soundEffectsVolume;
|
||||
ConfigVar<int> fanfareVolume;
|
||||
ConfigVar<bool> enableReverb;
|
||||
} audio;
|
||||
|
||||
// Game settings
|
||||
|
||||
struct {
|
||||
// QoL
|
||||
bool enableQuickTransform;
|
||||
bool hideTvSettingsScreen;
|
||||
bool biggerWallets;
|
||||
bool noReturnRupees;
|
||||
bool disableRupeeCutscenes;
|
||||
bool noSwordRecoil;
|
||||
int damageMultiplier;
|
||||
bool instantDeath;
|
||||
bool fastClimbing;
|
||||
bool noMissClimbing;
|
||||
bool fastTears;
|
||||
ConfigVar<bool> enableQuickTransform;
|
||||
ConfigVar<bool> hideTvSettingsScreen;
|
||||
ConfigVar<bool> biggerWallets;
|
||||
ConfigVar<bool> noReturnRupees;
|
||||
ConfigVar<bool> disableRupeeCutscenes;
|
||||
ConfigVar<bool> noSwordRecoil;
|
||||
ConfigVar<int> damageMultiplier;
|
||||
ConfigVar<bool> instantDeath;
|
||||
ConfigVar<bool> fastClimbing;
|
||||
ConfigVar<bool> noMissClimbing;
|
||||
ConfigVar<bool> fastTears;
|
||||
|
||||
// Preferences
|
||||
bool enableMirrorMode;
|
||||
bool invertCameraXAxis;
|
||||
ConfigVar<bool> enableMirrorMode;
|
||||
ConfigVar<bool> invertCameraXAxis;
|
||||
|
||||
// Graphics
|
||||
bool enableBloom;
|
||||
bool useWaterProjectionOffset;
|
||||
ConfigVar<bool> enableBloom;
|
||||
ConfigVar<bool> useWaterProjectionOffset;
|
||||
|
||||
// Audio
|
||||
bool noLowHpSound;
|
||||
bool midnasLamentNonStop;
|
||||
ConfigVar<bool> noLowHpSound;
|
||||
ConfigVar<bool> midnasLamentNonStop;
|
||||
|
||||
// Cheats
|
||||
bool enableFastIronBoots;
|
||||
bool canTransformAnywhere;
|
||||
ConfigVar<bool> enableFastIronBoots;
|
||||
ConfigVar<bool> canTransformAnywhere;
|
||||
|
||||
// Technical
|
||||
bool restoreWiiGlitches;
|
||||
ConfigVar<bool> restoreWiiGlitches;
|
||||
|
||||
// Controls
|
||||
bool enableTurboKeybind;
|
||||
ConfigVar<bool> enableTurboKeybind;
|
||||
} game;
|
||||
};
|
||||
|
||||
UserSettings& getSettings();
|
||||
|
||||
void registerSettings();
|
||||
|
||||
// Transient settings
|
||||
|
||||
struct CollisionViewSettings {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+41
-16
@@ -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;
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,222 @@
|
||||
#include "dusk/config.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 <limits>
|
||||
#include <string>
|
||||
|
||||
#include "dusk/dusk.h"
|
||||
|
||||
using namespace dusk::config;
|
||||
|
||||
constexpr auto ConfigFileName = "config.json";
|
||||
|
||||
using json = nlohmann::json;
|
||||
|
||||
aurora::Module DuskConfigLog("dusk::config");
|
||||
|
||||
static absl::flat_hash_map<std::string_view, ConfigVarBase*> RegisteredConfigVars;
|
||||
static bool RegistrationDone;
|
||||
|
||||
static std::string GetConfigJsonPath() {
|
||||
return fmt::format("{}{}", configPath, 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<ConfigValue T>
|
||||
void ConfigImpl<T>::loadFromJson(ConfigVar<T>& cVar, const json& jsonValue) {
|
||||
cVar.setValue(jsonValue.get<T>(), false);
|
||||
}
|
||||
|
||||
template<ConfigValue T>
|
||||
nlohmann::json ConfigImpl<T>::dumpToJson(const ConfigVar<T>& cVar) {
|
||||
return cVar.getValue();
|
||||
}
|
||||
|
||||
template<ConfigValue T> requires std::is_integral_v<T> && std::is_signed_v<T>
|
||||
static void loadFromArgImpl(ConfigVar<T>& cVar, const std::string_view stringValue) {
|
||||
const std::string str(stringValue);
|
||||
const auto result = std::stoll(str);
|
||||
if (result >= std::numeric_limits<T>::min() && result <= std::numeric_limits<T>::max()) {
|
||||
cVar.setOverrideValue(result);
|
||||
} else {
|
||||
throw std::out_of_range("Value is too large");
|
||||
}
|
||||
}
|
||||
|
||||
template<ConfigValue T> requires std::is_integral_v<T> && std::is_unsigned_v<T>
|
||||
static void loadFromArgImpl(ConfigVar<T>& cVar, const std::string_view stringValue) {
|
||||
const std::string str(stringValue);
|
||||
const auto result = std::stoull(str);
|
||||
if (result <= std::numeric_limits<T>::max()) {
|
||||
cVar.setOverrideValue(result);
|
||||
} else {
|
||||
throw std::out_of_range("Value is too large");
|
||||
}
|
||||
}
|
||||
|
||||
static void loadFromArgImpl(ConfigVar<f32>& cVar, const std::string_view stringValue) {
|
||||
const std::string str(stringValue);
|
||||
const auto result = std::stof(str);
|
||||
cVar.setOverrideValue(result);
|
||||
}
|
||||
|
||||
static void loadFromArgImpl(ConfigVar<f64>& cVar, const std::string_view stringValue) {
|
||||
const std::string str(stringValue);
|
||||
const auto result = std::stod(str);
|
||||
cVar.setOverrideValue(result);
|
||||
}
|
||||
|
||||
static void loadFromArgImpl(ConfigVar<std::string>& cVar, const std::string_view stringValue) {
|
||||
cVar.setOverrideValue(std::string(stringValue));
|
||||
}
|
||||
|
||||
template<ConfigValue T>
|
||||
void ConfigImpl<T>::loadFromArg(ConfigVar<T>& cVar, const std::string_view stringValue) {
|
||||
loadFromArgImpl(cVar, stringValue);
|
||||
}
|
||||
|
||||
template<>
|
||||
void ConfigImpl<bool>::loadFromArg(ConfigVar<bool>& 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<bool>;
|
||||
template class ConfigImpl<s8>;
|
||||
template class ConfigImpl<u8>;
|
||||
template class ConfigImpl<s16>;
|
||||
template class ConfigImpl<u16>;
|
||||
template class ConfigImpl<s32>;
|
||||
template class ConfigImpl<u32>;
|
||||
template class ConfigImpl<s64>;
|
||||
template class ConfigImpl<u64>;
|
||||
template class ConfigImpl<f32>;
|
||||
template class ConfigImpl<f64>;
|
||||
template class ConfigImpl<std::string>;
|
||||
}
|
||||
|
||||
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 configJsonPath = GetConfigJsonPath();
|
||||
if (configJsonPath.empty()) {
|
||||
return;
|
||||
}
|
||||
LoadFromFileName(configJsonPath.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 configJsonPath = GetConfigJsonPath();
|
||||
if (configJsonPath.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
DuskConfigLog.info("Saving config to '{}'", configJsonPath);
|
||||
|
||||
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(configJsonPath.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;
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
#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<bool>& var) {
|
||||
bool copy = var.getValue();
|
||||
if (ImGui::Checkbox(title, ©)) {
|
||||
var.setValue(copy);
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGuiSliderFloat(const char* label, ConfigVar<float>& var, float v_min, float v_max, const char* format = "%.3f", ImGuiSliderFlags flags = 0) {
|
||||
float val = var;
|
||||
if (ImGui::SliderFloat(label, &val, v_min, v_max, format, flags)) {
|
||||
var.setValue(val);
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGuiSliderInt(const char* label, ConfigVar<int>& var, int v_min, int v_max, const char* format = "%d", ImGuiSliderFlags flags = 0) {
|
||||
int val = var;
|
||||
if (ImGui::SliderInt(label, &val, v_min, v_max, format, flags)) {
|
||||
var.setValue(val);
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
static void ImGuiMenuItem(const char* label, const char* shortcut, ConfigVar<bool>& p_selected, bool enabled = true) {
|
||||
bool copy = p_selected.getValue();
|
||||
if (ImGui::MenuItem(label, shortcut, ©, enabled)) {
|
||||
p_selected.setValue(copy);
|
||||
Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif // DUSK_IMGUICONFIG_HPP
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "ImGuiConsole.hpp"
|
||||
|
||||
#include "JSystem/JUtility/JUTGamePad.h"
|
||||
#include "dusk/config.hpp"
|
||||
#include "dusk/settings.h"
|
||||
|
||||
#if _WIN32
|
||||
@@ -192,8 +193,7 @@ namespace dusk {
|
||||
}
|
||||
|
||||
if (ImGui::IsKeyPressed(ImGuiKey_F11)) {
|
||||
getSettings().video.enableFullscreen = !getSettings().video.enableFullscreen;
|
||||
VISetWindowFullscreen(getSettings().video.enableFullscreen);
|
||||
ImGuiMenuGame::ToggleFullscreen();
|
||||
}
|
||||
|
||||
if (CheckMenuViewToggle(ImGuiKey_F1, m_isHidden)) {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
#include "imgui.h"
|
||||
|
||||
#include "ImGuiMenuEnhancements.hpp"
|
||||
|
||||
#include "ImGuiConfig.hpp"
|
||||
#include "dusk/settings.h"
|
||||
|
||||
namespace dusk {
|
||||
@@ -10,45 +10,45 @@ namespace dusk {
|
||||
void ImGuiMenuEnhancements::draw() {
|
||||
if (ImGui::BeginMenu("Enhancements")) {
|
||||
if (ImGui::BeginMenu("Quality of Life")) {
|
||||
ImGui::Checkbox("Quick Transform (R+Y)", &getSettings().game.enableQuickTransform);
|
||||
config::ImGuiCheckbox("Quick Transform (R+Y)", getSettings().game.enableQuickTransform);
|
||||
|
||||
ImGui::Checkbox("Bigger Wallets", &getSettings().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)");
|
||||
}
|
||||
|
||||
ImGui::Checkbox("No Rupee Returns", &getSettings().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");
|
||||
}
|
||||
|
||||
ImGui::Checkbox("Disable Rupee Cutscenes", &getSettings().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");
|
||||
}
|
||||
|
||||
ImGui::Checkbox("No Sword Recoil", &getSettings().game.noSwordRecoil);
|
||||
config::ImGuiCheckbox("No Sword Recoil", getSettings().game.noSwordRecoil);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Link won't recoil when his sword hits walls");
|
||||
}
|
||||
|
||||
ImGui::Checkbox("Faster Climbing", &getSettings().game.fastClimbing);
|
||||
config::ImGuiCheckbox("Faster Climbing", getSettings().game.fastClimbing);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Quicker climbing on ladders and vines like the HD version");
|
||||
}
|
||||
|
||||
ImGui::Checkbox("No Climbing Miss Animation", &getSettings().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");
|
||||
}
|
||||
|
||||
ImGui::Checkbox("Faster Tears of Light", &getSettings().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");
|
||||
}
|
||||
|
||||
ImGui::Checkbox("Hide TV Settings Screen", &getSettings().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")) {
|
||||
ImGui::Checkbox("Mirror Mode", &getSettings().game.enableMirrorMode);
|
||||
config::ImGuiCheckbox("Mirror Mode", getSettings().game.enableMirrorMode);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Mirrors the world, matching the Wii version of the game");
|
||||
}
|
||||
|
||||
ImGui::Checkbox("Invert Camera X Axis", &getSettings().game.invertCameraXAxis);
|
||||
config::ImGuiCheckbox("Invert Camera X Axis", getSettings().game.invertCameraXAxis);
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Graphics")) {
|
||||
ImGui::Checkbox("Native Bloom", &getSettings().game.enableBloom);
|
||||
config::ImGuiCheckbox("Native Bloom", getSettings().game.enableBloom);
|
||||
|
||||
ImGui::Checkbox("Water Projection Offset", &getSettings().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")) {
|
||||
ImGui::Checkbox("No Low HP Sound", &getSettings().game.noLowHpSound);
|
||||
config::ImGuiCheckbox("No Low HP Sound", getSettings().game.noLowHpSound);
|
||||
if (ImGui::IsItemHovered()) {
|
||||
ImGui::SetTooltip("Disable the beeping sound when having low health");
|
||||
}
|
||||
|
||||
ImGui::Checkbox("Non-Stop Midna's Lament", &getSettings().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")) {
|
||||
ImGui::Checkbox("Fast Iron Boots", &getSettings().game.enableFastIronBoots);
|
||||
config::ImGuiCheckbox("Fast Iron Boots", getSettings().game.enableFastIronBoots);
|
||||
|
||||
ImGui::Checkbox("Can Transform Anywhere", &getSettings().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")) {
|
||||
ImGui::SliderInt("Damage Multiplier", &getSettings().game.damageMultiplier, 1, 8, "x%d");
|
||||
config::ImGuiSliderInt("Damage Multiplier", getSettings().game.damageMultiplier, 1, 8, "x%d");
|
||||
|
||||
ImGui::Checkbox("Instant Death", &getSettings().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")) {
|
||||
ImGui::Checkbox("Restore Wii 1.0 Glitches", &getSettings().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");
|
||||
@@ -125,6 +125,12 @@ namespace dusk {
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
if (ImGui::BeginMenu("Tools")) {
|
||||
config::ImGuiCheckbox("Enable Turbo Key", getSettings().game.enableTurboKeybind);
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
|
||||
#include "ImGuiConsole.hpp"
|
||||
#include "ImGuiMenuGame.hpp"
|
||||
#include "ImGuiConfig.hpp"
|
||||
#include <imgui_internal.h>
|
||||
|
||||
#include "JSystem/JUtility/JUTGamePad.h"
|
||||
@@ -14,6 +15,12 @@
|
||||
#include "m_Do/m_Do_graphic.h"
|
||||
|
||||
namespace dusk {
|
||||
void ImGuiMenuGame::ToggleFullscreen() {
|
||||
getSettings().video.enableFullscreen.setValue(!getSettings().video.enableFullscreen);
|
||||
VISetWindowFullscreen(getSettings().video.enableFullscreen);
|
||||
config::Save();
|
||||
}
|
||||
|
||||
ImGuiMenuGame::ImGuiMenuGame() {}
|
||||
|
||||
void ImGuiMenuGame::draw() {
|
||||
@@ -26,8 +33,7 @@ namespace dusk {
|
||||
|
||||
if (ImGui::BeginMenu("Graphics")) {
|
||||
if (ImGui::MenuItem("Toggle Fullscreen", hotkeys::TOGGLE_FULLSCREEN)) {
|
||||
getSettings().video.enableFullscreen = !getSettings().video.enableFullscreen;
|
||||
VISetWindowFullscreen(getSettings().video.enableFullscreen);
|
||||
ToggleFullscreen();
|
||||
}
|
||||
|
||||
if (ImGui::MenuItem("Default Window Size")) {
|
||||
@@ -42,9 +48,8 @@ namespace dusk {
|
||||
|
||||
if (ImGui::BeginMenu("Audio")) {
|
||||
ImGui::Text("Master Volume");
|
||||
ImGui::SliderInt("##masterVolume", &getSettings().audio.masterVolume, 0, 100);
|
||||
ImGui::Checkbox("Enable Reverb", &getSettings().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");
|
||||
|
||||
@@ -16,6 +16,8 @@ namespace dusk {
|
||||
void windowInputViewer();
|
||||
void windowControllerConfig();
|
||||
|
||||
static void ToggleFullscreen();
|
||||
|
||||
private:
|
||||
struct {
|
||||
int m_selectedPort = 0;
|
||||
|
||||
@@ -7,10 +7,10 @@
|
||||
#include "ImGuiConsole.hpp"
|
||||
#include "ImGuiMenuTools.hpp"
|
||||
|
||||
#include "m_Do/m_Do_main.h"
|
||||
#include "d/d_com_inf_game.h"
|
||||
#include "d/actor/d_a_alink.h"
|
||||
#include "d/actor/d_a_horse.h"
|
||||
#include "d/d_com_inf_game.h"
|
||||
#include "m_Do/m_Do_main.h"
|
||||
|
||||
namespace dusk {
|
||||
ImGuiMenuTools::ImGuiMenuTools() {}
|
||||
@@ -18,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;
|
||||
}
|
||||
@@ -49,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();
|
||||
ImGui::MenuItem("Enable Turbo Key", hotkeys::TURBO, &getSettings().game.enableTurboKeybind);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
#include "dusk/io.hpp"
|
||||
#include <cstdio>
|
||||
#include <filesystem>
|
||||
|
||||
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
|
||||
#if _MSVC_VER
|
||||
#define MODE(val) ##val
|
||||
#else
|
||||
#define MODE(val) val
|
||||
#endif
|
||||
#endif
|
||||
|
||||
static FILE* ThrowIfNotOpen(const FileStream& file) {
|
||||
if (!file.GetFileHandle()) {
|
||||
throw std::runtime_error("Invalid file handle!");
|
||||
}
|
||||
|
||||
return static_cast<FILE*>(file.GetFileHandle());
|
||||
}
|
||||
|
||||
[[noreturn]] static void ThrowForError(int code) {
|
||||
throw std::system_error(std::make_error_code(static_cast<std::errc>(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<std::filesystem::path::value_type, wchar_t>);
|
||||
err = _wfopen_s(&file, path.c_str(), mode);
|
||||
#else
|
||||
errno = 0;
|
||||
static_assert(std::is_same_v<std::filesystem::path::value_type, char>);
|
||||
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<const char8_t*>(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*>(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<u8> FileStream::ReadFull() {
|
||||
const auto fileHandle = ThrowIfNotOpen(*this);
|
||||
|
||||
std::vector<u8> 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<u8> 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());
|
||||
}
|
||||
+66
-34
@@ -1,68 +1,100 @@
|
||||
#include "dusk/settings.h"
|
||||
#include "dusk/config.hpp"
|
||||
|
||||
namespace dusk {
|
||||
|
||||
UserSettings g_userSettings = {
|
||||
// Program settings
|
||||
|
||||
// Video
|
||||
.video = {
|
||||
.enableFullscreen = false,
|
||||
.enableFullscreen {"video.enableFullscreen", false},
|
||||
},
|
||||
|
||||
// Audio
|
||||
.audio = {
|
||||
.masterVolume = 80,
|
||||
.mainMusicVolume = 100,
|
||||
.subMusicVolume = 100,
|
||||
.soundEffectsVolume = 100,
|
||||
.fanfareVolume = 100,
|
||||
.enableReverb = true
|
||||
.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 settings
|
||||
.game = {
|
||||
// Quality of Life
|
||||
.enableQuickTransform = false,
|
||||
.hideTvSettingsScreen = false,
|
||||
.biggerWallets = false,
|
||||
.noReturnRupees = false,
|
||||
.disableRupeeCutscenes = false,
|
||||
.noSwordRecoil = false,
|
||||
.damageMultiplier = 1,
|
||||
.instantDeath = false,
|
||||
.fastClimbing = false,
|
||||
.noMissClimbing = false,
|
||||
.fastTears = false,
|
||||
.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 = false,
|
||||
.invertCameraXAxis = false,
|
||||
.enableMirrorMode {"game.enableMirrorMode", false},
|
||||
.invertCameraXAxis {"game.invertCameraXAxis", false},
|
||||
|
||||
// Graphics
|
||||
.enableBloom = true,
|
||||
.useWaterProjectionOffset = false,
|
||||
.enableBloom {"game.enableBloom", true},
|
||||
.useWaterProjectionOffset {"game.useWaterProjectionOffset", false},
|
||||
|
||||
// Audio
|
||||
.noLowHpSound = false,
|
||||
.midnasLamentNonStop = false,
|
||||
.noLowHpSound {"game.noLowHpSound", false},
|
||||
.midnasLamentNonStop {"game.midnasLamentNonStop", false},
|
||||
|
||||
// Cheats
|
||||
.enableFastIronBoots = false,
|
||||
.canTransformAnywhere = false,
|
||||
.enableFastIronBoots {"game.enableFastIronBoots", false},
|
||||
.canTransformAnywhere {"game.canTransformAnywhere", false},
|
||||
|
||||
// Technical
|
||||
.restoreWiiGlitches = false,
|
||||
.restoreWiiGlitches {"game.restoreWiiGlitches", false},
|
||||
|
||||
// Controls
|
||||
.enableTurboKeybind = true,
|
||||
}
|
||||
.enableTurboKeybind {"game.enableTurboKeybind", true},
|
||||
},
|
||||
};
|
||||
|
||||
UserSettings& getSettings() {
|
||||
return g_userSettings;
|
||||
}
|
||||
|
||||
void registerSettings() {
|
||||
// Video
|
||||
Register(g_userSettings.video.enableFullscreen);
|
||||
|
||||
// Audio
|
||||
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(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);
|
||||
}
|
||||
|
||||
// Transient settings
|
||||
|
||||
static TransientSettings g_transientSettings = {
|
||||
|
||||
+57
-5
@@ -44,11 +44,12 @@
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
#include "SSystem/SComponent/c_API.h"
|
||||
#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 <aurora/aurora.h>
|
||||
#include <aurora/event.h>
|
||||
@@ -56,7 +57,9 @@
|
||||
#include <aurora/dvd.h>
|
||||
#include <dolphin/dvd.h>
|
||||
|
||||
#include "SDL3/SDL_filesystem.h"
|
||||
#include "cxxopts.hpp"
|
||||
#include "dusk/config.hpp"
|
||||
|
||||
// --- GLOBALS ---
|
||||
s8 mDoMain::developmentMode = -1;
|
||||
@@ -107,6 +110,7 @@ s32 LOAD_COPYDATE(void*) {
|
||||
}
|
||||
|
||||
AuroraInfo auroraInfo;
|
||||
const char* configPath;
|
||||
|
||||
void main01(void) {
|
||||
OS_REPORT("\x1b[m");
|
||||
@@ -233,10 +237,51 @@ static void aurora_imgui_init_callback(const AuroraWindowSize* size) {
|
||||
dusk::ImGuiEngine_Initialize(size->scale);
|
||||
}
|
||||
|
||||
static void ApplyCVarOverrides(const cxxopts::OptionValue& option) {
|
||||
if (option.count() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto& cVars = option.as<std::vector<std::string>>();
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
// =========================================================================
|
||||
int game_main(int argc, char* argv[]) {
|
||||
dusk::registerSettings();
|
||||
dusk::config::FinishRegistration();
|
||||
|
||||
cxxopts::ParseResult parsed_arg_options;
|
||||
|
||||
try {
|
||||
@@ -246,7 +291,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<uint8_t>()->default_value("0"))
|
||||
("h,help", "Print usage")
|
||||
("dvd", "Path to DVD image file", cxxopts::value<std::string>()->default_value("game.iso"))
|
||||
("backend", "Graphics API backend to use (auto, d3d11, d3d12, metal, vulkan, opengl, opengles, webgpu, null)", cxxopts::value<std::string>()->default_value("auto"));
|
||||
("backend", "Graphics API backend to use (auto, d3d11, d3d12, metal, vulkan, opengl, opengles, webgpu, null)", cxxopts::value<std::string>()->default_value("auto"))
|
||||
("cvar", "Override configuration variables without modifying config", cxxopts::value<std::vector<std::string>>());
|
||||
|
||||
arg_options.parse_positional({"dvd"});
|
||||
arg_options.positional_help("<dvd-image>");
|
||||
@@ -265,8 +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 = FB_WIDTH * 2;
|
||||
|
||||
Reference in New Issue
Block a user