mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-07-07 12:03:24 -04:00
Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a01c01b582 | |||
| 552b3ad353 | |||
| 074b43a089 | |||
| b772b6d952 | |||
| 42910ab2fd | |||
| f54892b2c2 | |||
| f32e069c4b | |||
| 09f087656a | |||
| fe15366912 | |||
| cfadf7607a | |||
| f81d25b425 | |||
| ebf6f31719 | |||
| 590d209f76 | |||
| ed21cd4fd0 | |||
| 277538bb81 | |||
| 5418b1831d | |||
| 2d4e69466b | |||
| 427dcfab82 |
@@ -20,31 +20,17 @@ It aims to be as accurate as possible to the original while also providing new o
|
|||||||
> Dusklight does *not* provide any copyrighted assets. You must provide your own copy of the original game.
|
> Dusklight does *not* provide any copyrighted assets. You must provide your own copy of the original game.
|
||||||
|
|
||||||
> [!IMPORTANT]
|
> [!IMPORTANT]
|
||||||
> At a minimum, Dusklight requires a GPU with support for either D3D12, Vulkan, or Metal. Your experience with specific hardware, operating systems, and drivers may vary. In particular, older Intel iGPUs have a high likelihood of incompatibility. We are also aware of a number of issues on devices with Adreno GPUs and are working to resolve them.
|
> At a minimum, Dusklight requires a GPU with support for D3D12, Vulkan 1.1+, or Metal. For older devices, best-effort support is provided for D3D11 and OpenGL ES (Android), but will not achieve full accuracy or performance. Your experience with specific hardware, operating systems, and drivers may vary.
|
||||||
|
|
||||||
### 1. Dump your game
|
### 1. Dump your game
|
||||||
|
|
||||||
You must dump your own copy of the game, please see [this article](https://wiki.dolphin-emu.org/index.php?title=Ripping_Games) for instructions. After dumping, you can use a program like [Dolphin](https://dolphin-emu.org/) or [nodtool](https://github.com/encounter/nod/releases) to convert the `.iso` to a `.rvz` to save space.
|
You must dump your own copy of the game. Please see [this article](https://wiki.dolphin-emu.org/index.php?title=Ripping_Games) for instructions. After dumping, you can use a program like [Dolphin](https://dolphin-emu.org/) or [nodtool](https://github.com/encounter/nod/releases) to convert the `.iso` to `.rvz` to save space.
|
||||||
|
|
||||||
Currently, only the GameCube USA and EUR releases are supported. Support for other versions of the game is planned in the future.
|
Currently, only the GameCube USA and EUR releases are supported. Support for other versions of the game is planned in the future.
|
||||||
|
|
||||||
### 2. Download [Dusklight](https://github.com/TwilitRealm/dusklight/releases)
|
### 2. Install Dusklight
|
||||||
|
|
||||||
### 3. Setup the game
|
Visit the [official installation guide](https://twilitrealm.dev/install/) for full instructions.
|
||||||
**Windows / macOS / Linux**
|
|
||||||
- Extract the .zip file
|
|
||||||
- Launch Dusklight
|
|
||||||
- Press **Select Disc Image** and provide the path to your supported game dump
|
|
||||||
- Press **Play**!
|
|
||||||
|
|
||||||
**iOS**
|
|
||||||
- Follow the [iOS setup guide](docs/ios-install-altstore.md)
|
|
||||||
|
|
||||||
**Android**
|
|
||||||
- Install the Dusklight APK
|
|
||||||
- Launch Dusklight
|
|
||||||
- Press **Select Disc Image** and provide the path to your supported game dump
|
|
||||||
- Press **Play**!
|
|
||||||
|
|
||||||
# Building
|
# Building
|
||||||
|
|
||||||
|
|||||||
Vendored
+1
-1
Submodule extern/aurora updated: 22351fb0b7...9087a409da
@@ -16,37 +16,37 @@
|
|||||||
];
|
];
|
||||||
forAllSystems = lib.genAttrs supportedSystems;
|
forAllSystems = lib.genAttrs supportedSystems;
|
||||||
|
|
||||||
dawnVersion = "v20260423.175430";
|
dawnVersion = "v20260618.032059";
|
||||||
nodVersion = "v2.0.0-alpha.8";
|
nodVersion = "v2.0.0-alpha.10";
|
||||||
versionSuffix = "nix-" + (self.shortRev or self.dirtyShortRev or "dirty");
|
versionSuffix = "nix-" + (self.shortRev or self.dirtyShortRev or "dirty");
|
||||||
|
|
||||||
dawnInfo = {
|
dawnInfo = {
|
||||||
"x86_64-linux" = {
|
"x86_64-linux" = {
|
||||||
triple = "linux-x86_64";
|
triple = "linux-x86_64";
|
||||||
hash = "sha256-HXfKTLHtMPwupnFnaflCARtXVPuS/0PoCePXidjE5xs=";
|
hash = "sha256-GFSd573b+VQx/VmFdNQgWDd0V9ayQlcw0Zuopke12ak=";
|
||||||
};
|
};
|
||||||
"aarch64-linux" = {
|
"aarch64-linux" = {
|
||||||
triple = "linux-aarch64";
|
triple = "linux-aarch64";
|
||||||
hash = "sha256-34yyFpfqBZUwoFXQ41F0AwAU78FaNihOSY0oriwn6B0=";
|
hash = "sha256-ZaoP7BAjBMnfAv2/AMRi3FNH2ZtyqASCSFyU/oB2Mzg=";
|
||||||
};
|
};
|
||||||
"aarch64-darwin" = {
|
"aarch64-darwin" = {
|
||||||
triple = "darwin-arm64";
|
triple = "darwin-arm64";
|
||||||
hash = "sha256-eQnzrBp6gjiBek1VYQ9A5W13ClYWrDDKjIqv/7eNTR4=";
|
hash = "sha256-HT+qtlLaSHyoXPrUcXgcTGa877X5YfzbxRD4bJb7i1Y=";
|
||||||
};
|
};
|
||||||
"x86_64-darwin" = {
|
"x86_64-darwin" = {
|
||||||
triple = "darwin-x86_64";
|
triple = "darwin-x86_64";
|
||||||
hash = "sha256-QGWiGdxiI9kci3NPXH6QFFirxn16851zB/w3jqhIBJ4=";
|
hash = "sha256-cUNaCbA7rlKSukDVKGaVEVw0Zt1+mSbaHbmUCMvMVWc=";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
nodPrebuiltInfo = {
|
nodPrebuiltInfo = {
|
||||||
"x86_64-linux" = {
|
"x86_64-linux" = {
|
||||||
triple = "linux-x86_64";
|
triple = "linux-x86_64";
|
||||||
hash = "sha256-mUqvLsbsqaZ+HAjMmHYPYO+MgtanGRTw7Gzn5uXR5rE=";
|
hash = "sha256-FVQWECVA2gWdc+n5OQ/Tvwn8z0qdgjSd1WlFt5HKOec=";
|
||||||
};
|
};
|
||||||
"aarch64-darwin" = {
|
"aarch64-darwin" = {
|
||||||
triple = "macos-arm64";
|
triple = "macos-arm64";
|
||||||
hash = "sha256-UPy1ywCcv0K6VJOU3uUelJuUdBh3UNaPRlyP5LOBeDw=";
|
hash = "sha256-8ZEejxksVgShNKUVRCBYaLOp9x/qOC9pAeVrElQUGUk=";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -75,7 +75,7 @@
|
|||||||
'';
|
'';
|
||||||
|
|
||||||
dawn = pkgs.fetchzip {
|
dawn = pkgs.fetchzip {
|
||||||
url = "https://github.com/encounter/dawn-build/releases/download/${dawnVersion}/dawn-${dawnInfo.${system}.triple}.tar.gz";
|
url = "https://github.com/encounter/dawn/releases/download/${dawnVersion}/dawn-${dawnInfo.${system}.triple}.tar.gz";
|
||||||
hash = dawnInfo.${system}.hash;
|
hash = dawnInfo.${system}.hash;
|
||||||
stripRoot = false;
|
stripRoot = false;
|
||||||
};
|
};
|
||||||
@@ -94,7 +94,7 @@
|
|||||||
owner = "encounter";
|
owner = "encounter";
|
||||||
repo = "nod";
|
repo = "nod";
|
||||||
rev = nodVersion;
|
rev = nodVersion;
|
||||||
hash = "sha256-+zrtVzjo0+X/6uMcNUn1+FaSR+jOhrcQSDNBFjw0NDs=";
|
hash = "sha256-r8qDlOVxv5iKiFjJQrcBuL9HVoOM3yEjRVnQIMqaICs=";
|
||||||
};
|
};
|
||||||
patches = [ ./fix-cmake-paths.patch ];
|
patches = [ ./fix-cmake-paths.patch ];
|
||||||
cargoDeps = pkgs.rustPlatform.importCargoLock {
|
cargoDeps = pkgs.rustPlatform.importCargoLock {
|
||||||
@@ -141,12 +141,12 @@
|
|||||||
XXHASH = pkgs.xxhash.src;
|
XXHASH = pkgs.xxhash.src;
|
||||||
ZSTD = pkgs.zstd.src;
|
ZSTD = pkgs.zstd.src;
|
||||||
FMT = pkgs.fetchzip {
|
FMT = pkgs.fetchzip {
|
||||||
url = "https://github.com/fmtlib/fmt/archive/refs/tags/11.1.4.tar.gz";
|
url = "https://github.com/fmtlib/fmt/archive/refs/tags/12.1.0.tar.gz";
|
||||||
hash = "sha256-sUbxlYi/Aupaox3JjWFqXIjcaQa0LFjclQAOleT+FRA=";
|
hash = "sha256-ZmI1Dv0ZabPlxa02OpERI47jp7zFfjpeWCy1WyuPYZ0=";
|
||||||
};
|
};
|
||||||
TRACY = pkgs.fetchzip {
|
TRACY = pkgs.fetchzip {
|
||||||
url = "https://github.com/wolfpld/tracy/archive/a64b9a20294d59421a2f57aeca3c6383d8c48169.tar.gz";
|
url = "https://github.com/wolfpld/tracy/archive/6789e7d6f9a65ec98926b602097a33a9676d2606.tar.gz";
|
||||||
hash = "sha256-hbNGOsGeyGSvCJ2No8RkwOib1lX2on3vNZSzyVkZdXw=";
|
hash = "sha256-Xxyd7G/mnXEPpN+ehmwl0AkAhS3CwObpJNDgcqbdUJg=";
|
||||||
};
|
};
|
||||||
IMGUI = pkgs.fetchFromGitHub {
|
IMGUI = pkgs.fetchFromGitHub {
|
||||||
owner = "ocornut";
|
owner = "ocornut";
|
||||||
@@ -269,6 +269,12 @@
|
|||||||
runHook postInstall
|
runHook postInstall
|
||||||
'';
|
'';
|
||||||
|
|
||||||
|
postFixup = lib.optionalString (!isDarwin) ''
|
||||||
|
patchelf \
|
||||||
|
--add-needed "${pkgs.vulkan-loader}/lib/libvulkan.so" \
|
||||||
|
$out/bin/dusklight
|
||||||
|
'';
|
||||||
|
|
||||||
dontStrip = true;
|
dontStrip = true;
|
||||||
|
|
||||||
meta = {
|
meta = {
|
||||||
|
|||||||
@@ -88,9 +88,14 @@ public:
|
|||||||
/* 0x396A */ u8 field_0x396A[0x399E - 0x396A];
|
/* 0x396A */ u8 field_0x396A[0x399E - 0x396A];
|
||||||
/* 0x399E */ s16 field_0x399e;
|
/* 0x399E */ s16 field_0x399e;
|
||||||
/* 0x39A0 */ u8 field_0x39A0[0x39A4 - 0x39A0];
|
/* 0x39A0 */ u8 field_0x39A0[0x39A4 - 0x39A0];
|
||||||
|
#if TARGET_PC
|
||||||
|
/* 0x39A4 */ cM_rnd_c mMantRng;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
#if TARGET_PC
|
||||||
|
STATIC_ASSERT(sizeof(mant_class) == 0x39ac);
|
||||||
|
#else
|
||||||
STATIC_ASSERT(sizeof(mant_class) == 0x39a4);
|
STATIC_ASSERT(sizeof(mant_class) == 0x39a4);
|
||||||
|
#endif
|
||||||
|
|
||||||
#endif /* D_A_MANT_H */
|
#endif /* D_A_MANT_H */
|
||||||
|
|||||||
@@ -218,6 +218,7 @@ private:
|
|||||||
bool mCursorInterpPrevAngular;
|
bool mCursorInterpPrevAngular;
|
||||||
bool mCursorInterpCurrAngular;
|
bool mCursorInterpCurrAngular;
|
||||||
bool mCursorInterpInit;
|
bool mCursorInterpInit;
|
||||||
|
bool mPointerTouchPressHoveredCurrent;
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -360,7 +360,12 @@ inline void dMsgObject_demoMessageGroup() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool dMsgObject_isTalkNowCheck() {
|
inline bool dMsgObject_isTalkNowCheck() {
|
||||||
|
#if TARGET_PC
|
||||||
|
dMsgObject_c* msgObject = dMsgObject_getMsgObjectClass();
|
||||||
|
return msgObject != NULL && msgObject->getStatus() != 1;
|
||||||
|
#else
|
||||||
return dMsgObject_getMsgObjectClass()->getStatus() == 1 ? false : true;
|
return dMsgObject_getMsgObjectClass()->getStatus() == 1 ? false : true;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
inline bool dMsgObject_isKillMessageFlag() {
|
inline bool dMsgObject_isKillMessageFlag() {
|
||||||
@@ -497,7 +502,12 @@ inline void dMsgObject_onMsgSend() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline bool dMsgObject_isFukidashiCheck() {
|
inline bool dMsgObject_isFukidashiCheck() {
|
||||||
|
#if TARGET_PC
|
||||||
|
dMsgObject_c* msgObject = dMsgObject_getMsgObjectClass();
|
||||||
|
return msgObject != NULL && msgObject->getScrnDrawPtr() != NULL;
|
||||||
|
#else
|
||||||
return dMsgObject_getMsgObjectClass()->getScrnDrawPtr() == NULL ? false : true;
|
return dMsgObject_getMsgObjectClass()->getScrnDrawPtr() == NULL ? false : true;
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
inline void* dMsgObject_getTalkHeap() {
|
inline void* dMsgObject_getTalkHeap() {
|
||||||
|
|||||||
@@ -6,6 +6,9 @@ class CPaneMgr;
|
|||||||
|
|
||||||
namespace dusk::menu_pointer {
|
namespace dusk::menu_pointer {
|
||||||
|
|
||||||
|
using TargetId = u16;
|
||||||
|
constexpr TargetId InvalidTarget = 0xffff;
|
||||||
|
|
||||||
enum class Context {
|
enum class Context {
|
||||||
None,
|
None,
|
||||||
FileSelect,
|
FileSelect,
|
||||||
@@ -43,12 +46,14 @@ bool active() noexcept;
|
|||||||
bool enabled() noexcept;
|
bool enabled() noexcept;
|
||||||
bool mouse_capture_active() noexcept;
|
bool mouse_capture_active() noexcept;
|
||||||
const State& state() noexcept;
|
const State& state() noexcept;
|
||||||
|
void set_hover_target(TargetId target) noexcept;
|
||||||
bool consume_click() noexcept;
|
bool consume_click() noexcept;
|
||||||
|
bool peek_click() noexcept;
|
||||||
void set_dialog_choice(u8 choice, bool clicked) noexcept;
|
void set_dialog_choice(u8 choice, bool clicked) noexcept;
|
||||||
bool get_dialog_choice(u8& choice) noexcept;
|
bool get_dialog_choice(u8& choice) noexcept;
|
||||||
bool consume_dialog_click(u8& choice) noexcept;
|
bool consume_dialog_click(u8& choice) noexcept;
|
||||||
void defer_activation(Context context, u8 target) noexcept;
|
void defer_activation(Context context, TargetId target) noexcept;
|
||||||
bool consume_deferred_activation(Context context, u8 target) noexcept;
|
bool consume_deferred_activation(Context context, TargetId target) noexcept;
|
||||||
void clear_deferred_activation(Context context) noexcept;
|
void clear_deferred_activation(Context context) noexcept;
|
||||||
u32 suppressed_pad_buttons(u32 port) noexcept;
|
u32 suppressed_pad_buttons(u32 port) noexcept;
|
||||||
void finish_pad_suppression_read(u32 port) noexcept;
|
void finish_pad_suppression_read(u32 port) noexcept;
|
||||||
|
|||||||
@@ -4,9 +4,9 @@
|
|||||||
|
|
||||||
namespace dusk::mouse {
|
namespace dusk::mouse {
|
||||||
void read();
|
void read();
|
||||||
void getAimDeltas(float& out_yaw, float& out_pitch);
|
void get_aim_deltas(float& out_yaw, float& out_pitch);
|
||||||
void getCameraDeltas(float& out_yaw, float& out_pitch);
|
void get_camera_deltas(float& out_yaw, float& out_pitch);
|
||||||
void handle_event(const SDL_Event& event) noexcept;
|
void handle_event(const SDL_Event& event) noexcept;
|
||||||
void onFocusLost();
|
void on_focus_lost();
|
||||||
void onFocusGained();
|
void on_focus_gained();
|
||||||
} // namespace dusk::mouse
|
} // namespace dusk::mouse
|
||||||
|
|||||||
+13
-1
@@ -46,6 +46,12 @@ enum class FrameInterpMode : u8 {
|
|||||||
Unlimited = 2,
|
Unlimited = 2,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class TouchTargeting : u8 {
|
||||||
|
Hybrid = 0,
|
||||||
|
Hold = 1,
|
||||||
|
Switch = 2,
|
||||||
|
};
|
||||||
|
|
||||||
enum class MenuScaling : u8 {
|
enum class MenuScaling : u8 {
|
||||||
GameCube = 0,
|
GameCube = 0,
|
||||||
Wii = 1,
|
Wii = 1,
|
||||||
@@ -97,6 +103,12 @@ struct ConfigEnumRange<FrameInterpMode> {
|
|||||||
static constexpr auto max = FrameInterpMode::Unlimited;
|
static constexpr auto max = FrameInterpMode::Unlimited;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <>
|
||||||
|
struct ConfigEnumRange<TouchTargeting> {
|
||||||
|
static constexpr auto min = TouchTargeting::Hybrid;
|
||||||
|
static constexpr auto max = TouchTargeting::Switch;
|
||||||
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
struct ConfigEnumRange<MenuScaling> {
|
struct ConfigEnumRange<MenuScaling> {
|
||||||
static constexpr auto min = MenuScaling::GameCube;
|
static constexpr auto min = MenuScaling::GameCube;
|
||||||
@@ -216,6 +228,7 @@ struct UserSettings {
|
|||||||
ConfigVar<bool> invertMouseY;
|
ConfigVar<bool> invertMouseY;
|
||||||
ConfigVar<bool> freeCamera;
|
ConfigVar<bool> freeCamera;
|
||||||
ConfigVar<bool> enableTouchControls;
|
ConfigVar<bool> enableTouchControls;
|
||||||
|
ConfigVar<TouchTargeting> touchTargeting;
|
||||||
ConfigVar<bool> enableMenuPointer;
|
ConfigVar<bool> enableMenuPointer;
|
||||||
ConfigVar<ui::ControlLayout> touchControlsLayout;
|
ConfigVar<ui::ControlLayout> touchControlsLayout;
|
||||||
ConfigVar<bool> invertCameraXAxis;
|
ConfigVar<bool> invertCameraXAxis;
|
||||||
@@ -275,7 +288,6 @@ struct UserSettings {
|
|||||||
ConfigVar<DiscVerificationState> isoVerification;
|
ConfigVar<DiscVerificationState> isoVerification;
|
||||||
ConfigVar<std::string> graphicsBackend;
|
ConfigVar<std::string> graphicsBackend;
|
||||||
ConfigVar<bool> skipPreLaunchUI;
|
ConfigVar<bool> skipPreLaunchUI;
|
||||||
ConfigVar<bool> showPipelineCompilation;
|
|
||||||
ConfigVar<bool> wasPresetChosen;
|
ConfigVar<bool> wasPresetChosen;
|
||||||
ConfigVar<bool> checkForUpdates;
|
ConfigVar<bool> checkForUpdates;
|
||||||
ConfigVar<int> cardFileType;
|
ConfigVar<int> cardFileType;
|
||||||
|
|||||||
@@ -37,5 +37,6 @@ struct SpeedrunInfo {
|
|||||||
extern SpeedrunInfo m_speedrunInfo;
|
extern SpeedrunInfo m_speedrunInfo;
|
||||||
|
|
||||||
void resetForSpeedrunMode();
|
void resetForSpeedrunMode();
|
||||||
|
void restoreFromSpeedrunMode();
|
||||||
|
|
||||||
} // namespace dusk
|
} // namespace dusk
|
||||||
|
|||||||
+52
-2
@@ -21,6 +21,7 @@ body {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fps,
|
fps,
|
||||||
|
pipeline-progress,
|
||||||
toast {
|
toast {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
border: 1dp #92875B;
|
border: 1dp #92875B;
|
||||||
@@ -98,7 +99,7 @@ toast message row.muted {
|
|||||||
opacity: 0.5;
|
opacity: 0.5;
|
||||||
}
|
}
|
||||||
|
|
||||||
toast progress {
|
progress {
|
||||||
height: 4dp;
|
height: 4dp;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
left: 0;
|
left: 0;
|
||||||
@@ -106,10 +107,50 @@ toast progress {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
}
|
}
|
||||||
|
|
||||||
toast progress fill {
|
progress fill {
|
||||||
background-color: rgba(194, 164, 45, 80%);
|
background-color: rgba(194, 164, 45, 80%);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pipeline-progress {
|
||||||
|
left: 12dp;
|
||||||
|
bottom: 12dp;
|
||||||
|
display: flex;
|
||||||
|
flex-flow: column;
|
||||||
|
z-index: 100;
|
||||||
|
min-width: 260dp;
|
||||||
|
max-width: 90%;
|
||||||
|
padding: 10dp 16dp 12dp;
|
||||||
|
border-radius: 7dp;
|
||||||
|
overflow: hidden;
|
||||||
|
filter: opacity(0);
|
||||||
|
transition: filter 0.2s linear-in-out;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
pipeline-progress[open] {
|
||||||
|
filter: opacity(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
pipeline-status {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
gap: 8dp;
|
||||||
|
font-size: 18dp;
|
||||||
|
font-weight: normal;
|
||||||
|
white-space: nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
icon.pipeline-spinner {
|
||||||
|
width: 1.2em;
|
||||||
|
height: 1.2em;
|
||||||
|
line-height: 1.2em;
|
||||||
|
font-size: 1.2em;
|
||||||
|
color: #C2A42D;
|
||||||
|
text-align: center;
|
||||||
|
transform-origin: center;
|
||||||
|
animation: 1s linear infinite pipeline-spinner-spin;
|
||||||
|
}
|
||||||
|
|
||||||
toast.achievement {
|
toast.achievement {
|
||||||
border: 1dp #C2A42D;
|
border: 1dp #C2A42D;
|
||||||
}
|
}
|
||||||
@@ -310,6 +351,15 @@ logo img.outer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@keyframes pipeline-spinner-spin {
|
||||||
|
from {
|
||||||
|
transform: rotate(0deg);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@media (max-height: 640dp) {
|
@media (max-height: 640dp) {
|
||||||
toast {
|
toast {
|
||||||
top: 20dp;
|
top: 20dp;
|
||||||
|
|||||||
@@ -122,19 +122,12 @@ BOOL daAlink_c::setBodyAngleToCamera() {
|
|||||||
var_f31 /= dComIfGp_getCameraZoomScale(field_0x317c);
|
var_f31 /= dComIfGp_getCameraZoomScale(field_0x317c);
|
||||||
}
|
}
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
if (dusk::getSettings().game.enableMouseAim && checkAimInputContext()) {
|
|
||||||
sp8 = mBodyAngle.x;
|
|
||||||
} else
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
shape_angle.y = shape_angle.y + (var_f31 * cM_ssin(mStickAngle) IF_DUSK(* (dusk::getSettings().game.invertFirstPersonXAxis ? -1.0f : 1.0f)));
|
shape_angle.y = shape_angle.y + (var_f31 * cM_ssin(mStickAngle) IF_DUSK(* (dusk::getSettings().game.invertFirstPersonXAxis ? -1.0f : 1.0f)));
|
||||||
sp8 = mBodyAngle.x + (var_f31 * cM_scos(mStickAngle) IF_DUSK(* (dusk::getSettings().game.invertFirstPersonYAxis ? -1.0f : 1.0f)));
|
sp8 = mBodyAngle.x + (var_f31 * cM_scos(mStickAngle) IF_DUSK(* (dusk::getSettings().game.invertFirstPersonYAxis ? -1.0f : 1.0f)));
|
||||||
|
|
||||||
if (checkNotItemSinkLimit() && sp8 > 0 && sp8 > mBodyAngle.x) {
|
if (checkNotItemSinkLimit() && sp8 > 0 && sp8 > mBodyAngle.x) {
|
||||||
sp8 = mBodyAngle.x;
|
sp8 = mBodyAngle.x;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
sp8 = mBodyAngle.x;
|
sp8 = mBodyAngle.x;
|
||||||
}
|
}
|
||||||
@@ -156,7 +149,7 @@ BOOL daAlink_c::setBodyAngleToCamera() {
|
|||||||
f32 final_yaw = 0.f;
|
f32 final_yaw = 0.f;
|
||||||
f32 final_pitch = 0.f;
|
f32 final_pitch = 0.f;
|
||||||
if (dusk::getSettings().game.enableMouseAim) {
|
if (dusk::getSettings().game.enableMouseAim) {
|
||||||
dusk::mouse::getAimDeltas(final_yaw, final_pitch);
|
dusk::mouse::get_aim_deltas(final_yaw, final_pitch);
|
||||||
}
|
}
|
||||||
if (dusk::getSettings().game.enableGyroAim) {
|
if (dusk::getSettings().game.enableGyroAim) {
|
||||||
f32 gyro_yaw = 0.f;
|
f32 gyro_yaw = 0.f;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "d/d_com_inf_game.h"
|
#include "d/d_com_inf_game.h"
|
||||||
|
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
|
#include <aurora/texture.hpp>
|
||||||
#include "dusk/dvd_asset.hpp"
|
#include "dusk/dvd_asset.hpp"
|
||||||
#include "dusk/frame_interpolation.h"
|
#include "dusk/frame_interpolation.h"
|
||||||
|
|
||||||
@@ -40,6 +41,8 @@ static f32* l_texCoord_get() { alignas(32) static f32 buf[338]; static bool _
|
|||||||
//#define l_pos (l_pos_get())
|
//#define l_pos (l_pos_get())
|
||||||
#define l_normal (l_normal_get())
|
#define l_normal (l_normal_get())
|
||||||
#define l_texCoord (l_texCoord_get())
|
#define l_texCoord (l_texCoord_get())
|
||||||
|
|
||||||
|
static bool l_Egnd_mantTEX_hasReplacement = false;
|
||||||
#else
|
#else
|
||||||
#include "assets/l_Egnd_mantTEX.h"
|
#include "assets/l_Egnd_mantTEX.h"
|
||||||
|
|
||||||
@@ -223,6 +226,7 @@ void daMant_packet_c::draw() {
|
|||||||
GXInitTexObjCI(
|
GXInitTexObjCI(
|
||||||
&undersideTexObj, l_Egnd_mantTEX_U, 0x80, 0x80, GX_TF_C8, GX_CLAMP, GX_CLAMP, 0, 0);
|
&undersideTexObj, l_Egnd_mantTEX_U, 0x80, 0x80, GX_TF_C8, GX_CLAMP, GX_CLAMP, 0, 0);
|
||||||
GXInitTexObjLOD(&undersideTexObj, GX_LINEAR, GX_LINEAR, 0.0, 0.0, 0.0, 0, 0, GX_ANISO_1);
|
GXInitTexObjLOD(&undersideTexObj, GX_LINEAR, GX_LINEAR, 0.0, 0.0, 0.0, 0, 0, GX_ANISO_1);
|
||||||
|
l_Egnd_mantTEX_hasReplacement = aurora::texture::has_replacement(&mainTexObj, &tlutObj);
|
||||||
textureObjsInitialized = true;
|
textureObjsInitialized = true;
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
@@ -636,7 +640,11 @@ static int daMant_Execute(mant_class* i_this) {
|
|||||||
iVar8 = 0;
|
iVar8 = 0;
|
||||||
|
|
||||||
if (i_this->field_0x3967 != 0) {
|
if (i_this->field_0x3967 != 0) {
|
||||||
|
#if TARGET_PC
|
||||||
|
mant_cut_type = l_Egnd_mantTEX_hasReplacement ? 1 : i_this->field_0x3967;
|
||||||
|
#else
|
||||||
mant_cut_type = i_this->field_0x3967;
|
mant_cut_type = i_this->field_0x3967;
|
||||||
|
#endif
|
||||||
|
|
||||||
if (i_this->field_0x3968 < 15) {
|
if (i_this->field_0x3968 < 15) {
|
||||||
i_this->field_0x3968++;
|
i_this->field_0x3968++;
|
||||||
@@ -648,10 +656,19 @@ static int daMant_Execute(mant_class* i_this) {
|
|||||||
iVar8 = 20;
|
iVar8 = 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if TARGET_PC
|
||||||
|
if (l_Egnd_mantTEX_hasReplacement) {
|
||||||
|
unaff_r29 = i_this->mMantRng.getF(65536.0f);
|
||||||
|
var_f31 = i_this->mMantRng.getFX(32.0f);
|
||||||
|
var_f30 = i_this->mMantRng.getFX(32.0f);
|
||||||
|
} else
|
||||||
|
#endif
|
||||||
|
{
|
||||||
unaff_r29 = cM_rndF(65536.0f);
|
unaff_r29 = cM_rndF(65536.0f);
|
||||||
var_f31 = cM_rndFX(32.0f);
|
var_f31 = cM_rndFX(32.0f);
|
||||||
var_f30 = cM_rndFX(32.0f);
|
var_f30 = cM_rndFX(32.0f);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
i_this->field_0x3967 = 0;
|
i_this->field_0x3967 = 0;
|
||||||
}
|
}
|
||||||
@@ -760,6 +777,8 @@ static int daMant_Create(fopAc_ac_c* i_this) {
|
|||||||
if(textureObjsInitialized) {
|
if(textureObjsInitialized) {
|
||||||
GXInitTlutObjData(&tlutObj, l_Egnd_mantPAL); // make sure the cached textures are updated
|
GXInitTlutObjData(&tlutObj, l_Egnd_mantPAL); // make sure the cached textures are updated
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_this->mMantRng.init(66, 16983, 855);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
lbl_277_bss_0 = 0;
|
lbl_277_bss_0 = 0;
|
||||||
|
|||||||
+5
-1
@@ -7602,6 +7602,10 @@ bool dCamera_c::executeDebugFlyCam() {
|
|||||||
sFlyCamLastMousePos = mouseValid ? io.MousePos : ImVec2{-1.0f, -1.0f};
|
sFlyCamLastMousePos = mouseValid ? io.MousePos : ImVec2{-1.0f, -1.0f};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (dusk::getSettings().game.enableMirrorMode) {
|
||||||
|
stickX *= -1.0f;
|
||||||
|
}
|
||||||
|
|
||||||
f32 verticalDisp = 0.0f;
|
f32 verticalDisp = 0.0f;
|
||||||
if (trigR >= FLYCAM_TRIGGER_DEADZONE) {
|
if (trigR >= FLYCAM_TRIGGER_DEADZONE) {
|
||||||
verticalDisp += trigR;
|
verticalDisp += trigR;
|
||||||
@@ -7712,7 +7716,7 @@ bool dCamera_c::freeCamera() {
|
|||||||
|
|
||||||
f32 yaw_rad = 0.0f;
|
f32 yaw_rad = 0.0f;
|
||||||
f32 pitch_rad = 0.0f;
|
f32 pitch_rad = 0.0f;
|
||||||
dusk::mouse::getCameraDeltas(yaw_rad, pitch_rad);
|
dusk::mouse::get_camera_deltas(yaw_rad, pitch_rad);
|
||||||
if (dusk::getSettings().game.enableMouseCamera && (yaw_rad != 0.0f || pitch_rad != 0.0f) &&
|
if (dusk::getSettings().game.enableMouseCamera && (yaw_rad != 0.0f || pitch_rad != 0.0f) &&
|
||||||
!dComIfGp_checkCameraAttentionStatus(dComIfGp_getPlayerCameraID(0), 0x8))
|
!dComIfGp_checkCameraAttentionStatus(dComIfGp_getPlayerCameraID(0), 0x8))
|
||||||
{
|
{
|
||||||
|
|||||||
+20
-9
@@ -777,6 +777,7 @@ bool dFile_select_c::pointerDataSelect() {
|
|||||||
if (!dusk::menu_pointer::hit_pane(mSelFilePanes[i], 8.0f)) {
|
if (!dusk::menu_pointer::hit_pane(mSelFilePanes[i], 8.0f)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
dusk::menu_pointer::set_hover_target(pointer_target(s_pointerDataSelectTarget, i));
|
||||||
const bool clicked = dusk::menu_pointer::consume_click();
|
const bool clicked = dusk::menu_pointer::consume_click();
|
||||||
if (mSelectNum != i) {
|
if (mSelectNum != i) {
|
||||||
mDoAud_seStart(Z2SE_FILE_SELECT_CURSOR, NULL, 0, 0);
|
mDoAud_seStart(Z2SE_FILE_SELECT_CURSOR, NULL, 0, 0);
|
||||||
@@ -805,6 +806,7 @@ bool dFile_select_c::pointerMenuSelect() {
|
|||||||
if (!dusk::menu_pointer::hit_pane(m3mSelPane[i], 8.0f)) {
|
if (!dusk::menu_pointer::hit_pane(m3mSelPane[i], 8.0f)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
dusk::menu_pointer::set_hover_target(pointer_target(s_pointerMenuSelectTarget, i));
|
||||||
const bool clicked = dusk::menu_pointer::consume_click();
|
const bool clicked = dusk::menu_pointer::consume_click();
|
||||||
if (!mIsDataNew[mSelectNum] && mSelectMenuNum != i) {
|
if (!mIsDataNew[mSelectNum] && mSelectMenuNum != i) {
|
||||||
mDoAud_seStart(Z2SE_SY_MENU_CURSOR_COMMON, NULL, 0, 0);
|
mDoAud_seStart(Z2SE_SY_MENU_CURSOR_COMMON, NULL, 0, 0);
|
||||||
@@ -833,6 +835,7 @@ bool dFile_select_c::pointerCopyDataToSelect() {
|
|||||||
if (!dusk::menu_pointer::hit_pane(mCpSelPane[i], 8.0f)) {
|
if (!dusk::menu_pointer::hit_pane(mCpSelPane[i], 8.0f)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
dusk::menu_pointer::set_hover_target(pointer_target(s_pointerCopySelectTarget, i));
|
||||||
const bool clicked = dusk::menu_pointer::consume_click();
|
const bool clicked = dusk::menu_pointer::consume_click();
|
||||||
if (field_0x026b != i) {
|
if (field_0x026b != i) {
|
||||||
mDoAud_seStart(Z2SE_FILE_SELECT_CURSOR, NULL, 0, 0);
|
mDoAud_seStart(Z2SE_FILE_SELECT_CURSOR, NULL, 0, 0);
|
||||||
@@ -861,6 +864,7 @@ bool dFile_select_c::pointerYesNoSelect(bool errorSelect) {
|
|||||||
if (!dusk::menu_pointer::hit_pane(mYnSelPane[i], 8.0f)) {
|
if (!dusk::menu_pointer::hit_pane(mYnSelPane[i], 8.0f)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
dusk::menu_pointer::set_hover_target(pointer_target(s_pointerYesNoSelectTarget, i));
|
||||||
const bool clicked =
|
const bool clicked =
|
||||||
(!errorSelect || field_0x0268 == i) && dusk::menu_pointer::consume_click();
|
(!errorSelect || field_0x0268 == i) && dusk::menu_pointer::consume_click();
|
||||||
if (field_0x0268 != i) {
|
if (field_0x0268 != i) {
|
||||||
@@ -1103,13 +1107,14 @@ void dFile_select_c::dataSelectAnmSet() {
|
|||||||
void dFile_select_c::dataSelectMoveAnime() {
|
void dFile_select_c::dataSelectMoveAnime() {
|
||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::FileSelect);
|
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::FileSelect);
|
||||||
if (mSelectNum != 0xFF && dusk::menu_pointer::hit_pane(mSelFilePanes[mSelectNum], 8.0f) &&
|
if (mSelectNum != 0xFF && dusk::menu_pointer::hit_pane(mSelFilePanes[mSelectNum], 8.0f)) {
|
||||||
dusk::menu_pointer::consume_click())
|
dusk::menu_pointer::set_hover_target(pointer_target(s_pointerDataSelectTarget, mSelectNum));
|
||||||
{
|
if (dusk::menu_pointer::consume_click()) {
|
||||||
dusk::menu_pointer::defer_activation(
|
dusk::menu_pointer::defer_activation(
|
||||||
dusk::menu_pointer::Context::FileSelect,
|
dusk::menu_pointer::Context::FileSelect,
|
||||||
pointer_target(s_pointerDataSelectTarget, mSelectNum));
|
pointer_target(s_pointerDataSelectTarget, mSelectNum));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
bool iVar7 = true;
|
bool iVar7 = true;
|
||||||
bool iVar6 = true;
|
bool iVar6 = true;
|
||||||
@@ -1494,13 +1499,15 @@ void dFile_select_c::menuSelectMoveAnm() {
|
|||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::FileSelect);
|
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::FileSelect);
|
||||||
if (mSelectMenuNum != 0xFF &&
|
if (mSelectMenuNum != 0xFF &&
|
||||||
dusk::menu_pointer::hit_pane(m3mSelPane[mSelectMenuNum], 8.0f) &&
|
dusk::menu_pointer::hit_pane(m3mSelPane[mSelectMenuNum], 8.0f))
|
||||||
dusk::menu_pointer::consume_click())
|
|
||||||
{
|
{
|
||||||
|
dusk::menu_pointer::set_hover_target(pointer_target(s_pointerMenuSelectTarget, mSelectMenuNum));
|
||||||
|
if (dusk::menu_pointer::consume_click()) {
|
||||||
dusk::menu_pointer::defer_activation(
|
dusk::menu_pointer::defer_activation(
|
||||||
dusk::menu_pointer::Context::FileSelect,
|
dusk::menu_pointer::Context::FileSelect,
|
||||||
pointer_target(s_pointerMenuSelectTarget, mSelectMenuNum));
|
pointer_target(s_pointerMenuSelectTarget, mSelectMenuNum));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
bool tmp1 = true;
|
bool tmp1 = true;
|
||||||
|
|
||||||
@@ -1997,13 +2004,15 @@ void dFile_select_c::copyDataToSelectMoveAnm() {
|
|||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::FileSelect);
|
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::FileSelect);
|
||||||
if (field_0x026b != 0xFF &&
|
if (field_0x026b != 0xFF &&
|
||||||
dusk::menu_pointer::hit_pane(mCpSelPane[field_0x026b], 8.0f) &&
|
dusk::menu_pointer::hit_pane(mCpSelPane[field_0x026b], 8.0f))
|
||||||
dusk::menu_pointer::consume_click())
|
|
||||||
{
|
{
|
||||||
|
dusk::menu_pointer::set_hover_target(pointer_target(s_pointerCopySelectTarget, field_0x026b));
|
||||||
|
if (dusk::menu_pointer::consume_click()) {
|
||||||
dusk::menu_pointer::defer_activation(
|
dusk::menu_pointer::defer_activation(
|
||||||
dusk::menu_pointer::Context::FileSelect,
|
dusk::menu_pointer::Context::FileSelect,
|
||||||
pointer_target(s_pointerCopySelectTarget, field_0x026b));
|
pointer_target(s_pointerCopySelectTarget, field_0x026b));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
bool iVar7 = true;
|
bool iVar7 = true;
|
||||||
bool iVar6 = true;
|
bool iVar6 = true;
|
||||||
@@ -2522,13 +2531,15 @@ void dFile_select_c::yesNoCursorMoveAnm() {
|
|||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::FileSelect);
|
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::FileSelect);
|
||||||
if (field_0x0268 != 0xFF &&
|
if (field_0x0268 != 0xFF &&
|
||||||
dusk::menu_pointer::hit_pane(mYnSelPane[field_0x0268], 8.0f) &&
|
dusk::menu_pointer::hit_pane(mYnSelPane[field_0x0268], 8.0f))
|
||||||
dusk::menu_pointer::consume_click())
|
|
||||||
{
|
{
|
||||||
|
dusk::menu_pointer::set_hover_target(pointer_target(s_pointerYesNoSelectTarget, field_0x0268));
|
||||||
|
if (dusk::menu_pointer::consume_click()) {
|
||||||
dusk::menu_pointer::defer_activation(
|
dusk::menu_pointer::defer_activation(
|
||||||
dusk::menu_pointer::Context::FileSelect,
|
dusk::menu_pointer::Context::FileSelect,
|
||||||
pointer_target(s_pointerYesNoSelectTarget, field_0x0268));
|
pointer_target(s_pointerYesNoSelectTarget, field_0x0268));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
bool isYnSelMove = yesnoSelectMoveAnm();
|
bool isYnSelMove = yesnoSelectMoveAnm();
|
||||||
bool isYnWakuAlpha = yesnoWakuAlpahAnm(field_0x0269);
|
bool isYnWakuAlpha = yesnoWakuAlpahAnm(field_0x0269);
|
||||||
|
|||||||
@@ -1960,6 +1960,7 @@ bool dMenu_Collect2D_c::pointerWait() {
|
|||||||
if (getItemTag(x, y, true) == 0 || !dusk::menu_pointer::hit_pane(mpSelPm[x][y], 8.0f)) {
|
if (getItemTag(x, y, true) == 0 || !dusk::menu_pointer::hit_pane(mpSelPm[x][y], 8.0f)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
dusk::menu_pointer::set_hover_target(static_cast<dusk::menu_pointer::TargetId>(x + y * 7));
|
||||||
if (mCursorX != x || mCursorY != y) {
|
if (mCursorX != x || mCursorY != y) {
|
||||||
mDoAud_seStart(Z2SE_SY_MENU_CURSOR_COMMON, NULL, 0, 0);
|
mDoAud_seStart(Z2SE_SY_MENU_CURSOR_COMMON, NULL, 0, 0);
|
||||||
mCursorX = x;
|
mCursorX = x;
|
||||||
|
|||||||
+19
-11
@@ -426,7 +426,15 @@ void dMenu_Fmap2DBack_c::draw() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
mpPointParent->setAlphaRate(mArrowAlpha * mSpotTextureFadeAlpha);
|
mpPointParent->setAlphaRate(mArrowAlpha * mSpotTextureFadeAlpha);
|
||||||
mpPointParent->translate(mArrowPos2DX + mTransX, mArrowPos2DY + mTransZ);
|
|
||||||
|
f32 drawX = mArrowPos2DX + mTransX;
|
||||||
|
#ifdef TARGET_PC
|
||||||
|
if (dusk::getSettings().game.enableMirrorMode) {
|
||||||
|
drawX = getMirrorPosX(drawX, 0.0f);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
mpPointParent->translate(drawX, mArrowPos2DY + mTransZ);
|
||||||
mpPointScreen->draw(0.0f, 0.0f, grafPort);
|
mpPointScreen->draw(0.0f, 0.0f, grafPort);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1005,6 +1013,11 @@ void dMenu_Fmap2DBack_c::allmap_move2(STControl* param_0) {
|
|||||||
f32 stickValue = param_0->getValueStick();
|
f32 stickValue = param_0->getValueStick();
|
||||||
if (stickValue >= spC) {
|
if (stickValue >= spC) {
|
||||||
s16 angle = param_0->getAngleStick();
|
s16 angle = param_0->getAngleStick();
|
||||||
|
#ifdef TARGET_PC
|
||||||
|
if (dusk::getSettings().game.enableMirrorMode) {
|
||||||
|
angle = -angle;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
f32 local_68 = (mTexMaxX - mTexMinX);
|
f32 local_68 = (mTexMaxX - mTexMinX);
|
||||||
f32 zoomRate = local_68 / getAllMapZoomRate();
|
f32 zoomRate = local_68 / getAllMapZoomRate();
|
||||||
f32 sp24;
|
f32 sp24;
|
||||||
@@ -1046,11 +1059,6 @@ void dMenu_Fmap2DBack_c::allmap_move2(STControl* param_0) {
|
|||||||
calcAllMapPos2D((mArrowPos3DX + control_xpos) - mStageTransX,
|
calcAllMapPos2D((mArrowPos3DX + control_xpos) - mStageTransX,
|
||||||
(mArrowPos3DZ + control_ypos) - mStageTransZ, &sp14, &sp10);
|
(mArrowPos3DZ + control_ypos) - mStageTransZ, &sp14, &sp10);
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
if (dusk::getSettings().game.enableMirrorMode) {
|
|
||||||
sp14 = getMirrorPosX(sp14, 0.0f);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
mSelectRegion = 0xff;
|
mSelectRegion = 0xff;
|
||||||
for (int i = 7; i >= 0; i--) {
|
for (int i = 7; i >= 0; i--) {
|
||||||
@@ -1907,6 +1915,11 @@ void dMenu_Fmap2DBack_c::regionMapMove(STControl* i_stick) {
|
|||||||
f32 stick_value = i_stick->getValueStick();
|
f32 stick_value = i_stick->getValueStick();
|
||||||
if (stick_value >= slow_bound) {
|
if (stick_value >= slow_bound) {
|
||||||
s16 angle = i_stick->getAngleStick();
|
s16 angle = i_stick->getAngleStick();
|
||||||
|
#ifdef TARGET_PC
|
||||||
|
if (dusk::getSettings().game.enableMirrorMode) {
|
||||||
|
angle = -angle;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
f32 local_68 = mTexMaxX - mTexMinX;
|
f32 local_68 = mTexMaxX - mTexMinX;
|
||||||
f32 spot_zoom = getSpotMapZoomRate();
|
f32 spot_zoom = getSpotMapZoomRate();
|
||||||
f32 region_zoom = getRegionMapZoomRate(mRegionCursor);
|
f32 region_zoom = getRegionMapZoomRate(mRegionCursor);
|
||||||
@@ -1946,11 +1959,6 @@ void dMenu_Fmap2DBack_c::regionMapMove(STControl* i_stick) {
|
|||||||
calcAllMapPos2D(mArrowPos3DX + control_xpos - mStageTransX,
|
calcAllMapPos2D(mArrowPos3DX + control_xpos - mStageTransX,
|
||||||
mArrowPos3DZ + control_ypos - mStageTransZ, &pos_x, &pos_y);
|
mArrowPos3DZ + control_ypos - mStageTransZ, &pos_x, &pos_y);
|
||||||
|
|
||||||
#if TARGET_PC
|
|
||||||
if (dusk::getSettings().game.enableMirrorMode) {
|
|
||||||
pos_x = getMirrorPosX(pos_x, 0.0f);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
mSelectRegion = 0xff;
|
mSelectRegion = 0xff;
|
||||||
int region = mRegionCursor;
|
int region = mRegionCursor;
|
||||||
|
|||||||
@@ -320,6 +320,7 @@ bool dMenu_Insect_c::pointerWait() {
|
|||||||
if (!isGetInsect(x, y) || !dusk::menu_pointer::hit_pane(mpINSParent[index], 8.0f)) {
|
if (!isGetInsect(x, y) || !dusk::menu_pointer::hit_pane(mpINSParent[index], 8.0f)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
dusk::menu_pointer::set_hover_target(index);
|
||||||
|
|
||||||
if (field_0xf4 != x || field_0xf5 != y) {
|
if (field_0xf4 != x || field_0xf5 != y) {
|
||||||
field_0xf4 = x;
|
field_0xf4 = x;
|
||||||
|
|||||||
@@ -482,6 +482,7 @@ bool dMenu_Letter_c::pointerWait() {
|
|||||||
if (!dusk::menu_pointer::hit_pane(mpLetterParent[i], 8.0f)) {
|
if (!dusk::menu_pointer::hit_pane(mpLetterParent[i], 8.0f)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
dusk::menu_pointer::set_hover_target(i);
|
||||||
|
|
||||||
if (mIndex != i) {
|
if (mIndex != i) {
|
||||||
mIndex = i;
|
mIndex = i;
|
||||||
|
|||||||
+45
-5
@@ -83,6 +83,12 @@ enum SelectType {
|
|||||||
SelectType8,
|
SelectType8,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#if TARGET_PC
|
||||||
|
static dusk::menu_pointer::TargetId option_yes_no_target(u8 index) noexcept {
|
||||||
|
return static_cast<dusk::menu_pointer::TargetId>(0x100 + index);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
dMenu_Option_c::dMenu_Option_c(JKRArchive* i_archive, STControl* i_stick) {
|
dMenu_Option_c::dMenu_Option_c(JKRArchive* i_archive, STControl* i_stick) {
|
||||||
mUseFlag = 0;
|
mUseFlag = 0;
|
||||||
mBarScale[0] = g_drawHIO.mOptionScreen.mBarScale[0];
|
mBarScale[0] = g_drawHIO.mOptionScreen.mBarScale[0];
|
||||||
@@ -1098,18 +1104,28 @@ void dMenu_Option_c::confirm_move_move() {
|
|||||||
if (!dusk::menu_pointer::hit_pane(mpYesNoSelBase_c[i], 8.0f)) {
|
if (!dusk::menu_pointer::hit_pane(mpYesNoSelBase_c[i], 8.0f)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
dusk::menu_pointer::set_hover_target(option_yes_no_target(i));
|
||||||
|
const bool clicked = dusk::menu_pointer::consume_click();
|
||||||
if (field_0x3f9 != i) {
|
if (field_0x3f9 != i) {
|
||||||
Z2GetAudioMgr()->seStart(Z2SE_SY_MENU_CURSOR_COMMON, NULL, 0, 0, 1.0f, 1.0f, -1.0f,
|
Z2GetAudioMgr()->seStart(Z2SE_SY_MENU_CURSOR_COMMON, NULL, 0, 0, 1.0f, 1.0f, -1.0f,
|
||||||
-1.0f, 0);
|
-1.0f, 0);
|
||||||
field_0x3fa = field_0x3f9;
|
field_0x3fa = field_0x3f9;
|
||||||
field_0x3f9 = i;
|
field_0x3f9 = i;
|
||||||
|
if (clicked) {
|
||||||
|
yesNoSelectStart();
|
||||||
|
field_0x3ef = SelectType7;
|
||||||
|
dMeter2Info_set2DVibrationM();
|
||||||
|
mpWarning->_move();
|
||||||
|
setAnimation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
yesnoSelectAnmSet();
|
yesnoSelectAnmSet();
|
||||||
field_0x3ef = SelectType6;
|
field_0x3ef = SelectType6;
|
||||||
mpWarning->_move();
|
mpWarning->_move();
|
||||||
setAnimation();
|
setAnimation();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (dusk::menu_pointer::consume_click()) {
|
if (clicked) {
|
||||||
yesNoSelectStart();
|
yesNoSelectStart();
|
||||||
field_0x3ef = SelectType7;
|
field_0x3ef = SelectType7;
|
||||||
dMeter2Info_set2DVibrationM();
|
dMeter2Info_set2DVibrationM();
|
||||||
@@ -1156,11 +1172,36 @@ void dMenu_Option_c::confirm_select_init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void dMenu_Option_c::confirm_select_move() {
|
void dMenu_Option_c::confirm_select_move() {
|
||||||
|
#if TARGET_PC
|
||||||
|
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::Options);
|
||||||
|
if (field_0x3f9 != 0xff &&
|
||||||
|
dusk::menu_pointer::hit_pane(mpYesNoSelBase_c[field_0x3f9], 8.0f))
|
||||||
|
{
|
||||||
|
const dusk::menu_pointer::TargetId target = option_yes_no_target(field_0x3f9);
|
||||||
|
dusk::menu_pointer::set_hover_target(target);
|
||||||
|
if (dusk::menu_pointer::consume_click()) {
|
||||||
|
dusk::menu_pointer::defer_activation(dusk::menu_pointer::Context::Options, target);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
u8 selectMoveAnm = yesnoSelectMoveAnm();
|
u8 selectMoveAnm = yesnoSelectMoveAnm();
|
||||||
u8 wakuAlphaAnm = yesnoWakuAlpahAnm(field_0x3fa);
|
u8 wakuAlphaAnm = yesnoWakuAlpahAnm(field_0x3fa);
|
||||||
|
|
||||||
if (selectMoveAnm == 1 && wakuAlphaAnm == 1) {
|
if (selectMoveAnm == 1 && wakuAlphaAnm == 1) {
|
||||||
yesnoCursorShow();
|
yesnoCursorShow();
|
||||||
|
#if TARGET_PC
|
||||||
|
if (field_0x3f9 != 0xff &&
|
||||||
|
dusk::menu_pointer::consume_deferred_activation(
|
||||||
|
dusk::menu_pointer::Context::Options, option_yes_no_target(field_0x3f9)))
|
||||||
|
{
|
||||||
|
yesNoSelectStart();
|
||||||
|
field_0x3ef = SelectType7;
|
||||||
|
dMeter2Info_set2DVibrationM();
|
||||||
|
mpWarning->_move();
|
||||||
|
setAnimation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
field_0x3ef = SelectType5;
|
field_0x3ef = SelectType5;
|
||||||
}
|
}
|
||||||
mpWarning->_move();
|
mpWarning->_move();
|
||||||
@@ -2196,16 +2237,14 @@ bool dMenu_Option_c::isRumbleSupported() {
|
|||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
bool dMenu_Option_c::pointerConfirmSelect() {
|
bool dMenu_Option_c::pointerConfirmSelect() {
|
||||||
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::Options);
|
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::Options);
|
||||||
if (!dusk::menu_pointer::state().clicked) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (u8 i = 0; i < SelectType3; ++i) {
|
for (u8 i = 0; i < SelectType3; ++i) {
|
||||||
if (dusk::menu_pointer::hit_pane(mpMenuPane[i], 8.0f)) {
|
if (dusk::menu_pointer::hit_pane(mpMenuPane[i], 8.0f)) {
|
||||||
|
dusk::menu_pointer::set_hover_target(i);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dusk::menu_pointer::set_hover_target(0x200);
|
||||||
if (!dusk::menu_pointer::consume_click()) {
|
if (!dusk::menu_pointer::consume_click()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -2226,6 +2265,7 @@ bool dMenu_Option_c::dpdMenuMove() {
|
|||||||
if (!dusk::menu_pointer::hit_pane(mpMenuPane[i], 8.0f)) {
|
if (!dusk::menu_pointer::hit_pane(mpMenuPane[i], 8.0f)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
dusk::menu_pointer::set_hover_target(i);
|
||||||
if (getSelectType() != i) {
|
if (getSelectType() != i) {
|
||||||
field_0x3ef = i;
|
field_0x3ef = i;
|
||||||
setCursorPos(i);
|
setCursorPos(i);
|
||||||
|
|||||||
+23
-1
@@ -198,6 +198,7 @@ dMenu_Ring_c::dMenu_Ring_c(JKRExpHeap* i_heap, STControl* i_stick, CSTControl* i
|
|||||||
mCursorInterpPrevAngular = false;
|
mCursorInterpPrevAngular = false;
|
||||||
mCursorInterpCurrAngular = false;
|
mCursorInterpCurrAngular = false;
|
||||||
mCursorInterpInit = false;
|
mCursorInterpInit = false;
|
||||||
|
mPointerTouchPressHoveredCurrent = false;
|
||||||
#endif
|
#endif
|
||||||
for (int i = 0; i < 4; i++) {
|
for (int i = 0; i < 4; i++) {
|
||||||
field_0x674[i] = 0;
|
field_0x674[i] = 0;
|
||||||
@@ -1561,6 +1562,10 @@ bool dMenu_Ring_c::pointerMove() {
|
|||||||
if (hoveredSlot < 0) {
|
if (hoveredSlot < 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if (pointer.pressed) {
|
||||||
|
mPointerTouchPressHoveredCurrent = pointer.touch && hoveredSlot == mCurrentSlot;
|
||||||
|
}
|
||||||
|
dusk::menu_pointer::set_hover_target(static_cast<dusk::menu_pointer::TargetId>(hoveredSlot));
|
||||||
|
|
||||||
if (mCurrentSlot != hoveredSlot) {
|
if (mCurrentSlot != hoveredSlot) {
|
||||||
mDirectSelectCursorPos.x = mItemSlotPosX[mCurrentSlot];
|
mDirectSelectCursorPos.x = mItemSlotPosX[mCurrentSlot];
|
||||||
@@ -1573,10 +1578,27 @@ bool dMenu_Ring_c::pointerMove() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dusk::menu_pointer::consume_click()) {
|
const bool clickOpensExplain = !pointer.touch || mPointerTouchPressHoveredCurrent;
|
||||||
|
if (clickOpensExplain && dusk::menu_pointer::consume_click()) {
|
||||||
|
const u8 item = dComIfGs_getItem(mItemSlots[mCurrentSlot], false);
|
||||||
|
if (!dMeter2Info_isTouchKeyCheck(0xe) && openExplain(item)) {
|
||||||
|
dMeter2Info_setItemExplainWindowStatus(1);
|
||||||
|
field_0x6c4 = mCurrentSlot;
|
||||||
|
setStatus(STATUS_EXPLAIN);
|
||||||
|
dMeter2Info_set2DVibration();
|
||||||
|
setDoStatus(0);
|
||||||
|
} else {
|
||||||
|
Z2GetAudioMgr()->seStart(Z2SE_SYS_ERROR, NULL, 0, 0, 1.0f, 1.0f, -1.0f,
|
||||||
|
-1.0f, 0);
|
||||||
|
}
|
||||||
|
mPointerTouchPressHoveredCurrent = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pointer.released) {
|
||||||
|
mPointerTouchPressHoveredCurrent = false;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
+10
-4
@@ -1820,6 +1820,7 @@ bool dMenu_save_c::pointerSaveSelect() {
|
|||||||
if (!dusk::menu_pointer::hit_pane(mpSelData[i], 8.0f)) {
|
if (!dusk::menu_pointer::hit_pane(mpSelData[i], 8.0f)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
dusk::menu_pointer::set_hover_target(pointer_target(s_pointerSaveSelectTarget, i));
|
||||||
const bool clicked = dusk::menu_pointer::consume_click();
|
const bool clicked = dusk::menu_pointer::consume_click();
|
||||||
if (mSelectedFile != i) {
|
if (mSelectedFile != i) {
|
||||||
mDoAud_seStart(Z2SE_FILE_SELECT_CURSOR, NULL, 0, 0);
|
mDoAud_seStart(Z2SE_FILE_SELECT_CURSOR, NULL, 0, 0);
|
||||||
@@ -1848,6 +1849,7 @@ bool dMenu_save_c::pointerYesNoSelect(bool errorSelect, u8 errParam, u8 soundPar
|
|||||||
if (!dusk::menu_pointer::hit_pane(mpNoYes[i], 8.0f)) {
|
if (!dusk::menu_pointer::hit_pane(mpNoYes[i], 8.0f)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
dusk::menu_pointer::set_hover_target(pointer_target(s_pointerYesNoSelectTarget, i));
|
||||||
const bool clicked =
|
const bool clicked =
|
||||||
(!errorSelect || mYesNoCursor == i) && dusk::menu_pointer::consume_click();
|
(!errorSelect || mYesNoCursor == i) && dusk::menu_pointer::consume_click();
|
||||||
if (mYesNoCursor != i) {
|
if (mYesNoCursor != i) {
|
||||||
@@ -1952,13 +1954,15 @@ void dMenu_save_c::saveSelectMoveAnime() {
|
|||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::Save);
|
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::Save);
|
||||||
if (mSelectedFile != 0xFF &&
|
if (mSelectedFile != 0xFF &&
|
||||||
dusk::menu_pointer::hit_pane(mpSelData[mSelectedFile], 8.0f) &&
|
dusk::menu_pointer::hit_pane(mpSelData[mSelectedFile], 8.0f))
|
||||||
dusk::menu_pointer::consume_click())
|
|
||||||
{
|
{
|
||||||
|
dusk::menu_pointer::set_hover_target(pointer_target(s_pointerSaveSelectTarget, mSelectedFile));
|
||||||
|
if (dusk::menu_pointer::consume_click()) {
|
||||||
dusk::menu_pointer::defer_activation(
|
dusk::menu_pointer::defer_activation(
|
||||||
dusk::menu_pointer::Context::Save,
|
dusk::menu_pointer::Context::Save,
|
||||||
pointer_target(s_pointerSaveSelectTarget, mSelectedFile));
|
pointer_target(s_pointerSaveSelectTarget, mSelectedFile));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
bool bookWakuAnmComplete = true;
|
bool bookWakuAnmComplete = true;
|
||||||
bool selWakuAnmComplete = true;
|
bool selWakuAnmComplete = true;
|
||||||
@@ -2130,13 +2134,15 @@ void dMenu_save_c::yesNoCursorMoveAnm() {
|
|||||||
#if TARGET_PC
|
#if TARGET_PC
|
||||||
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::Save);
|
dusk::menu_pointer::begin_context(dusk::menu_pointer::Context::Save);
|
||||||
if (mYesNoCursor != 0xFF &&
|
if (mYesNoCursor != 0xFF &&
|
||||||
dusk::menu_pointer::hit_pane(mpNoYes[mYesNoCursor], 8.0f) &&
|
dusk::menu_pointer::hit_pane(mpNoYes[mYesNoCursor], 8.0f))
|
||||||
dusk::menu_pointer::consume_click())
|
|
||||||
{
|
{
|
||||||
|
dusk::menu_pointer::set_hover_target(pointer_target(s_pointerYesNoSelectTarget, mYesNoCursor));
|
||||||
|
if (dusk::menu_pointer::consume_click()) {
|
||||||
dusk::menu_pointer::defer_activation(
|
dusk::menu_pointer::defer_activation(
|
||||||
dusk::menu_pointer::Context::Save,
|
dusk::menu_pointer::Context::Save,
|
||||||
pointer_target(s_pointerYesNoSelectTarget, mYesNoCursor));
|
pointer_target(s_pointerYesNoSelectTarget, mYesNoCursor));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
bool selAnmComplete = yesnoSelectMoveAnm(0);
|
bool selAnmComplete = yesnoSelectMoveAnm(0);
|
||||||
bool wakuAnmComplete = yesnoWakuAlpahAnm(mYesNoPrevCursor);
|
bool wakuAnmComplete = yesnoWakuAlpahAnm(mYesNoPrevCursor);
|
||||||
|
|||||||
@@ -316,6 +316,7 @@ bool dMenu_Skill_c::pointerWait() {
|
|||||||
if (!dusk::menu_pointer::hit_pane(mpLetterParent[i], 8.0f)) {
|
if (!dusk::menu_pointer::hit_pane(mpLetterParent[i], 8.0f)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
dusk::menu_pointer::set_hover_target(i);
|
||||||
|
|
||||||
if (mIndex != i) {
|
if (mIndex != i) {
|
||||||
mIndex = i;
|
mIndex = i;
|
||||||
|
|||||||
@@ -437,7 +437,12 @@ void dMeter2_c::checkStatus() {
|
|||||||
|
|
||||||
field_0x128 = daPy_py_c::checkNowWolf();
|
field_0x128 = daPy_py_c::checkNowWolf();
|
||||||
|
|
||||||
|
#if TARGET_PC
|
||||||
|
dMsgObject_c* msgObject = dMsgObject_getMsgObjectClass();
|
||||||
|
if (!dComIfGp_2dShowCheck() || (msgObject != NULL && msgObject->isPlaceMessage())) {
|
||||||
|
#else
|
||||||
if (!dComIfGp_2dShowCheck() || dMsgObject_getMsgObjectClass()->isPlaceMessage()) {
|
if (!dComIfGp_2dShowCheck() || dMsgObject_getMsgObjectClass()->isPlaceMessage()) {
|
||||||
|
#endif
|
||||||
mStatus |= 0x4000;
|
mStatus |= 0x4000;
|
||||||
} else if (dComIfGp_checkPlayerStatus1(0, 1) && dComIfGp_getAStatus() == 0x12) {
|
} else if (dComIfGp_checkPlayerStatus1(0, 1) && dComIfGp_getAStatus() == 0x12) {
|
||||||
mStatus |= 0x200000;
|
mStatus |= 0x200000;
|
||||||
@@ -2870,8 +2875,14 @@ void dMeter2_c::alphaAnimeButton() {
|
|||||||
u8 var_31;
|
u8 var_31;
|
||||||
var_31 = 0;
|
var_31 = 0;
|
||||||
|
|
||||||
|
#if TARGET_PC
|
||||||
|
dMsgObject_c* msgObject = dMsgObject_getMsgObjectClass();
|
||||||
|
if ((mStatus & 0x4000) ||
|
||||||
|
((mStatus & 0x100) && (msgObject != NULL && msgObject->isAutoMessageFlag())) ||
|
||||||
|
#else
|
||||||
if ((mStatus & 0x4000) ||
|
if ((mStatus & 0x4000) ||
|
||||||
((mStatus & 0x100) && dMsgObject_getMsgObjectClass()->isAutoMessageFlag()) ||
|
((mStatus & 0x100) && dMsgObject_getMsgObjectClass()->isAutoMessageFlag()) ||
|
||||||
|
#endif
|
||||||
((mStatus & 0x40000000) && !(mStatus & 0x100)) || (mStatus & 0x80000000) || (mStatus & 8) ||
|
((mStatus & 0x40000000) && !(mStatus & 0x100)) || (mStatus & 0x80000000) || (mStatus & 8) ||
|
||||||
(mStatus & 0x10) || (mStatus & 0x20) || (mStatus & 0x04000000) || (mStatus & 0x10000000))
|
(mStatus & 0x10) || (mStatus & 0x20) || (mStatus & 0x04000000) || (mStatus & 0x10000000))
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -560,7 +560,8 @@ bool dMsgScrn3Select_c::pointerMove() {
|
|||||||
|
|
||||||
mDPDPoint = choice;
|
mDPDPoint = choice;
|
||||||
field_0x110 = paneIndex;
|
field_0x110 = paneIndex;
|
||||||
dusk::menu_pointer::set_dialog_choice(choice, dusk::menu_pointer::state().clicked);
|
dusk::menu_pointer::set_hover_target(choice);
|
||||||
|
dusk::menu_pointer::set_dialog_choice(choice, dusk::menu_pointer::peek_click());
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -378,6 +378,7 @@ nlohmann::json ConfigImpl<ui::ControlLayout>::dumpToJson(const ConfigVar<ui::Con
|
|||||||
}
|
}
|
||||||
|
|
||||||
template class ConfigImpl<dusk::FrameInterpMode>;
|
template class ConfigImpl<dusk::FrameInterpMode>;
|
||||||
|
template class ConfigImpl<dusk::TouchTargeting>;
|
||||||
template class ConfigImpl<dusk::MenuScaling>;
|
template class ConfigImpl<dusk::MenuScaling>;
|
||||||
template class ConfigImpl<dusk::Resampler>;
|
template class ConfigImpl<dusk::Resampler>;
|
||||||
template class ConfigImpl<dusk::MagicArmorMode>;
|
template class ConfigImpl<dusk::MagicArmorMode>;
|
||||||
|
|||||||
@@ -375,7 +375,6 @@ namespace dusk {
|
|||||||
|
|
||||||
void ImGuiConsole::PostDraw() {
|
void ImGuiConsole::PostDraw() {
|
||||||
m_menuTools.afterDraw();
|
m_menuTools.afterDraw();
|
||||||
ShowPipelineProgress();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGuiConsole::UpdateDragScroll() {
|
void ImGuiConsole::UpdateDragScroll() {
|
||||||
@@ -524,31 +523,4 @@ namespace dusk {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGuiConsole::ShowPipelineProgress() {
|
|
||||||
const auto* stats = aurora_get_stats();
|
|
||||||
const u32 queuedPipelines = stats->queuedPipelines;
|
|
||||||
if (queuedPipelines == 0 || !getSettings().backend.showPipelineCompilation) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const u32 createdPipelines = stats->createdPipelines;
|
|
||||||
const u32 totalPipelines = queuedPipelines + createdPipelines;
|
|
||||||
|
|
||||||
const auto* viewport = ImGui::GetMainViewport();
|
|
||||||
const auto padding = viewport->WorkPos.y + 10.f;
|
|
||||||
const auto halfWidth = viewport->GetWorkCenter().x;
|
|
||||||
ImGui::SetNextWindowPos(ImVec2{halfWidth, padding}, ImGuiCond_Always, ImVec2{0.5f, 0.f});
|
|
||||||
ImGui::SetNextWindowSize(ImVec2{halfWidth, 0.f}, ImGuiCond_Always);
|
|
||||||
ImGui::SetNextWindowBgAlpha(0.65f);
|
|
||||||
ImGui::Begin("Pipelines", nullptr,
|
|
||||||
ImGuiWindowFlags_NoDecoration | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoMove |
|
|
||||||
ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing);
|
|
||||||
const auto percent = static_cast<float>(createdPipelines) / static_cast<float>(totalPipelines);
|
|
||||||
const auto progressStr = fmt::format("Processing pipelines: {} / {}", createdPipelines, totalPipelines);
|
|
||||||
const auto textSize = ImGui::CalcTextSize(progressStr.data(), progressStr.data() + progressStr.size());
|
|
||||||
ImGui::NewLine();
|
|
||||||
ImGui::SameLine(ImGui::GetWindowWidth() / 2.f - textSize.x + textSize.x / 2.f);
|
|
||||||
ImGuiStringViewText(progressStr);
|
|
||||||
ImGui::ProgressBar(percent);
|
|
||||||
ImGui::End();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ private:
|
|||||||
// Keep always last
|
// Keep always last
|
||||||
ImGuiMenuTools m_menuTools;
|
ImGuiMenuTools m_menuTools;
|
||||||
|
|
||||||
void ShowPipelineProgress();
|
|
||||||
void UpdateDragScroll();
|
void UpdateDragScroll();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+143
-15
@@ -1,16 +1,34 @@
|
|||||||
#include "dusk/menu_pointer.h"
|
#include "dusk/menu_pointer.h"
|
||||||
|
|
||||||
#include "m_Do/m_Do_graphic.h"
|
|
||||||
#include "d/d_pane_class.h"
|
#include "d/d_pane_class.h"
|
||||||
#include "dusk/settings.h"
|
#include "dusk/settings.h"
|
||||||
|
#include "m_Do/m_Do_graphic.h"
|
||||||
|
|
||||||
#include <aurora/rmlui.hpp>
|
#include <aurora/rmlui.hpp>
|
||||||
#include <dolphin/pad.h>
|
#include <dolphin/pad.h>
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
namespace dusk::menu_pointer {
|
namespace dusk::menu_pointer {
|
||||||
namespace {
|
namespace {
|
||||||
|
using Clock = std::chrono::steady_clock;
|
||||||
|
|
||||||
|
constexpr auto kTapMaxDuration = std::chrono::milliseconds(300);
|
||||||
|
constexpr f32 kTapMoveThresholdDp = 12.0f;
|
||||||
|
|
||||||
|
struct Gesture {
|
||||||
|
bool active = false;
|
||||||
|
bool movedTooFar = false;
|
||||||
|
bool crossedTarget = false;
|
||||||
|
bool pressTargetValid = false;
|
||||||
|
Context pressContext = Context::None;
|
||||||
|
TargetId pressTarget = InvalidTarget;
|
||||||
|
f32 startX = 0.0f;
|
||||||
|
f32 startY = 0.0f;
|
||||||
|
Clock::time_point startedAt{};
|
||||||
|
};
|
||||||
|
|
||||||
State s_state;
|
State s_state;
|
||||||
bool s_clickConsumed = false;
|
bool s_clickConsumed = false;
|
||||||
Context s_lastContext = Context::None;
|
Context s_lastContext = Context::None;
|
||||||
@@ -27,7 +45,14 @@ s32 s_mouseButton = -1;
|
|||||||
u32 s_suppressedPadHoldMask = 0;
|
u32 s_suppressedPadHoldMask = 0;
|
||||||
u32 s_suppressedPadNextReadMask = 0;
|
u32 s_suppressedPadNextReadMask = 0;
|
||||||
Context s_deferredActivationContext = Context::None;
|
Context s_deferredActivationContext = Context::None;
|
||||||
u8 s_deferredActivationTarget = 0xFF;
|
TargetId s_deferredActivationTarget = InvalidTarget;
|
||||||
|
Gesture s_gesture;
|
||||||
|
bool s_hoverTargetValid = false;
|
||||||
|
TargetId s_hoverTarget = InvalidTarget;
|
||||||
|
bool s_clickPending = false;
|
||||||
|
Context s_clickContext = Context::None;
|
||||||
|
TargetId s_clickTarget = InvalidTarget;
|
||||||
|
bool s_clickTargetValid = false;
|
||||||
|
|
||||||
s32 scancode_from_rml_button(s32 button) noexcept {
|
s32 scancode_from_rml_button(s32 button) noexcept {
|
||||||
switch (button) {
|
switch (button) {
|
||||||
@@ -104,6 +129,37 @@ void suppress_pad_for_mouse_button(s32 button, bool held) noexcept {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
f32 tap_move_threshold() noexcept {
|
||||||
|
auto* context = aurora::rmlui::get_context();
|
||||||
|
if (context == nullptr) {
|
||||||
|
return kTapMoveThresholdDp;
|
||||||
|
}
|
||||||
|
|
||||||
|
return kTapMoveThresholdDp * std::max(context->GetDensityIndependentPixelRatio(), 1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_gesture_movement(f32 x, f32 y) noexcept {
|
||||||
|
if (!s_gesture.active || s_gesture.movedTooFar) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const f32 dx = x - s_gesture.startX;
|
||||||
|
const f32 dy = y - s_gesture.startY;
|
||||||
|
const f32 threshold = tap_move_threshold();
|
||||||
|
if (dx * dx + dy * dy > threshold * threshold) {
|
||||||
|
s_gesture.movedTooFar = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void clear_click_state() noexcept {
|
||||||
|
s_clickConsumed = false;
|
||||||
|
s_clickPending = false;
|
||||||
|
s_clickContext = Context::None;
|
||||||
|
s_clickTarget = InvalidTarget;
|
||||||
|
s_clickTargetValid = false;
|
||||||
|
s_state.clicked = false;
|
||||||
|
}
|
||||||
|
|
||||||
void set_position_from_rml(f32 x, f32 y) noexcept {
|
void set_position_from_rml(f32 x, f32 y) noexcept {
|
||||||
auto* context = aurora::rmlui::get_context();
|
auto* context = aurora::rmlui::get_context();
|
||||||
if (context == nullptr) {
|
if (context == nullptr) {
|
||||||
@@ -121,7 +177,7 @@ void set_position_from_rml(f32 x, f32 y) noexcept {
|
|||||||
|
|
||||||
void clear_input_state() noexcept {
|
void clear_input_state() noexcept {
|
||||||
s_state = {};
|
s_state = {};
|
||||||
s_clickConsumed = false;
|
clear_click_state();
|
||||||
s_lastDialogChoice = 0xFF;
|
s_lastDialogChoice = 0xFF;
|
||||||
s_currentDialogChoice = 0xFF;
|
s_currentDialogChoice = 0xFF;
|
||||||
s_lastDialogChoiceValid = false;
|
s_lastDialogChoiceValid = false;
|
||||||
@@ -134,7 +190,10 @@ void clear_input_state() noexcept {
|
|||||||
s_suppressedPadHoldMask = 0;
|
s_suppressedPadHoldMask = 0;
|
||||||
s_suppressedPadNextReadMask = 0;
|
s_suppressedPadNextReadMask = 0;
|
||||||
s_deferredActivationContext = Context::None;
|
s_deferredActivationContext = Context::None;
|
||||||
s_deferredActivationTarget = 0xFF;
|
s_deferredActivationTarget = InvalidTarget;
|
||||||
|
s_gesture = {};
|
||||||
|
s_hoverTargetValid = false;
|
||||||
|
s_hoverTarget = InvalidTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
@@ -144,8 +203,6 @@ bool handle_fallthrough_pointer(f32 x, f32 y, Phase phase, bool touch, s32 mouse
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
s_clickConsumed = false;
|
|
||||||
|
|
||||||
if (!touch) {
|
if (!touch) {
|
||||||
if (phase == Phase::Press) {
|
if (phase == Phase::Press) {
|
||||||
if (!mouse_button_is_menu_confirm(mouseButton)) {
|
if (!mouse_button_is_menu_confirm(mouseButton)) {
|
||||||
@@ -174,21 +231,41 @@ bool handle_fallthrough_pointer(f32 x, f32 y, Phase phase, bool touch, s32 mouse
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (phase != Phase::Cancel) {
|
if (phase != Phase::Cancel) {
|
||||||
|
update_gesture_movement(x, y);
|
||||||
set_position_from_rml(x, y);
|
set_position_from_rml(x, y);
|
||||||
}
|
}
|
||||||
s_state.touch = touch;
|
s_state.touch = touch;
|
||||||
|
|
||||||
switch (phase) {
|
switch (phase) {
|
||||||
case Phase::Press:
|
case Phase::Press:
|
||||||
|
clear_click_state();
|
||||||
|
s_gesture = {
|
||||||
|
.active = true,
|
||||||
|
.startX = x,
|
||||||
|
.startY = y,
|
||||||
|
.startedAt = Clock::now(),
|
||||||
|
};
|
||||||
s_state.down = true;
|
s_state.down = true;
|
||||||
s_state.pressed = true;
|
s_state.pressed = true;
|
||||||
break;
|
break;
|
||||||
case Phase::Release:
|
case Phase::Release: {
|
||||||
|
const bool shortEnough =
|
||||||
|
s_gesture.active && Clock::now() - s_gesture.startedAt <= kTapMaxDuration;
|
||||||
|
const bool stillEnough = s_gesture.active && !s_gesture.movedTooFar;
|
||||||
|
const bool targetClean = s_gesture.active && !s_gesture.crossedTarget;
|
||||||
|
s_clickContext = s_gesture.pressContext;
|
||||||
|
s_clickTarget = s_gesture.pressTarget;
|
||||||
|
s_clickTargetValid = s_gesture.pressTargetValid;
|
||||||
|
s_clickPending = shortEnough && stillEnough && targetClean;
|
||||||
s_state.down = false;
|
s_state.down = false;
|
||||||
s_state.released = true;
|
s_state.released = true;
|
||||||
s_state.clicked = true;
|
s_state.clicked = s_clickPending;
|
||||||
|
s_gesture = {};
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case Phase::Cancel:
|
case Phase::Cancel:
|
||||||
|
clear_click_state();
|
||||||
|
s_gesture = {};
|
||||||
s_state.down = false;
|
s_state.down = false;
|
||||||
break;
|
break;
|
||||||
case Phase::Move:
|
case Phase::Move:
|
||||||
@@ -211,6 +288,12 @@ void begin_game_frame() noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void end_game_frame() noexcept {
|
void end_game_frame() noexcept {
|
||||||
|
if (s_gesture.active && s_gesture.pressTargetValid &&
|
||||||
|
s_currentContext == s_gesture.pressContext && !s_hoverTargetValid)
|
||||||
|
{
|
||||||
|
s_gesture.crossedTarget = true;
|
||||||
|
}
|
||||||
|
|
||||||
s_lastContext = s_currentContext;
|
s_lastContext = s_currentContext;
|
||||||
s_lastDialogChoice = s_currentDialogChoice;
|
s_lastDialogChoice = s_currentDialogChoice;
|
||||||
s_lastDialogChoiceValid = s_currentDialogChoiceValid;
|
s_lastDialogChoiceValid = s_currentDialogChoiceValid;
|
||||||
@@ -222,10 +305,16 @@ void end_game_frame() noexcept {
|
|||||||
s_state.valid = false;
|
s_state.valid = false;
|
||||||
}
|
}
|
||||||
s_clickConsumed = false;
|
s_clickConsumed = false;
|
||||||
|
s_clickPending = false;
|
||||||
|
s_clickContext = Context::None;
|
||||||
|
s_clickTarget = InvalidTarget;
|
||||||
|
s_clickTargetValid = false;
|
||||||
|
s_hoverTargetValid = false;
|
||||||
|
s_hoverTarget = InvalidTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
void begin_context(Context context) noexcept {
|
void begin_context(Context context) noexcept {
|
||||||
if (context == Context::None) {
|
if (context == Context::None || !enabled()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -237,7 +326,11 @@ void begin_context(Context context) noexcept {
|
|||||||
s_suppressedPadHoldMask = 0;
|
s_suppressedPadHoldMask = 0;
|
||||||
s_suppressedPadNextReadMask = 0;
|
s_suppressedPadNextReadMask = 0;
|
||||||
s_deferredActivationContext = Context::None;
|
s_deferredActivationContext = Context::None;
|
||||||
s_deferredActivationTarget = 0xFF;
|
s_deferredActivationTarget = InvalidTarget;
|
||||||
|
s_gesture = {};
|
||||||
|
s_hoverTargetValid = false;
|
||||||
|
s_hoverTarget = InvalidTarget;
|
||||||
|
clear_click_state();
|
||||||
}
|
}
|
||||||
|
|
||||||
s_currentContext = context;
|
s_currentContext = context;
|
||||||
@@ -259,15 +352,50 @@ const State& state() noexcept {
|
|||||||
return s_state;
|
return s_state;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void set_hover_target(TargetId target) noexcept {
|
||||||
|
s_hoverTargetValid = true;
|
||||||
|
s_hoverTarget = target;
|
||||||
|
|
||||||
|
if (s_gesture.active && !s_gesture.pressTargetValid && s_state.down) {
|
||||||
|
s_gesture.pressContext = s_currentContext;
|
||||||
|
s_gesture.pressTarget = target;
|
||||||
|
s_gesture.pressTargetValid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (s_gesture.active && s_gesture.pressTargetValid &&
|
||||||
|
(s_currentContext != s_gesture.pressContext || target != s_gesture.pressTarget))
|
||||||
|
{
|
||||||
|
s_gesture.crossedTarget = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool click_matches_hover_target() noexcept {
|
||||||
|
if (!s_clickPending || !s_hoverTargetValid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!s_clickTargetValid) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return s_currentContext == s_clickContext && s_hoverTarget == s_clickTarget;
|
||||||
|
}
|
||||||
|
|
||||||
bool consume_click() noexcept {
|
bool consume_click() noexcept {
|
||||||
if (!s_state.clicked || s_clickConsumed) {
|
if (s_clickConsumed || !click_matches_hover_target()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
s_clickConsumed = true;
|
s_clickConsumed = true;
|
||||||
|
s_clickPending = false;
|
||||||
|
s_state.clicked = false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool peek_click() noexcept {
|
||||||
|
return !s_clickConsumed && click_matches_hover_target();
|
||||||
|
}
|
||||||
|
|
||||||
void set_dialog_choice(u8 choice, bool clicked) noexcept {
|
void set_dialog_choice(u8 choice, bool clicked) noexcept {
|
||||||
s_currentDialogChoice = choice;
|
s_currentDialogChoice = choice;
|
||||||
s_currentDialogChoiceValid = true;
|
s_currentDialogChoiceValid = true;
|
||||||
@@ -300,18 +428,18 @@ bool consume_dialog_click(u8& choice) noexcept {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void defer_activation(Context context, u8 target) noexcept {
|
void defer_activation(Context context, TargetId target) noexcept {
|
||||||
s_deferredActivationContext = context;
|
s_deferredActivationContext = context;
|
||||||
s_deferredActivationTarget = target;
|
s_deferredActivationTarget = target;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool consume_deferred_activation(Context context, u8 target) noexcept {
|
bool consume_deferred_activation(Context context, TargetId target) noexcept {
|
||||||
if (s_deferredActivationContext != context || s_deferredActivationTarget != target) {
|
if (s_deferredActivationContext != context || s_deferredActivationTarget != target) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
s_deferredActivationContext = Context::None;
|
s_deferredActivationContext = Context::None;
|
||||||
s_deferredActivationTarget = 0xFF;
|
s_deferredActivationTarget = InvalidTarget;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -321,7 +449,7 @@ void clear_deferred_activation(Context context) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
s_deferredActivationContext = Context::None;
|
s_deferredActivationContext = Context::None;
|
||||||
s_deferredActivationTarget = 0xFF;
|
s_deferredActivationTarget = InvalidTarget;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 suppressed_pad_buttons(u32 port) noexcept {
|
u32 suppressed_pad_buttons(u32 port) noexcept {
|
||||||
|
|||||||
+70
-48
@@ -1,54 +1,69 @@
|
|||||||
#include "dusk/mouse.h"
|
#include "dusk/mouse.h"
|
||||||
|
#include "d/actor/d_a_alink.h"
|
||||||
|
#include "d/d_com_inf_game.h"
|
||||||
#include "dusk/menu_pointer.h"
|
#include "dusk/menu_pointer.h"
|
||||||
#include "dusk/settings.h"
|
#include "dusk/settings.h"
|
||||||
#include "dusk/ui/ui.hpp"
|
#include "dusk/ui/ui.hpp"
|
||||||
#include "d/actor/d_a_alink.h"
|
|
||||||
#include "d/d_com_inf_game.h"
|
|
||||||
|
|
||||||
#include <aurora/lib/window.hpp>
|
|
||||||
#include <imgui.h>
|
|
||||||
#include <SDL3/SDL_mouse.h>
|
#include <SDL3/SDL_mouse.h>
|
||||||
#include <SDL3/SDL_video.h>
|
#include <SDL3/SDL_video.h>
|
||||||
|
#include <aurora/lib/window.hpp>
|
||||||
|
#include <imgui.h>
|
||||||
|
|
||||||
|
#include <chrono>
|
||||||
|
|
||||||
namespace dusk::mouse {
|
namespace dusk::mouse {
|
||||||
namespace {
|
namespace {
|
||||||
|
using Clock = std::chrono::steady_clock;
|
||||||
|
|
||||||
constexpr float kMousePixelToRad = 0.0025f;
|
constexpr float kMousePixelToRad = 0.0025f;
|
||||||
constexpr int kIdleHideFrames = 99; // Approx. 3 seconds with 33ms ticks
|
constexpr auto kCursorIdleDuration = std::chrono::seconds(1);
|
||||||
|
|
||||||
float s_aim_yaw_rad = 0.0f;
|
float s_aim_yaw_rad = 0.0f;
|
||||||
float s_aim_pitch_rad = 0.0f;
|
float s_aim_pitch_rad = 0.0f;
|
||||||
float s_camera_yaw_rad = 0.0f;
|
float s_camera_yaw_rad = 0.0f;
|
||||||
float s_camera_pitch_rad = 0.0f;
|
float s_camera_pitch_rad = 0.0f;
|
||||||
int s_idle_frames = 0;
|
Clock::time_point s_last_cursor_motion = Clock::now();
|
||||||
|
|
||||||
void reset_deltas() {
|
void reset_deltas() {
|
||||||
s_aim_yaw_rad = s_aim_pitch_rad = 0.0f;
|
s_aim_yaw_rad = s_aim_pitch_rad = 0.0f;
|
||||||
s_camera_yaw_rad = s_camera_pitch_rad = 0.0f;
|
s_camera_yaw_rad = s_camera_pitch_rad = 0.0f;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool queryMouseAimContext() {
|
bool query_mouse_aim_context() {
|
||||||
return getSettings().game.enableMouseAim.getValue() && dCamera_c::isAimActive();
|
return getSettings().game.enableMouseAim.getValue() && dCamera_c::isAimActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool wantMouseCapture() {
|
bool want_mouse_capture() {
|
||||||
return getSettings().game.enableMouseCamera.getValue() || queryMouseAimContext();
|
return getSettings().game.enableMouseCamera.getValue() || query_mouse_aim_context();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool isWindowFocused(SDL_Window* window) {
|
bool mouse_input_enabled() {
|
||||||
|
const auto& game = getSettings().game;
|
||||||
|
return game.enableMouseAim.getValue() || game.enableMouseCamera.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_window_focused(SDL_Window* window) {
|
||||||
if (window == nullptr) {
|
if (window == nullptr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return (SDL_GetWindowFlags(window) & SDL_WINDOW_INPUT_FOCUS) != 0;
|
return (SDL_GetWindowFlags(window) & SDL_WINDOW_INPUT_FOCUS) != 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool shouldCaptureMouse(SDL_Window* window) {
|
bool imgui_windows_visible() {
|
||||||
if (window == nullptr || ui::any_document_visible() || menu_pointer::active()) {
|
return ImGui::GetIO().MetricsRenderWindows > 0;
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return wantMouseCapture() && isWindowFocused(window);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool syncCaptureState(SDL_Window* window, bool should_capture) {
|
bool should_capture_mouse(SDL_Window* window) {
|
||||||
|
if (window == nullptr || ui::any_document_visible() || imgui_windows_visible() ||
|
||||||
|
menu_pointer::active())
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return want_mouse_capture() && is_window_focused(window);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool sync_capture_state(SDL_Window* window, bool should_capture) {
|
||||||
if (window == nullptr) {
|
if (window == nullptr) {
|
||||||
reset_deltas();
|
reset_deltas();
|
||||||
return false;
|
return false;
|
||||||
@@ -78,7 +93,7 @@ bool syncCaptureState(SDL_Window* window, bool should_capture) {
|
|||||||
return is_captured;
|
return is_captured;
|
||||||
}
|
}
|
||||||
|
|
||||||
void accumulateDeltas(float mx_rel, float my_rel, bool camera_active, bool aim_active) {
|
void accumulate_deltas(float mx_rel, float my_rel, bool camera_active, bool aim_active) {
|
||||||
const auto& game = getSettings().game;
|
const auto& game = getSettings().game;
|
||||||
const bool mirror_mode = game.enableMirrorMode.getValue();
|
const bool mirror_mode = game.enableMirrorMode.getValue();
|
||||||
const bool invert_y = game.invertMouseY.getValue();
|
const bool invert_y = game.invertMouseY.getValue();
|
||||||
@@ -114,57 +129,62 @@ void set_cursor_visible(bool visible) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_cursor_visibility(SDL_Window* window, bool captured) {
|
bool cursor_idle() {
|
||||||
if (window == nullptr || !isWindowFocused(window)) {
|
return Clock::now() - s_last_cursor_motion >= kCursorIdleDuration;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
bool should_show_cursor(bool captured) {
|
||||||
if (captured) {
|
if (captured) {
|
||||||
s_idle_frames = 0;
|
return false;
|
||||||
set_cursor_visible(false);
|
}
|
||||||
|
if (ui::any_document_visible()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (imgui_windows_visible()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (menu_pointer::enabled() && menu_pointer::active()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (mouse_input_enabled()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return !cursor_idle();
|
||||||
|
}
|
||||||
|
|
||||||
|
void update_cursor_visibility(SDL_Window* window, bool captured) {
|
||||||
|
if (window == nullptr || !is_window_focused(window)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const ImGuiIO& io = ImGui::GetIO();
|
set_cursor_visible(should_show_cursor(captured));
|
||||||
if (io.MouseDelta.x != 0.0f || io.MouseDelta.y != 0.0f) {
|
|
||||||
s_idle_frames = 0;
|
|
||||||
set_cursor_visible(true);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (s_idle_frames < kIdleHideFrames) {
|
|
||||||
++s_idle_frames;
|
|
||||||
set_cursor_visible(true);
|
|
||||||
} else {
|
|
||||||
set_cursor_visible(false);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void read() {
|
void read() {
|
||||||
SDL_Window* window = aurora::window::get_sdl_window();
|
SDL_Window* window = aurora::window::get_sdl_window();
|
||||||
const bool capture_active = syncCaptureState(window, shouldCaptureMouse(window));
|
const bool capture_active = sync_capture_state(window, should_capture_mouse(window));
|
||||||
update_cursor_visibility(window, capture_active);
|
update_cursor_visibility(window, capture_active);
|
||||||
|
|
||||||
if (!capture_active) {
|
if (!capture_active) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const bool aim_active = capture_active && queryMouseAimContext();
|
const bool aim_active = capture_active && query_mouse_aim_context();
|
||||||
const bool camera_active = capture_active && getSettings().game.enableMouseCamera;
|
const bool camera_active = capture_active && getSettings().game.enableMouseCamera;
|
||||||
|
|
||||||
float mx_rel = 0.0f;
|
float mx_rel = 0.0f;
|
||||||
float my_rel = 0.0f;
|
float my_rel = 0.0f;
|
||||||
SDL_GetRelativeMouseState(&mx_rel, &my_rel);
|
SDL_GetRelativeMouseState(&mx_rel, &my_rel);
|
||||||
accumulateDeltas(mx_rel, my_rel, camera_active, aim_active);
|
accumulate_deltas(mx_rel, my_rel, camera_active, aim_active);
|
||||||
}
|
}
|
||||||
|
|
||||||
void getAimDeltas(float& out_yaw, float& out_pitch) {
|
void get_aim_deltas(float& out_yaw, float& out_pitch) {
|
||||||
out_yaw = s_aim_yaw_rad;
|
out_yaw = s_aim_yaw_rad;
|
||||||
out_pitch = s_aim_pitch_rad;
|
out_pitch = s_aim_pitch_rad;
|
||||||
}
|
}
|
||||||
|
|
||||||
void getCameraDeltas(float& out_yaw, float& out_pitch) {
|
void get_camera_deltas(float& out_yaw, float& out_pitch) {
|
||||||
out_yaw = 0.0f;
|
out_yaw = 0.0f;
|
||||||
out_pitch = 0.0f;
|
out_pitch = 0.0f;
|
||||||
|
|
||||||
@@ -178,26 +198,28 @@ void getCameraDeltas(float& out_yaw, float& out_pitch) {
|
|||||||
|
|
||||||
void handle_event(const SDL_Event& event) noexcept {
|
void handle_event(const SDL_Event& event) noexcept {
|
||||||
switch (event.type) {
|
switch (event.type) {
|
||||||
|
case SDL_EVENT_MOUSE_MOTION:
|
||||||
|
s_last_cursor_motion = Clock::now();
|
||||||
|
break;
|
||||||
case SDL_EVENT_WINDOW_FOCUS_LOST:
|
case SDL_EVENT_WINDOW_FOCUS_LOST:
|
||||||
onFocusLost();
|
on_focus_lost();
|
||||||
break;
|
break;
|
||||||
case SDL_EVENT_WINDOW_FOCUS_GAINED:
|
case SDL_EVENT_WINDOW_FOCUS_GAINED:
|
||||||
onFocusGained();
|
on_focus_gained();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void onFocusLost() {
|
void on_focus_lost() {
|
||||||
SDL_Window* window = aurora::window::get_sdl_window();
|
SDL_Window* window = aurora::window::get_sdl_window();
|
||||||
if (window != nullptr) {
|
if (window != nullptr) {
|
||||||
syncCaptureState(window, false);
|
sync_capture_state(window, false);
|
||||||
}
|
}
|
||||||
s_idle_frames = 0;
|
|
||||||
set_cursor_visible(true);
|
set_cursor_visible(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
void onFocusGained() {
|
void on_focus_gained() {
|
||||||
SDL_Window* window = aurora::window::get_sdl_window();
|
SDL_Window* window = aurora::window::get_sdl_window();
|
||||||
syncCaptureState(window, shouldCaptureMouse(window));
|
sync_capture_state(window, should_capture_mouse(window));
|
||||||
}
|
}
|
||||||
} // namespace dusk::mouse
|
} // namespace dusk::mouse
|
||||||
|
|||||||
@@ -96,6 +96,7 @@ UserSettings g_userSettings = {
|
|||||||
.invertMouseY {"game.invertMouseY", false},
|
.invertMouseY {"game.invertMouseY", false},
|
||||||
.freeCamera {"game.freeCamera", false},
|
.freeCamera {"game.freeCamera", false},
|
||||||
.enableTouchControls {"game.enableTouchControls", false},
|
.enableTouchControls {"game.enableTouchControls", false},
|
||||||
|
.touchTargeting {"game.touchTargeting", TouchTargeting::Hybrid},
|
||||||
.enableMenuPointer {"game.enableMenuPointer", true},
|
.enableMenuPointer {"game.enableMenuPointer", true},
|
||||||
.touchControlsLayout {"game.touchControlsLayout", ui::ControlLayout{}},
|
.touchControlsLayout {"game.touchControlsLayout", ui::ControlLayout{}},
|
||||||
.invertCameraXAxis {"game.invertCameraXAxis", false},
|
.invertCameraXAxis {"game.invertCameraXAxis", false},
|
||||||
@@ -160,7 +161,6 @@ UserSettings g_userSettings = {
|
|||||||
.isoVerification {"backend.isoVerification", DiscVerificationState::Unknown},
|
.isoVerification {"backend.isoVerification", DiscVerificationState::Unknown},
|
||||||
.graphicsBackend {"backend.graphicsBackend", "auto"},
|
.graphicsBackend {"backend.graphicsBackend", "auto"},
|
||||||
.skipPreLaunchUI {"backend.skipPreLaunchUI", false},
|
.skipPreLaunchUI {"backend.skipPreLaunchUI", false},
|
||||||
.showPipelineCompilation {"backend.showPipelineCompilation", false},
|
|
||||||
.wasPresetChosen {"backend.wasPresetChosen", false},
|
.wasPresetChosen {"backend.wasPresetChosen", false},
|
||||||
.checkForUpdates {"backend.checkForUpdates", true},
|
.checkForUpdates {"backend.checkForUpdates", true},
|
||||||
.cardFileType {"backend.cardFileType", static_cast<int>(CARD_GCIFOLDER)},
|
.cardFileType {"backend.cardFileType", static_cast<int>(CARD_GCIFOLDER)},
|
||||||
@@ -330,6 +330,7 @@ void registerSettings() {
|
|||||||
Register(g_userSettings.game.invertMouseY);
|
Register(g_userSettings.game.invertMouseY);
|
||||||
Register(g_userSettings.game.freeCamera);
|
Register(g_userSettings.game.freeCamera);
|
||||||
Register(g_userSettings.game.enableTouchControls);
|
Register(g_userSettings.game.enableTouchControls);
|
||||||
|
Register(g_userSettings.game.touchTargeting);
|
||||||
Register(g_userSettings.game.enableMenuPointer);
|
Register(g_userSettings.game.enableMenuPointer);
|
||||||
Register(g_userSettings.game.touchControlsLayout);
|
Register(g_userSettings.game.touchControlsLayout);
|
||||||
Register(g_userSettings.game.debugFlyCam);
|
Register(g_userSettings.game.debugFlyCam);
|
||||||
@@ -345,7 +346,6 @@ void registerSettings() {
|
|||||||
Register(g_userSettings.backend.isoVerification);
|
Register(g_userSettings.backend.isoVerification);
|
||||||
Register(g_userSettings.backend.graphicsBackend);
|
Register(g_userSettings.backend.graphicsBackend);
|
||||||
Register(g_userSettings.backend.skipPreLaunchUI);
|
Register(g_userSettings.backend.skipPreLaunchUI);
|
||||||
Register(g_userSettings.backend.showPipelineCompilation);
|
|
||||||
Register(g_userSettings.backend.wasPresetChosen);
|
Register(g_userSettings.backend.wasPresetChosen);
|
||||||
Register(g_userSettings.backend.checkForUpdates);
|
Register(g_userSettings.backend.checkForUpdates);
|
||||||
Register(g_userSettings.backend.cardFileType);
|
Register(g_userSettings.backend.cardFileType);
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
#include "dusk/speedrun.h"
|
#include "dusk/speedrun.h"
|
||||||
#include "dusk/settings.h"
|
#include "dusk/settings.h"
|
||||||
|
#include "dusk/config.hpp"
|
||||||
#include "m_Do/m_Do_main.h"
|
#include "m_Do/m_Do_main.h"
|
||||||
#include <aurora/aurora.h>
|
#include <aurora/aurora.h>
|
||||||
|
|
||||||
@@ -34,6 +35,7 @@ void resetForSpeedrunMode() {
|
|||||||
getSettings().game.fastRoll.setSpeedrunValue(false);
|
getSettings().game.fastRoll.setSpeedrunValue(false);
|
||||||
getSettings().game.fastSpinner.setSpeedrunValue(false);
|
getSettings().game.fastSpinner.setSpeedrunValue(false);
|
||||||
getSettings().game.armorRupeeDrain.setSpeedrunValue(MagicArmorMode::NORMAL);
|
getSettings().game.armorRupeeDrain.setSpeedrunValue(MagicArmorMode::NORMAL);
|
||||||
|
getSettings().game.invincibleEnemies.setSpeedrunValue(false);
|
||||||
|
|
||||||
getSettings().game.pauseOnFocusLost.setSpeedrunValue(false);
|
getSettings().game.pauseOnFocusLost.setSpeedrunValue(false);
|
||||||
aurora_set_pause_on_focus_lost(false);
|
aurora_set_pause_on_focus_lost(false);
|
||||||
@@ -43,4 +45,15 @@ void resetForSpeedrunMode() {
|
|||||||
getSettings().game.debugFlyCam.setSpeedrunValue(false);
|
getSettings().game.debugFlyCam.setSpeedrunValue(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void clear_speedrun_overrides() {
|
||||||
|
config::EnumerateRegistered([](config::ConfigVarBase& cvar) {
|
||||||
|
cvar.clearSpeedrunOverride();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void restoreFromSpeedrunMode() {
|
||||||
|
clear_speedrun_overrides();
|
||||||
|
aurora_set_pause_on_focus_lost(getSettings().game.pauseOnFocusLost.getValue());
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace dusk
|
} // namespace dusk
|
||||||
|
|||||||
@@ -7,6 +7,9 @@ float s_pitch_dp = 0.0f;
|
|||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
void add_delta(float yaw_dp, float pitch_dp) noexcept {
|
void add_delta(float yaw_dp, float pitch_dp) noexcept {
|
||||||
|
if (getSettings().game.enableMirrorMode) {
|
||||||
|
yaw_dp *= -1.0;
|
||||||
|
}
|
||||||
s_yaw_dp += yaw_dp;
|
s_yaw_dp += yaw_dp;
|
||||||
s_pitch_dp += pitch_dp;
|
s_pitch_dp += pitch_dp;
|
||||||
}
|
}
|
||||||
|
|||||||
+66
-8
@@ -1,9 +1,9 @@
|
|||||||
#include "overlay.hpp"
|
#include "overlay.hpp"
|
||||||
|
|
||||||
#include "aurora/lib/logging.hpp"
|
#include "aurora/lib/logging.hpp"
|
||||||
|
#include "controller_config.hpp"
|
||||||
#include "dusk/achievements.h"
|
#include "dusk/achievements.h"
|
||||||
#include "dusk/action_bindings.h"
|
#include "dusk/action_bindings.h"
|
||||||
#include "controller_config.hpp"
|
|
||||||
#include "dusk/livesplit.h"
|
#include "dusk/livesplit.h"
|
||||||
#include "dusk/settings.h"
|
#include "dusk/settings.h"
|
||||||
#include "dusk/speedrun.h"
|
#include "dusk/speedrun.h"
|
||||||
@@ -33,6 +33,13 @@ const Rml::String kDocumentSource = R"RML(
|
|||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<fps id="fps" />
|
<fps id="fps" />
|
||||||
|
<pipeline-progress id="pipeline-progress">
|
||||||
|
<pipeline-status>
|
||||||
|
<icon class="pipeline-spinner"></icon>
|
||||||
|
<span id="pipeline-progress-label" />
|
||||||
|
</pipeline-status>
|
||||||
|
<progress id="pipeline-progress-bar" />
|
||||||
|
</pipeline-progress>
|
||||||
<speedrun-timer id="speedrun-timer">
|
<speedrun-timer id="speedrun-timer">
|
||||||
<speedrun-rta id="speedrun-rta" />
|
<speedrun-rta id="speedrun-rta" />
|
||||||
<speedrun-igt id="speedrun-igt" />
|
<speedrun-igt id="speedrun-igt" />
|
||||||
@@ -48,6 +55,7 @@ constexpr std::array<std::pair<const char*, const char*>, 3> kAutoSaveLayers{{
|
|||||||
}};
|
}};
|
||||||
|
|
||||||
constexpr auto kMenuNotificationDuration = std::chrono::milliseconds(2500);
|
constexpr auto kMenuNotificationDuration = std::chrono::milliseconds(2500);
|
||||||
|
constexpr auto kPipelineProgressOpenDelay = std::chrono::milliseconds(250);
|
||||||
|
|
||||||
constexpr std::array<const char*, 4> kFpsCorners = {"tl", "tr", "bl", "br"};
|
constexpr std::array<const char*, 4> kFpsCorners = {"tl", "tr", "bl", "br"};
|
||||||
|
|
||||||
@@ -160,8 +168,8 @@ Rml::Element* create_menu_notification(Rml::Element* parent) {
|
|||||||
Rml::String padButton{};
|
Rml::String padButton{};
|
||||||
SDL_Gamepad* gamepad = gamepad_for_port(PAD_CHAN0);
|
SDL_Gamepad* gamepad = gamepad_for_port(PAD_CHAN0);
|
||||||
if (isActionBound(ActionBinds::OPEN_DUSKLIGHT_MENU, PAD_CHAN0) && gamepad != nullptr) {
|
if (isActionBound(ActionBinds::OPEN_DUSKLIGHT_MENU, PAD_CHAN0) && gamepad != nullptr) {
|
||||||
padButton = native_button_name(gamepad,
|
padButton = native_button_name(
|
||||||
getActionBindButton(ActionBinds::OPEN_DUSKLIGHT_MENU, PAD_CHAN0));
|
gamepad, getActionBindButton(ActionBinds::OPEN_DUSKLIGHT_MENU, PAD_CHAN0));
|
||||||
} else {
|
} else {
|
||||||
padButton = back_button_name();
|
padButton = back_button_name();
|
||||||
}
|
}
|
||||||
@@ -197,6 +205,9 @@ static std::string FormatTime(OSTime ticks) {
|
|||||||
|
|
||||||
Overlay::Overlay() : Document(kDocumentSource, true) {
|
Overlay::Overlay() : Document(kDocumentSource, true) {
|
||||||
mFpsCounter = mDocument->GetElementById("fps");
|
mFpsCounter = mDocument->GetElementById("fps");
|
||||||
|
mPipelineProgress = mDocument->GetElementById("pipeline-progress");
|
||||||
|
mPipelineProgressLabel = mDocument->GetElementById("pipeline-progress-label");
|
||||||
|
mPipelineProgressBar = mDocument->GetElementById("pipeline-progress-bar");
|
||||||
mSpeedrunTimer = mDocument->GetElementById("speedrun-timer");
|
mSpeedrunTimer = mDocument->GetElementById("speedrun-timer");
|
||||||
mSpeedrunRta = mDocument->GetElementById("speedrun-rta");
|
mSpeedrunRta = mDocument->GetElementById("speedrun-rta");
|
||||||
mSpeedrunIgt = mDocument->GetElementById("speedrun-igt");
|
mSpeedrunIgt = mDocument->GetElementById("speedrun-igt");
|
||||||
@@ -258,6 +269,8 @@ void Overlay::update() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
update_pipeline_progress();
|
||||||
|
|
||||||
#if !(defined(__ANDROID__) || (defined(__APPLE__) && TARGET_OS_IOS && !TARGET_OS_MACCATALYST))
|
#if !(defined(__ANDROID__) || (defined(__APPLE__) && TARGET_OS_IOS && !TARGET_OS_MACCATALYST))
|
||||||
if (getSettings().game.speedrunMode && getSettings().game.liveSplitEnabled) {
|
if (getSettings().game.speedrunMode && getSettings().game.liveSplitEnabled) {
|
||||||
dusk::speedrun::updateLiveSplit();
|
dusk::speedrun::updateLiveSplit();
|
||||||
@@ -309,7 +322,8 @@ void Overlay::update() {
|
|||||||
mSpeedrunRta->RemoveAttribute("open");
|
mSpeedrunRta->RemoveAttribute("open");
|
||||||
}
|
}
|
||||||
|
|
||||||
mSpeedrunIgt->SetInnerRML(escape(fmt::format("IGT {}", FormatTime(m_speedrunInfo.m_igtTimer))));
|
mSpeedrunIgt->SetInnerRML(
|
||||||
|
escape(fmt::format("IGT {}", FormatTime(m_speedrunInfo.m_igtTimer))));
|
||||||
} else {
|
} else {
|
||||||
mSpeedrunTimer->RemoveAttribute("open");
|
mSpeedrunTimer->RemoveAttribute("open");
|
||||||
}
|
}
|
||||||
@@ -373,10 +387,8 @@ void Overlay::update() {
|
|||||||
std::chrono::duration<float>(clock::now() - mCurrentToastStartTime).count();
|
std::chrono::duration<float>(clock::now() - mCurrentToastStartTime).count();
|
||||||
const float ratio = duration > 0.0f ? std::clamp(elapsed / duration, 0.0f, 1.0f) : 1.0f;
|
const float ratio = duration > 0.0f ? std::clamp(elapsed / duration, 0.0f, 1.0f) : 1.0f;
|
||||||
const auto remaining = 1.f - ratio;
|
const auto remaining = 1.f - ratio;
|
||||||
Rml::ElementList list;
|
if (auto* progress = mCurrentToast->QuerySelector("progress")) {
|
||||||
mDocument->GetElementsByTagName(list, "progress");
|
progress->SetAttribute("value", remaining);
|
||||||
for (auto* elem : list) {
|
|
||||||
elem->SetAttribute("value", remaining);
|
|
||||||
}
|
}
|
||||||
if (remaining == 0.f) {
|
if (remaining == 0.f) {
|
||||||
if (mCurrentToast->IsPseudoClassSet("done") ||
|
if (mCurrentToast->IsPseudoClassSet("done") ||
|
||||||
@@ -395,6 +407,52 @@ void Overlay::update() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Overlay::update_pipeline_progress() {
|
||||||
|
if (mPipelineProgress == nullptr || mPipelineProgressLabel == nullptr ||
|
||||||
|
mPipelineProgressBar == nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto* stats = aurora_get_stats();
|
||||||
|
const uint32_t queuedPipelines = stats != nullptr ? stats->queuedPipelines : 0;
|
||||||
|
if (queuedPipelines == 0) {
|
||||||
|
mPipelineProgress->RemoveAttribute("open");
|
||||||
|
mPipelineProgressActive = false;
|
||||||
|
mPipelineBatchCreatedBase = 0;
|
||||||
|
mLastQueuedPipelines = 0;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t createdPipelines = stats->createdPipelines;
|
||||||
|
if (!mPipelineProgressActive || createdPipelines < mPipelineBatchCreatedBase) {
|
||||||
|
mPipelineProgressActive = true;
|
||||||
|
mPipelineBatchCreatedBase = createdPipelines;
|
||||||
|
mPipelineProgressStartTime = clock::now();
|
||||||
|
mLastQueuedPipelines = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const uint32_t builtPipelines = createdPipelines - mPipelineBatchCreatedBase;
|
||||||
|
const uint32_t totalPipelines = queuedPipelines + builtPipelines;
|
||||||
|
const float progress = totalPipelines > 0 ? static_cast<float>(builtPipelines) /
|
||||||
|
static_cast<float>(totalPipelines) :
|
||||||
|
0.0f;
|
||||||
|
|
||||||
|
if (queuedPipelines != mLastQueuedPipelines) {
|
||||||
|
mLastQueuedPipelines = queuedPipelines;
|
||||||
|
const auto noun = queuedPipelines == 1 ? "pipeline" : "pipelines";
|
||||||
|
mPipelineProgressLabel->SetInnerRML(
|
||||||
|
escape(fmt::format("Building {} {}", queuedPipelines, noun)));
|
||||||
|
}
|
||||||
|
mPipelineProgressBar->SetAttribute("value", progress);
|
||||||
|
|
||||||
|
if (clock::now() >= mPipelineProgressStartTime + kPipelineProgressOpenDelay) {
|
||||||
|
mPipelineProgress->SetAttribute("open", "");
|
||||||
|
} else {
|
||||||
|
mPipelineProgress->RemoveAttribute("open");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool Overlay::handle_nav_command(Rml::Event& event, NavCommand cmd) {
|
bool Overlay::handle_nav_command(Rml::Event& event, NavCommand cmd) {
|
||||||
Log.warn("Overlay received nav command: {}", magic_enum::enum_name(cmd));
|
Log.warn("Overlay received nav command: {}", magic_enum::enum_name(cmd));
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -16,7 +16,13 @@ public:
|
|||||||
protected:
|
protected:
|
||||||
bool handle_nav_command(Rml::Event& event, NavCommand cmd) override;
|
bool handle_nav_command(Rml::Event& event, NavCommand cmd) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void update_pipeline_progress();
|
||||||
|
|
||||||
Rml::Element* mFpsCounter = nullptr;
|
Rml::Element* mFpsCounter = nullptr;
|
||||||
|
Rml::Element* mPipelineProgress = nullptr;
|
||||||
|
Rml::Element* mPipelineProgressLabel = nullptr;
|
||||||
|
Rml::Element* mPipelineProgressBar = nullptr;
|
||||||
Rml::Element* mCurrentToast = nullptr;
|
Rml::Element* mCurrentToast = nullptr;
|
||||||
Rml::Element* mControllerWarning = nullptr;
|
Rml::Element* mControllerWarning = nullptr;
|
||||||
Rml::Element* mMenuNotification = nullptr;
|
Rml::Element* mMenuNotification = nullptr;
|
||||||
@@ -25,7 +31,11 @@ protected:
|
|||||||
Rml::Element* mSpeedrunIgt = nullptr;
|
Rml::Element* mSpeedrunIgt = nullptr;
|
||||||
clock::time_point mCurrentToastStartTime;
|
clock::time_point mCurrentToastStartTime;
|
||||||
clock::time_point mMenuNotificationStartTime;
|
clock::time_point mMenuNotificationStartTime;
|
||||||
|
clock::time_point mPipelineProgressStartTime;
|
||||||
Uint64 mFpsLastUpdate = 0;
|
Uint64 mFpsLastUpdate = 0;
|
||||||
|
uint32_t mPipelineBatchCreatedBase = 0;
|
||||||
|
uint32_t mLastQueuedPipelines = 0;
|
||||||
|
bool mPipelineProgressActive = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace dusk::ui
|
} // namespace dusk::ui
|
||||||
|
|||||||
+63
-56
@@ -15,6 +15,7 @@
|
|||||||
#include "dusk/io.hpp"
|
#include "dusk/io.hpp"
|
||||||
#include "dusk/livesplit.h"
|
#include "dusk/livesplit.h"
|
||||||
#include "dusk/discord_presence.hpp"
|
#include "dusk/discord_presence.hpp"
|
||||||
|
#include "dusk/speedrun.h"
|
||||||
#include "graphics_tuner.hpp"
|
#include "graphics_tuner.hpp"
|
||||||
#include "m_Do/m_Do_main.h"
|
#include "m_Do/m_Do_main.h"
|
||||||
#include "menu_bar.hpp"
|
#include "menu_bar.hpp"
|
||||||
@@ -77,6 +78,18 @@ constexpr std::array kInterpolationModes = {
|
|||||||
"Unlimited",
|
"Unlimited",
|
||||||
};
|
};
|
||||||
|
|
||||||
|
constexpr std::array kTouchTargetingLabels = {
|
||||||
|
"Hybrid",
|
||||||
|
"Hold",
|
||||||
|
"Switch",
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr std::array kTouchTargetingDescriptions = {
|
||||||
|
"Tap once to lock on when a target is found. Double-tap when none is found to hold L.",
|
||||||
|
"L stays held only while your finger is on the button.",
|
||||||
|
"Tap L to keep it held. Tap again to release it.",
|
||||||
|
};
|
||||||
|
|
||||||
constexpr std::array kGyroInputModeLabels = {
|
constexpr std::array kGyroInputModeLabels = {
|
||||||
"Sensor",
|
"Sensor",
|
||||||
"Mouse",
|
"Mouse",
|
||||||
@@ -206,54 +219,6 @@ AuroraBackend configured_backend() {
|
|||||||
return configuredBackend;
|
return configuredBackend;
|
||||||
}
|
}
|
||||||
|
|
||||||
void reset_for_speedrun_mode() {
|
|
||||||
mDoMain::developmentMode = -1;
|
|
||||||
|
|
||||||
getSettings().game.enableTurboKeybind.setSpeedrunValue(false);
|
|
||||||
|
|
||||||
getSettings().game.damageMultiplier.setSpeedrunValue(1);
|
|
||||||
getSettings().game.instantDeath.setSpeedrunValue(false);
|
|
||||||
getSettings().game.noHeartDrops.setSpeedrunValue(false);
|
|
||||||
getSettings().game.autoSave.setSpeedrunValue(false);
|
|
||||||
getSettings().game.sunsSong.setSpeedrunValue(false);
|
|
||||||
|
|
||||||
getSettings().game.infiniteHearts.setSpeedrunValue(false);
|
|
||||||
getSettings().game.infiniteArrows.setSpeedrunValue(false);
|
|
||||||
getSettings().game.infiniteSeeds.setSpeedrunValue(false);
|
|
||||||
getSettings().game.infiniteBombs.setSpeedrunValue(false);
|
|
||||||
getSettings().game.infiniteOil.setSpeedrunValue(false);
|
|
||||||
getSettings().game.infiniteOxygen.setSpeedrunValue(false);
|
|
||||||
getSettings().game.infiniteRupees.setSpeedrunValue(false);
|
|
||||||
getSettings().game.enableIndefiniteItemDrops.setSpeedrunValue(false);
|
|
||||||
getSettings().game.moonJump.setSpeedrunValue(false);
|
|
||||||
getSettings().game.superClawshot.setSpeedrunValue(false);
|
|
||||||
getSettings().game.alwaysGreatspin.setSpeedrunValue(false);
|
|
||||||
getSettings().game.enableFastIronBoots.setSpeedrunValue(false);
|
|
||||||
getSettings().game.canTransformAnywhere.setSpeedrunValue(false);
|
|
||||||
getSettings().game.fastRoll.setSpeedrunValue(false);
|
|
||||||
getSettings().game.fastSpinner.setSpeedrunValue(false);
|
|
||||||
getSettings().game.armorRupeeDrain.setSpeedrunValue(MagicArmorMode::NORMAL);
|
|
||||||
getSettings().game.invincibleEnemies.setSpeedrunValue(false);
|
|
||||||
|
|
||||||
getSettings().game.pauseOnFocusLost.setSpeedrunValue(false);
|
|
||||||
aurora_set_pause_on_focus_lost(false);
|
|
||||||
|
|
||||||
getSettings().backend.enableAdvancedSettings.setSpeedrunValue(false);
|
|
||||||
getSettings().game.recordingMode.setSpeedrunValue(false);
|
|
||||||
getSettings().game.debugFlyCam.setSpeedrunValue(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear_speedrun_overrides() {
|
|
||||||
config::EnumerateRegistered([](config::ConfigVarBase& cvar) {
|
|
||||||
cvar.clearSpeedrunOverride();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
void restore_from_speedrun_mode() {
|
|
||||||
clear_speedrun_overrides();
|
|
||||||
aurora_set_pause_on_focus_lost(getSettings().game.pauseOnFocusLost.getValue());
|
|
||||||
}
|
|
||||||
|
|
||||||
std::filesystem::path normalized_display_path(const std::filesystem::path& path) {
|
std::filesystem::path normalized_display_path(const std::filesystem::path& path) {
|
||||||
std::error_code ec;
|
std::error_code ec;
|
||||||
auto normalized = std::filesystem::weakly_canonical(path, ec);
|
auto normalized = std::filesystem::weakly_canonical(path, ec);
|
||||||
@@ -407,6 +372,14 @@ bool gyro_enabled() {
|
|||||||
return getSettings().game.enableGyroAim || getSettings().game.enableGyroRollgoal;
|
return getSettings().game.enableGyroAim || getSettings().game.enableGyroRollgoal;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Rml::String touch_targeting_label(TouchTargeting targeting) {
|
||||||
|
const auto index = static_cast<std::size_t>(targeting);
|
||||||
|
if (index >= kTouchTargetingLabels.size()) {
|
||||||
|
return "Unknown";
|
||||||
|
}
|
||||||
|
return kTouchTargetingLabels[index];
|
||||||
|
}
|
||||||
|
|
||||||
struct ConfigBoolProps {
|
struct ConfigBoolProps {
|
||||||
Rml::String key;
|
Rml::String key;
|
||||||
Rml::String icon;
|
Rml::String icon;
|
||||||
@@ -668,7 +641,7 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
|||||||
leftPane.register_control(
|
leftPane.register_control(
|
||||||
leftPane.add_select_button({
|
leftPane.add_select_button({
|
||||||
.key = "Graphics Backend",
|
.key = "Graphics Backend",
|
||||||
.getValue = [] { return Rml::String{backend_name(configured_backend())}; },
|
.getValue = [] { return Rml::String{backend_name(aurora_get_backend())}; },
|
||||||
.isModified =
|
.isModified =
|
||||||
[] {
|
[] {
|
||||||
return getSettings().backend.graphicsBackend.getValue() !=
|
return getSettings().backend.graphicsBackend.getValue() !=
|
||||||
@@ -1003,6 +976,45 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
|||||||
pane.clear();
|
pane.clear();
|
||||||
pane.add_text("Open the touch controls layout editor.");
|
pane.add_text("Open the touch controls layout editor.");
|
||||||
});
|
});
|
||||||
|
leftPane.register_control(leftPane.add_select_button({
|
||||||
|
.key = "Touch Targeting",
|
||||||
|
.getValue =
|
||||||
|
[] {
|
||||||
|
return touch_targeting_label(
|
||||||
|
getSettings().game.touchTargeting.getValue());
|
||||||
|
},
|
||||||
|
.isDisabled =
|
||||||
|
[] { return !getSettings().game.enableTouchControls; },
|
||||||
|
.isModified =
|
||||||
|
[] {
|
||||||
|
const auto& targeting =
|
||||||
|
getSettings().game.touchTargeting;
|
||||||
|
return targeting.getValue() !=
|
||||||
|
targeting.getDefaultValue();
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
rightPane, [](Pane& pane) {
|
||||||
|
pane.clear();
|
||||||
|
for (int i = 0; i < static_cast<int>(kTouchTargetingLabels.size()); ++i) {
|
||||||
|
pane.add_button({
|
||||||
|
.text = kTouchTargetingLabels[i],
|
||||||
|
.isSelected =
|
||||||
|
[i] {
|
||||||
|
return getSettings().game.touchTargeting.getValue() ==
|
||||||
|
static_cast<TouchTargeting>(i);
|
||||||
|
},
|
||||||
|
})
|
||||||
|
.on_pressed([i] {
|
||||||
|
mDoAud_seStartMenu(kSoundItemChange);
|
||||||
|
getSettings().game.touchTargeting.setValue(
|
||||||
|
static_cast<TouchTargeting>(i));
|
||||||
|
config::Save();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
pane.add_rml(fmt::format("<br/>Hybrid: {}<br/>Hold: {}<br/>Switch: {}",
|
||||||
|
kTouchTargetingDescriptions[0], kTouchTargetingDescriptions[1],
|
||||||
|
kTouchTargetingDescriptions[2]));
|
||||||
|
});
|
||||||
config_percent_select(leftPane, rightPane, getSettings().game.touchCameraXSensitivity,
|
config_percent_select(leftPane, rightPane, getSettings().game.touchCameraXSensitivity,
|
||||||
"Touch Camera X Sensitivity",
|
"Touch Camera X Sensitivity",
|
||||||
"Adjusts touch camera horizontal sensitivity.<br/><br/>Applies to touch input only.",
|
"Adjusts touch camera horizontal sensitivity.<br/><br/>Applies to touch input only.",
|
||||||
@@ -1266,9 +1278,9 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
|||||||
.onChange =
|
.onChange =
|
||||||
[](bool enabled) {
|
[](bool enabled) {
|
||||||
if (enabled) {
|
if (enabled) {
|
||||||
reset_for_speedrun_mode();
|
resetForSpeedrunMode();
|
||||||
} else {
|
} else {
|
||||||
restore_from_speedrun_mode();
|
restoreFromSpeedrunMode();
|
||||||
if (getSettings().game.liveSplitEnabled) {
|
if (getSettings().game.liveSplitEnabled) {
|
||||||
speedrun::disconnectLiveSplit();
|
speedrun::disconnectLiveSplit();
|
||||||
}
|
}
|
||||||
@@ -1485,11 +1497,6 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
|||||||
.helpText = "When starting Dusklight, skip the main menu and boot straight into the "
|
.helpText = "When starting Dusklight, skip the main menu and boot straight into the "
|
||||||
"game if a disc image is available.",
|
"game if a disc image is available.",
|
||||||
});
|
});
|
||||||
config_bool_select(leftPane, rightPane, getSettings().backend.showPipelineCompilation,
|
|
||||||
{
|
|
||||||
.key = "Show Pipeline Compilation",
|
|
||||||
.helpText = "Show an overlay when shaders are being compiled for your hardware.",
|
|
||||||
});
|
|
||||||
config_bool_select(leftPane, rightPane, getSettings().backend.checkForUpdates,
|
config_bool_select(leftPane, rightPane, getSettings().backend.checkForUpdates,
|
||||||
{
|
{
|
||||||
.key = "Check for Updates",
|
.key = "Check for Updates",
|
||||||
|
|||||||
@@ -485,6 +485,32 @@ void TouchControls::set_control_pressed(Control control, bool pressed) {
|
|||||||
mLastLTapTime = {};
|
mLastLTapTime = {};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
switch (getSettings().game.touchTargeting.getValue()) {
|
||||||
|
case TouchTargeting::Hold:
|
||||||
|
mLPressed = pressed;
|
||||||
|
mLLatched = false;
|
||||||
|
mManualLLatched = false;
|
||||||
|
mLReleasePending = false;
|
||||||
|
mLPressStartTime = {};
|
||||||
|
mLastLTapTime = {};
|
||||||
|
break;
|
||||||
|
case TouchTargeting::Switch:
|
||||||
|
if (pressed) {
|
||||||
|
const bool wasLatched = mLPressed || mLLatched || mManualLLatched;
|
||||||
|
mLPressed = false;
|
||||||
|
mLLatched = false;
|
||||||
|
mManualLLatched = !wasLatched;
|
||||||
|
mLReleasePending = true;
|
||||||
|
} else {
|
||||||
|
mLPressed = false;
|
||||||
|
mLLatched = false;
|
||||||
|
mLReleasePending = false;
|
||||||
|
}
|
||||||
|
mLPressStartTime = {};
|
||||||
|
mLastLTapTime = {};
|
||||||
|
break;
|
||||||
|
case TouchTargeting::Hybrid:
|
||||||
|
default:
|
||||||
if (pressed && (mLLatched || mManualLLatched)) {
|
if (pressed && (mLLatched || mManualLLatched)) {
|
||||||
mLLatched = false;
|
mLLatched = false;
|
||||||
mManualLLatched = false;
|
mManualLLatched = false;
|
||||||
@@ -524,6 +550,8 @@ void TouchControls::set_control_pressed(Control control, bool pressed) {
|
|||||||
mLLatched = false;
|
mLLatched = false;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
case Control::R:
|
case Control::R:
|
||||||
mRTriggerHeld = pressed;
|
mRTriggerHeld = pressed;
|
||||||
break;
|
break;
|
||||||
@@ -635,6 +663,17 @@ void TouchControls::apply_control_transform(Control control) noexcept {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void TouchControls::sync_l_lock_state() noexcept {
|
void TouchControls::sync_l_lock_state() noexcept {
|
||||||
|
const auto targeting = getSettings().game.touchTargeting.getValue();
|
||||||
|
if (targeting == TouchTargeting::Hold) {
|
||||||
|
mLLatched = false;
|
||||||
|
mManualLLatched = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (targeting == TouchTargeting::Switch) {
|
||||||
|
mLLatched = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (player_attention_locked()) {
|
if (player_attention_locked()) {
|
||||||
if (mLPressed) {
|
if (mLPressed) {
|
||||||
mLLatched = true;
|
mLLatched = true;
|
||||||
|
|||||||
@@ -249,12 +249,12 @@ void main01(void) {
|
|||||||
goto eventsDone;
|
goto eventsDone;
|
||||||
case AURORA_PAUSED:
|
case AURORA_PAUSED:
|
||||||
dusk::audio::SetPaused(true);
|
dusk::audio::SetPaused(true);
|
||||||
dusk::mouse::onFocusLost();
|
dusk::mouse::on_focus_lost();
|
||||||
break;
|
break;
|
||||||
case AURORA_UNPAUSED:
|
case AURORA_UNPAUSED:
|
||||||
dusk::audio::SetPaused(false);
|
dusk::audio::SetPaused(false);
|
||||||
dusk::game_clock::reset_frame_timer();
|
dusk::game_clock::reset_frame_timer();
|
||||||
dusk::mouse::onFocusGained();
|
dusk::mouse::on_focus_gained();
|
||||||
break;
|
break;
|
||||||
case AURORA_SDL_EVENT:
|
case AURORA_SDL_EVENT:
|
||||||
dusk::mouse::handle_event(event->sdl);
|
dusk::mouse::handle_event(event->sdl);
|
||||||
|
|||||||
@@ -0,0 +1,189 @@
|
|||||||
|
"""
|
||||||
|
Loads d_a_mant.rel from CWD, applies tears using seed (66, 16983, 855) and cut type 1, writes PNGs to tear_textures/
|
||||||
|
Requires pillow and xxhash.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import math
|
||||||
|
import struct
|
||||||
|
import xxhash
|
||||||
|
from pathlib import Path
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
def yaz0_decompress(data):
|
||||||
|
expand_size = struct.unpack_from(">I", data, 4)[0]
|
||||||
|
out = bytearray(expand_size)
|
||||||
|
src_pos = 0x10
|
||||||
|
dst_pos = 0
|
||||||
|
chunk_bits_left = 0
|
||||||
|
chunk_bits = 0
|
||||||
|
|
||||||
|
while dst_pos < expand_size:
|
||||||
|
if chunk_bits_left == 0:
|
||||||
|
chunk_bits = data[src_pos]
|
||||||
|
src_pos += 1
|
||||||
|
chunk_bits_left = 8
|
||||||
|
|
||||||
|
if chunk_bits & 0x80:
|
||||||
|
out[dst_pos] = data[src_pos]
|
||||||
|
src_pos += 1
|
||||||
|
dst_pos += 1
|
||||||
|
else:
|
||||||
|
b0 = data[src_pos]
|
||||||
|
b1 = data[src_pos + 1]
|
||||||
|
src_pos += 2
|
||||||
|
dist = ((b0 & 0x0F) << 8) | b1
|
||||||
|
count = b0 >> 4
|
||||||
|
if count == 0:
|
||||||
|
count = data[src_pos] + 0x12
|
||||||
|
src_pos += 1
|
||||||
|
else:
|
||||||
|
count += 2
|
||||||
|
|
||||||
|
copy_pos = dst_pos - dist - 1
|
||||||
|
for _ in range(count):
|
||||||
|
out[dst_pos] = out[copy_pos]
|
||||||
|
dst_pos += 1
|
||||||
|
copy_pos += 1
|
||||||
|
|
||||||
|
chunk_bits <<= 1
|
||||||
|
chunk_bits_left -= 1
|
||||||
|
|
||||||
|
return bytes(out)
|
||||||
|
|
||||||
|
SINCOS_TABLE = tuple(
|
||||||
|
(
|
||||||
|
math.sin((i * math.tau) / (1 << 13)),
|
||||||
|
math.cos((i * math.tau) / (1 << 13)),
|
||||||
|
)
|
||||||
|
for i in range(1 << 13)
|
||||||
|
)
|
||||||
|
|
||||||
|
def rnd(rng):
|
||||||
|
rng[0] = (rng[0] * 171) % 30269
|
||||||
|
rng[1] = (rng[1] * 172) % 30307
|
||||||
|
rng[2] = (rng[2] * 170) % 30323
|
||||||
|
value = rng[0] / 30269.0 + rng[1] / 30307.0 + rng[2] / 30323.0
|
||||||
|
return abs(value % 1.0)
|
||||||
|
|
||||||
|
def rnd_f(rng, max_value):
|
||||||
|
return rnd(rng) * max_value
|
||||||
|
|
||||||
|
def rnd_fx(rng, max_value):
|
||||||
|
return max_value * (rnd(rng) - 0.5) * 2.0
|
||||||
|
|
||||||
|
def linear_index_to_swizzled(linear_index):
|
||||||
|
within_tile_x = linear_index & 0x7
|
||||||
|
tile_row_offset = (linear_index & 0x78) * 4
|
||||||
|
tile_column_offset = (linear_index >> 4) & 0x18
|
||||||
|
macro_row_offset = linear_index & 0x3E00
|
||||||
|
|
||||||
|
return within_tile_x + tile_row_offset + tile_column_offset + macro_row_offset
|
||||||
|
|
||||||
|
SWIZZLED_TO_XY = [(0, 0)] * 0x4000
|
||||||
|
for linear_index in range(0x4000):
|
||||||
|
x = linear_index & 0x7F
|
||||||
|
y = linear_index >> 7
|
||||||
|
swizzled_index = linear_index_to_swizzled(linear_index)
|
||||||
|
SWIZZLED_TO_XY[swizzled_index] = (x, y)
|
||||||
|
|
||||||
|
NEIGHBOR_OFFSETS = (0, 1, 0x80, 0x81, 2, 0x82, 0x102, 0x101, 0x100)
|
||||||
|
|
||||||
|
def write_c8_texture(c8_data, stage, output_dir, palette, palette_data):
|
||||||
|
min_index = min(c8_data)
|
||||||
|
max_index = max(c8_data)
|
||||||
|
tlut_offset = 2 * min_index
|
||||||
|
tlut_size = 2 * (max_index + 1 - min_index)
|
||||||
|
tlut_end = tlut_offset + tlut_size
|
||||||
|
path = output_dir / (
|
||||||
|
f"[{stage:02d}] tex1_{0x80}x{0x80}_"
|
||||||
|
f"{xxhash.xxh64(c8_data, seed=0).intdigest():016x}_"
|
||||||
|
f"{xxhash.xxh64(palette_data[tlut_offset:tlut_end], seed=0).intdigest():016x}_"
|
||||||
|
f"{0x9}.png"
|
||||||
|
)
|
||||||
|
|
||||||
|
rgba = Image.new("RGBA", (0x80, 0x80))
|
||||||
|
pixels = rgba.load()
|
||||||
|
for swizzled_index, palette_index in enumerate(c8_data):
|
||||||
|
x, y = SWIZZLED_TO_XY[swizzled_index]
|
||||||
|
pixels[x, y] = palette[palette_index]
|
||||||
|
rgba.save(path)
|
||||||
|
return path
|
||||||
|
|
||||||
|
def write_stage(tex, tex_u, pal, stage, output_dir, palette):
|
||||||
|
return [
|
||||||
|
write_c8_texture(bytes(tex), stage, output_dir, palette, pal),
|
||||||
|
write_c8_texture(bytes(tex_u), stage, output_dir, palette, pal),
|
||||||
|
]
|
||||||
|
|
||||||
|
def export_mant_tears():
|
||||||
|
rel = yaz0_decompress(Path("d_a_mant.rel").read_bytes())
|
||||||
|
tex = bytearray(rel[0x1C00 : 0x1C00 + 0x4000])
|
||||||
|
tex_u = bytearray([6] * 0x4000)
|
||||||
|
pal = bytes(rel[0x9C00 : 0x9C00 + 0x60])
|
||||||
|
rng = [int(66), int(16983), int(855)]
|
||||||
|
|
||||||
|
Path("tear_textures").mkdir(parents=True, exist_ok=True)
|
||||||
|
written = []
|
||||||
|
|
||||||
|
rgba_palette = []
|
||||||
|
for offset in range(0, len(pal), 2):
|
||||||
|
color16 = struct.unpack_from(">H", pal, offset)[0]
|
||||||
|
if color16 & 0x8000:
|
||||||
|
r = (color16 >> 7) & 0xF8
|
||||||
|
r |= r >> 5
|
||||||
|
g = (color16 >> 2) & 0xF8
|
||||||
|
g |= g >> 5
|
||||||
|
b = (color16 << 3) & 0xF8
|
||||||
|
b |= b >> 5
|
||||||
|
a = 255
|
||||||
|
else:
|
||||||
|
r = (color16 >> 4) & 0xF0
|
||||||
|
r |= r >> 4
|
||||||
|
g = color16 & 0xF0
|
||||||
|
g |= g >> 4
|
||||||
|
b = (color16 << 4) & 0xF0
|
||||||
|
b |= b >> 4
|
||||||
|
a = (color16 >> 7) & 0xE0
|
||||||
|
a |= (a >> 3) | (a >> 6)
|
||||||
|
rgba_palette.append((r, g, b, a))
|
||||||
|
while len(rgba_palette) < 256:
|
||||||
|
rgba_palette.append((0, 0, 0, 0))
|
||||||
|
|
||||||
|
written.extend(write_stage(tex, tex_u, pal, 0, Path("tear_textures"), rgba_palette))
|
||||||
|
|
||||||
|
cut_step = 0
|
||||||
|
for _ in range(15):
|
||||||
|
cut_step += 1
|
||||||
|
|
||||||
|
angle = int(rnd_f(rng, 65536.0)) & 0xFFFF
|
||||||
|
if angle >= 0x8000:
|
||||||
|
angle -= 0x10000
|
||||||
|
|
||||||
|
x = rnd_fx(rng, 32.0)
|
||||||
|
y = rnd_fx(rng, 32.0)
|
||||||
|
sincos_index = (angle & 0xFFFF) >> (16 - 13)
|
||||||
|
sin_v, cos_v = SINCOS_TABLE[sincos_index]
|
||||||
|
|
||||||
|
for i, texel_count in enumerate(
|
||||||
|
tuple(
|
||||||
|
1 if i <= 3 or i >= 26 else (9 if 12 <= i <= 18 else 4)
|
||||||
|
for i in range(30)
|
||||||
|
)
|
||||||
|
):
|
||||||
|
x += sin_v
|
||||||
|
y -= cos_v
|
||||||
|
|
||||||
|
packed = int(x + 64.0) | (int(y + 64.0) << 7)
|
||||||
|
for j in range(texel_count):
|
||||||
|
u_var1 = packed + NEIGHBOR_OFFSETS[j]
|
||||||
|
if 0 <= u_var1 < 0x4000:
|
||||||
|
i_var5 = linear_index_to_swizzled(u_var1)
|
||||||
|
tex[i_var5] = 0
|
||||||
|
tex_u[i_var5] = 0
|
||||||
|
|
||||||
|
written.extend(write_stage(tex, tex_u, pal, cut_step, Path("tear_textures"), rgba_palette))
|
||||||
|
|
||||||
|
return written
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
export_mant_tears()
|
||||||
Reference in New Issue
Block a user