Compare commits

..

3 Commits

Author SHA1 Message Date
madeline 1520205403 Merge branch 'main' of https://github.com/TakaRikka/dusk into vmem 2026-04-28 02:52:17 -07:00
madeline d2d7459d05 more granular heap grows 2026-04-28 02:49:24 -07:00
madeline c71272af05 virtual memory and actor spawner 2026-04-28 02:25:18 -07:00
138 changed files with 1482 additions and 11267 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
Language: Cpp Language: Cpp
Standard: C++03 Standard: C++03
AccessModifierOffset: -4 AccessModifierOffset: -4
AlignAfterOpenBracket: DontAlign AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false AlignConsecutiveDeclarations: false
AlignOperands: true AlignOperands: true
-1
View File
@@ -100,7 +100,6 @@ if (CMAKE_SYSTEM_NAME STREQUAL Linux)
endif () endif ()
set(AURORA_ENABLE_DVD ON CACHE BOOL "Enable DVD API support" FORCE) set(AURORA_ENABLE_DVD ON CACHE BOOL "Enable DVD API support" FORCE)
set(AURORA_ENABLE_CARD ON CACHE BOOL "Enable CARD API support" FORCE) set(AURORA_ENABLE_CARD ON CACHE BOOL "Enable CARD API support" FORCE)
set(AURORA_ENABLE_RMLUI ON CACHE BOOL "Enable RmlUi UI support" FORCE)
add_subdirectory(extern/aurora EXCLUDE_FROM_ALL) add_subdirectory(extern/aurora EXCLUDE_FROM_ALL)
add_subdirectory(libs/freeverb) add_subdirectory(libs/freeverb)
+1 -7
View File
@@ -1,12 +1,8 @@
![DuskLogo](res/logo-mascot.png) ![DuskLogo](res/logo-mascot.webp)
- ### **[Official Website](https://twilitrealm.dev)** - ### **[Official Website](https://twilitrealm.dev)**
- ### **[Discord](https://discord.gg/QACynxeyna)** - ### **[Discord](https://discord.gg/QACynxeyna)**
# Overview
Dusk is a reverse-engineered reimplementation of Twilight Princess.
It aims to be as accurate as possible to the original while also providing new options, enhancements, and tools to customize your experience.
# Setup # Setup
**⚠️ Dusk does NOT provide any copyrighted assets. You must provide your own copy of the game.** **⚠️ Dusk does NOT provide any copyrighted assets. You must provide your own copy of the game.**
@@ -31,7 +27,5 @@ First make sure your dump of the game is clean and supported by Dusk. You can do
# Building # Building
If you'd like to build Dusk from source, please read the [build instructions](docs/building.md). If you'd like to build Dusk from source, please read the [build instructions](docs/building.md).
Pull Requests are welcomed! Note that we do not accept contributions that are primarily AI generated and will close your PR if we suspect as much.
# Credits # Credits
Special thanks to the [TP decompilation](https://github.com/zeldaret/tp) team, the GC/Wii decompilation community, the [Aurora](https://github.com/encounter/aurora) developers, the [TP speedrunning community](https://zsrtp.link), and all [contributors](https://github.com/TwilitRealm/dusk/graphs/contributors). Special thanks to the [TP decompilation](https://github.com/zeldaret/tp) team, the GC/Wii decompilation community, the [Aurora](https://github.com/encounter/aurora) developers, the [TP speedrunning community](https://zsrtp.link), and all [contributors](https://github.com/TwilitRealm/dusk/graphs/contributors).
+1 -1
+3 -42
View File
@@ -1,7 +1,7 @@
set(DOLZEL_FILES set(DOLZEL_FILES
src/m_Do/m_Do_main.cpp src/m_Do/m_Do_main.cpp
#src/m_Do/m_Do_printf.cpp src/m_Do/m_Do_printf.cpp
src/m_Do/m_Do_audio.cpp src/m_Do/m_Do_audio.cpp
src/m_Do/m_Do_controller_pad.cpp src/m_Do/m_Do_controller_pad.cpp
#src/m_Do/m_Re_controller_pad.cpp #src/m_Do/m_Re_controller_pad.cpp
@@ -1429,7 +1429,6 @@ set(DUSK_FILES
src/dusk/globals.cpp src/dusk/globals.cpp
src/dusk/gyro.cpp src/dusk/gyro.cpp
src/dusk/gamepad_color.cpp src/dusk/gamepad_color.cpp
src/dusk/autosave.cpp
src/dusk/io.cpp src/dusk/io.cpp
src/dusk/layout.cpp src/dusk/layout.cpp
src/dusk/logging.cpp src/dusk/logging.cpp
@@ -1454,6 +1453,7 @@ set(DUSK_FILES
src/dusk/imgui/ImGuiProcessOverlay.cpp src/dusk/imgui/ImGuiProcessOverlay.cpp
src/dusk/imgui/ImGuiCameraOverlay.cpp src/dusk/imgui/ImGuiCameraOverlay.cpp
src/dusk/imgui/ImGuiHeapOverlay.cpp src/dusk/imgui/ImGuiHeapOverlay.cpp
src/dusk/imgui/ImGuiActorSpawner.cpp
src/dusk/imgui/ImGuiDebugPad.cpp src/dusk/imgui/ImGuiDebugPad.cpp
src/dusk/imgui/ImGuiControllerOverlay.cpp src/dusk/imgui/ImGuiControllerOverlay.cpp
src/dusk/imgui/ImGuiStubLog.cpp src/dusk/imgui/ImGuiStubLog.cpp
@@ -1463,51 +1463,12 @@ set(DUSK_FILES
src/dusk/imgui/ImGuiStateShare.cpp src/dusk/imgui/ImGuiStateShare.cpp
src/dusk/imgui/ImGuiAchievements.hpp src/dusk/imgui/ImGuiAchievements.hpp
src/dusk/imgui/ImGuiAchievements.cpp src/dusk/imgui/ImGuiAchievements.cpp
src/dusk/ui/bool_button.cpp
src/dusk/ui/bool_button.hpp
src/dusk/ui/button.cpp
src/dusk/ui/button.hpp
src/dusk/ui/component.cpp
src/dusk/ui/component.hpp
src/dusk/ui/document.cpp
src/dusk/ui/document.hpp
src/dusk/ui/editor.cpp
src/dusk/ui/editor.hpp
src/dusk/ui/event.cpp
src/dusk/ui/event.hpp
src/dusk/ui/input.cpp
src/dusk/ui/input.hpp
src/dusk/ui/nav_types.hpp
src/dusk/ui/number_button.cpp
src/dusk/ui/number_button.hpp
src/dusk/ui/overlay.cpp
src/dusk/ui/overlay.hpp
src/dusk/ui/pane.cpp
src/dusk/ui/pane.hpp
src/dusk/ui/popup.cpp
src/dusk/ui/popup.hpp
src/dusk/ui/prelaunch.cpp
src/dusk/ui/prelaunch.hpp
src/dusk/ui/prelaunch_options.cpp
src/dusk/ui/prelaunch_options.hpp
src/dusk/ui/select_button.cpp
src/dusk/ui/select_button.hpp
src/dusk/ui/settings.cpp
src/dusk/ui/settings.hpp
src/dusk/ui/string_button.cpp
src/dusk/ui/string_button.hpp
src/dusk/ui/tab_bar.cpp
src/dusk/ui/tab_bar.hpp
src/dusk/ui/ui.cpp
src/dusk/ui/ui.hpp
src/dusk/ui/window.cpp
src/dusk/ui/window.hpp
src/dusk/achievements.cpp src/dusk/achievements.cpp
src/dusk/iso_validate.cpp src/dusk/iso_validate.cpp
src/dusk/livesplit.cpp src/dusk/livesplit.cpp
src/dusk/offset_ptr.cpp src/dusk/offset_ptr.cpp
src/dusk/vmem.cpp
src/dusk/OSContext.cpp src/dusk/OSContext.cpp
src/dusk/OSReport.cpp
src/dusk/OSThread.cpp src/dusk/OSThread.cpp
src/dusk/OSMutex.cpp src/dusk/OSMutex.cpp
src/dusk/discord_presence.cpp src/dusk/discord_presence.cpp
-1
View File
@@ -27,7 +27,6 @@ public:
/* 0x17C */ cXyz mViewScale; /* 0x17C */ cXyz mViewScale;
#if TARGET_PC #if TARGET_PC
bool mbReset = false; bool mbReset = false;
bool mbHadEntry = false;
#endif #endif
}; };
-4
View File
@@ -91,10 +91,6 @@ public:
void calcCursor(); void calcCursor();
void drawCursor(); void drawCursor();
#if TARGET_PC
void dMapBgWide();
#endif
void setDPDFloorSelCurPos(s8 i_pos) { field_0xdd6 = i_pos; } void setDPDFloorSelCurPos(s8 i_pos) { field_0xdd6 = i_pos; }
f32 getMapWidth() { return mMapWidth; } f32 getMapWidth() { return mMapWidth; }
-8
View File
@@ -81,10 +81,6 @@ public:
void calcDrawPriority(); void calcDrawPriority();
void setArrowPosAxis(f32, f32); void setArrowPosAxis(f32, f32);
#if TARGET_PC
void fMapBackWide();
#endif
virtual void draw(); virtual void draw();
virtual ~dMenu_Fmap2DBack_c(); virtual ~dMenu_Fmap2DBack_c();
@@ -334,10 +330,6 @@ public:
void setHIO(bool); void setHIO(bool);
bool isWarpAccept(); bool isWarpAccept();
#if TARGET_PC
void fMapTopWide();
#endif
virtual void draw(); virtual void draw();
virtual ~dMenu_Fmap2DTop_c(); virtual ~dMenu_Fmap2DTop_c();
-3
View File
@@ -67,9 +67,6 @@ public:
bool isStaffMessage(); bool isStaffMessage();
bool isSaveMessage(); bool isSaveMessage();
bool isTalkMessage(); bool isTalkMessage();
#if TARGET_PC
bool isShopItemMessage();
#endif
const char* getSmellName(); const char* getSmellName();
const char* getPortalName(); const char* getPortalName();
const char* getBombName(); const char* getBombName();
-9
View File
@@ -4,8 +4,6 @@
#include <functional> #include <functional>
#include <queue> #include <queue>
#include <string> #include <string>
#include <string_view>
#include <unordered_set>
#include <vector> #include <vector>
#include "nlohmann/json.hpp" #include "nlohmann/json.hpp"
@@ -16,7 +14,6 @@ enum class AchievementCategory : uint8_t {
Collection, Collection,
Challenge, Challenge,
Minigame, Minigame,
Misc,
Glitched Glitched
}; };
@@ -43,11 +40,6 @@ public:
void save(); void save();
void tick(); void tick();
void clearAll(); void clearAll();
void clearOne(const char* key);
// Signals are visible to all achievement checks within the same tick, then cleared.
void signal(const char* key);
bool hasSignal(const char* key) const;
std::vector<Achievement> getAchievements() const; std::vector<Achievement> getAchievements() const;
bool hasPendingUnlock() const { return !m_pendingUnlocks.empty(); } bool hasPendingUnlock() const { return !m_pendingUnlocks.empty(); }
@@ -65,7 +57,6 @@ private:
void processEntry(Entry& e); void processEntry(Entry& e);
std::vector<Entry> m_entries; std::vector<Entry> m_entries;
std::unordered_set<std::string_view> m_signals;
bool m_loaded = false; bool m_loaded = false;
bool m_dirty = false; bool m_dirty = false;
std::queue<std::string> m_pendingUnlocks; std::queue<std::string> m_pendingUnlocks;
-17
View File
@@ -1,17 +0,0 @@
#pragma once
#ifndef AUTOSAVE_H
#define AUTOSAVE_H
#include <m_Do/m_Do_MemCardRWmng.h>
#include <m_Do/m_Do_MemCard.h>
void noAutoSave();
void triggerAutoSave();
void updateAutoSave();
void enterAutoSave();
void autoSaving();
void waitingForWrite();
void endAutoSave();
#endif
-10
View File
@@ -1,10 +0,0 @@
#ifndef DUSK_MEMORY_H
#define DUSK_MEMORY_H
#if TARGET_PC
#define HEAP_SIZE(original, dusk) (dusk)
#else
#define HEAP_SIZE(original, dusk) (original)
#endif
#endif
-3
View File
@@ -55,7 +55,6 @@ struct UserSettings {
ConfigVar<int> soundEffectsVolume; ConfigVar<int> soundEffectsVolume;
ConfigVar<int> fanfareVolume; ConfigVar<int> fanfareVolume;
ConfigVar<bool> enableReverb; ConfigVar<bool> enableReverb;
ConfigVar<bool> enableHrtf;
} audio; } audio;
// Game settings // Game settings
@@ -72,7 +71,6 @@ struct UserSettings {
ConfigVar<bool> disableRupeeCutscenes; ConfigVar<bool> disableRupeeCutscenes;
ConfigVar<bool> noSwordRecoil; ConfigVar<bool> noSwordRecoil;
ConfigVar<int> damageMultiplier; ConfigVar<int> damageMultiplier;
ConfigVar<bool> hyperEnemies;
ConfigVar<bool> noHeartDrops; ConfigVar<bool> noHeartDrops;
ConfigVar<bool> instantDeath; ConfigVar<bool> instantDeath;
ConfigVar<bool> fastClimbing; ConfigVar<bool> fastClimbing;
@@ -82,7 +80,6 @@ struct UserSettings {
ConfigVar<bool> instantSaves; ConfigVar<bool> instantSaves;
ConfigVar<bool> instantText; ConfigVar<bool> instantText;
ConfigVar<bool> sunsSong; ConfigVar<bool> sunsSong;
ConfigVar<bool> autoSave;
// Preferences // Preferences
ConfigVar<bool> enableMirrorMode; ConfigVar<bool> enableMirrorMode;
+54
View File
@@ -0,0 +1,54 @@
#pragma once
#include <stddef.h>
#ifndef __cplusplus
#include <stdbool.h>
#endif
#ifdef __cplusplus
namespace dusk {
#endif
// Reserve a contiguous virtual address range without committing physical pages
void* vmem_reserve(size_t size);
// Commit physical backing for pages in a previously reserved range, ptr and size should be page-aligned
bool vmem_commit(void* ptr, size_t size);
// Decommit physical pages in a reserved range, releasing RAM without releasing address space
void vmem_decommit(void* ptr, size_t size);
// Release an entire virtual reservation obtained from vmem_reserve
void vmem_release(void* ptr, size_t size);
// Returns the OS page size
size_t vmem_page_size();
// Shared vmem arena
// All JKR heap vmem reservations are sub-allocated from a single large reservation,
// keeping the total entry count at 1 regardless of how many heaps exist
// Must be called once before any JKR heap is created
void vmem_arena_init();
// Allocate a slot of size bytes (page-aligned) from the arena
void* vmem_arena_alloc(size_t size);
// Return a slot to the arena and decommit its physical pages
void vmem_arena_free(void* ptr, size_t size);
#ifdef __cplusplus
} // namespace dusk
// Total virtual address space reserved for the shared JKR heap arena
inline constexpr size_t JKR_VMEM_ARENA_SIZE = 128ULL * 1024 * 1024 * 1024; // 128 GB
// Virtual address space reserved per JKR heap (one slot in the shared arena)
inline constexpr size_t JKR_HEAP_VIRTUAL_RESERVE = 64ULL * 1024 * 1024; // 64 MB
// Minimum growth increment when a JKR heap expands into reserved but uncommitted pages
inline constexpr size_t JKR_HEAP_GROW_CHUNK = 4ULL * 1024 * 1024; // 4 MB
// Maximum number of free slots the arena can track (= total slots in the arena)
inline constexpr size_t JKR_VMEM_MAX_FREE_SLOTS = JKR_VMEM_ARENA_SIZE / JKR_HEAP_VIRTUAL_RESERVE;
#endif
@@ -59,9 +59,6 @@ public:
bool isActive() const { return mSeqList.getNumLinks() != 0; } bool isActive() const { return mSeqList.getNumLinks() != 0; }
int getNumActiveSeqs() const { return mSeqList.getNumLinks(); } int getNumActiveSeqs() const { return mSeqList.getNumLinks(); }
void pause(bool paused) { mActivity.field_0x0.flags.flag2 = paused; } void pause(bool paused) { mActivity.field_0x0.flags.flag2 = paused; }
#if TARGET_PC
JSUList<JAISeq>* getSeqList() { return &mSeqList; }
#endif
private: private:
/* 0x08 */ JAIAudience* mAudience; /* 0x08 */ JAIAudience* mAudience;
@@ -127,6 +127,13 @@ public:
[[nodiscard]] const CMemBlock* getFreeHead() const { return mHeadFreeList; } [[nodiscard]] const CMemBlock* getFreeHead() const { return mHeadFreeList; }
[[nodiscard]] CMemBlock* getUsedHead() { return mHeadUsedList; } [[nodiscard]] CMemBlock* getUsedHead() { return mHeadUsedList; }
[[nodiscard]] const CMemBlock* getUsedHead() const { return mHeadUsedList; } [[nodiscard]] const CMemBlock* getUsedHead() const { return mHeadUsedList; }
void* mVmemBase; // base of VM reservation
size_t mVmemCapacity; // total reserved bytes
size_t mVmemCommitted; // page-aligned committed bytes so far
// Commit more pages and splice them into the free list
bool growHeap(u32 needed);
#endif #endif
}; };
@@ -61,6 +61,15 @@ public:
static JKRSolidHeap* create(u32, JKRHeap*, bool); static JKRSolidHeap* create(u32, JKRHeap*, bool);
static void* getState_(TState* state) { return getState_buf_(state); } static void* getState_(TState* state) { return getState_buf_(state); }
#if TARGET_PC
void* mVmemBase; // base of VM reservation
size_t mVmemCapacity; // total reserved bytes
size_t mVmemCommitted; // page-aligned committed bytes so far
// Commit more pages and extend the free region
bool growHeap(u32 needed);
#endif
}; };
inline JKRSolidHeap* JKRCreateSolidHeap(u32 param_0, JKRHeap* heap, bool param_2) { inline JKRSolidHeap* JKRCreateSolidHeap(u32 param_0, JKRHeap* heap, bool param_2) {
@@ -207,11 +207,4 @@ void JPARegistAlphaEnv(JPAEmitterWorkData*, JPABaseParticle*);
void JPARegistPrmAlpha(JPAEmitterWorkData*, JPABaseParticle*); void JPARegistPrmAlpha(JPAEmitterWorkData*, JPABaseParticle*);
void JPARegistPrmAlphaEnv(JPAEmitterWorkData*, JPABaseParticle*); void JPARegistPrmAlphaEnv(JPAEmitterWorkData*, JPABaseParticle*);
#if TARGET_PC
void JPAInterpBillboard(JPAEmitterWorkData*, JPABaseParticle*);
void JPAInterpRotBillboard(JPAEmitterWorkData*, JPABaseParticle*);
void JPAInterpDirection(JPAEmitterWorkData*, JPABaseParticle*);
void JPAInterpRotDirection(JPAEmitterWorkData*, JPABaseParticle*);
#endif
#endif /* JPABASESHAPE_H */ #endif /* JPABASESHAPE_H */
@@ -24,9 +24,6 @@ public:
void init_c(JPAEmitterWorkData*, JPABaseParticle*); void init_c(JPAEmitterWorkData*, JPABaseParticle*);
bool calc_p(JPAEmitterWorkData*); bool calc_p(JPAEmitterWorkData*);
bool calc_c(JPAEmitterWorkData*); bool calc_c(JPAEmitterWorkData*);
#if TARGET_PC
void interp(JPAEmitterWorkData*, void const* drawFunc);
#endif
bool canCreateChild(JPAEmitterWorkData*); bool canCreateChild(JPAEmitterWorkData*);
f32 getWidth(JPABaseEmitter const*) const; f32 getWidth(JPABaseEmitter const*) const;
f32 getHeight(JPABaseEmitter const*) const; f32 getHeight(JPABaseEmitter const*) const;
@@ -40,9 +40,6 @@ public:
JUTTransparency getTransparency() const { return JUTTransparency(mTransparency); } JUTTransparency getTransparency() const { return JUTTransparency(mTransparency); }
u16 getNumColors() const { return mNumColors; } u16 getNumColors() const { return mNumColors; }
ResTLUT* getColorTable() const { return mColorTable; } ResTLUT* getColorTable() const { return mColorTable; }
#if TARGET_PC
void dataUploaded();
#endif
private: private:
/* 0x00 */ GXTlutObj mTlutObj; /* 0x00 */ GXTlutObj mTlutObj;
@@ -75,7 +75,6 @@ public:
s32 getTransparency() const { return mTexInfo->alphaEnabled; } s32 getTransparency() const { return mTexInfo->alphaEnabled; }
s32 getWidth() const { return mTexInfo->width; } s32 getWidth() const { return mTexInfo->width; }
s32 getHeight() const { return mTexInfo->height; } s32 getHeight() const { return mTexInfo->height; }
JUTPalette* getPalette() const { return mPalette; }
void setCaptureFlag(bool flag) { mFlags &= 2 | flag; } void setCaptureFlag(bool flag) { mFlags &= 2 | flag; }
bool getCaptureFlag() const { return mFlags & 1; } bool getCaptureFlag() const { return mFlags & 1; }
bool getEmbPaletteDelFlag() const { return mFlags & 2; } bool getEmbPaletteDelFlag() const { return mFlags & 2; }
@@ -83,7 +82,7 @@ public:
int getTlutName() const { return mTlutName; } int getTlutName() const { return mTlutName; }
bool operator==(const JUTTexture& other) { bool operator==(const JUTTexture& other) {
return mTexInfo == other.mTexInfo return mTexInfo == other.mTexInfo
&& mPalette == other.mPalette && field_0x2c == other.field_0x2c
&& mWrapS == other.mWrapS && mWrapS == other.mWrapS
&& mWrapT == other.mWrapT && mWrapT == other.mWrapT
&& mMinFilter == other.mMinFilter && mMinFilter == other.mMinFilter
@@ -101,7 +100,7 @@ private:
/* 0x20 */ const ResTIMG* mTexInfo; /* 0x20 */ const ResTIMG* mTexInfo;
/* 0x24 */ void* mTexData; /* 0x24 */ void* mTexData;
/* 0x28 */ JUTPalette* mEmbPalette; /* 0x28 */ JUTPalette* mEmbPalette;
/* 0x2C */ JUTPalette* mPalette; /* 0x2C */ JUTPalette* field_0x2c;
/* 0x30 */ u8 mWrapS; /* 0x30 */ u8 mWrapS;
/* 0x31 */ u8 mWrapT; /* 0x31 */ u8 mWrapT;
/* 0x32 */ u8 mMinFilter; /* 0x32 */ u8 mMinFilter;
+1 -9
View File
@@ -1,9 +1,6 @@
#include "JSystem/JSystem.h" // IWYU pragma: keep #include "JSystem/JSystem.h" // IWYU pragma: keep
#include "JSystem/JAudio2/JASChannel.h" #include "JSystem/JAudio2/JASChannel.h"
#if TARGET_PC
#include "dusk/audio/DuskDsp.hpp"
#endif
#include "JSystem/JAudio2/JASAiCtrl.h" #include "JSystem/JAudio2/JASAiCtrl.h"
#include "JSystem/JAudio2/JASCalc.h" #include "JSystem/JAudio2/JASCalc.h"
#include "JSystem/JAudio2/JASDriverIF.h" #include "JSystem/JAudio2/JASDriverIF.h"
@@ -173,12 +170,7 @@ void JASChannel::updateEffectorParam(JASDsp::TChannel* i_channel, u16* i_mixerVo
f32 pan = 0.5f; f32 pan = 0.5f;
f32 dolby = 0.0f; f32 dolby = 0.0f;
#if TARGET_PC switch (JASDriver::getOutputMode()) {
u32 effectiveOutputMode = dusk::audio::EnableHrtf ? JAS_OUTPUT_SURROUND : JASDriver::getOutputMode();
#else
u32 effectiveOutputMode = JASDriver::getOutputMode();
#endif
switch (effectiveOutputMode) {
case JAS_OUTPUT_MONO: case JAS_OUTPUT_MONO:
break; break;
case JAS_OUTPUT_STEREO: case JAS_OUTPUT_STEREO:
+1
View File
@@ -302,6 +302,7 @@ void JASKernel::setupRootHeap(JKRSolidHeap* heap, u32 size) {
JKRHEAP_NAME(sSystemHeap, "JASKernel::sSystemHeap"); JKRHEAP_NAME(sSystemHeap, "JASKernel::sSystemHeap");
JUT_ASSERT(787, sSystemHeap); JUT_ASSERT(787, sSystemHeap);
sCommandHeap = JKR_NEW_ARGS (heap, 0) JASMemChunkPool<1024, JASThreadingModel::ObjectLevelLockable>; sCommandHeap = JKR_NEW_ARGS (heap, 0) JASMemChunkPool<1024, JASThreadingModel::ObjectLevelLockable>;
JKRHEAP_NAME(sSystemHeap, "JASKernel::sCommandHeap");
JUT_ASSERT(790, sCommandHeap); JUT_ASSERT(790, sCommandHeap);
JASDram = heap; JASDram = heap;
} }
@@ -442,7 +442,6 @@ static JAUSectionHeap* JAUNewSectionHeap(JKRSolidHeap* heap, bool param_1) {
JAUSectionHeap* JAUNewSectionHeap(bool param_0) { JAUSectionHeap* JAUNewSectionHeap(bool param_0) {
s32 freeSize = JASDram->getFreeSize(); s32 freeSize = JASDram->getFreeSize();
JKRSolidHeap* sectionHeap = JKRCreateSolidHeap(freeSize, JASDram, true); JKRSolidHeap* sectionHeap = JKRCreateSolidHeap(freeSize, JASDram, true);
JKRHEAP_NAME(sectionHeap, "sectionHeap");
JUT_ASSERT(821, sectionHeap); JUT_ASSERT(821, sectionHeap);
return JAUNewSectionHeap(sectionHeap, param_0); return JAUNewSectionHeap(sectionHeap, param_0);
} }
+125 -13
View File
@@ -10,6 +10,11 @@
#include "JSystem/JUtility/JUTConsole.h" #include "JSystem/JUtility/JUTConsole.h"
#include "JSystem/JUtility/JUTException.h" #include "JSystem/JUtility/JUTException.h"
#include <cstdlib> #include <cstdlib>
#if TARGET_PC
#include "dusk/vmem.h"
#include <algorithm>
#include "dusk/logging.h"
#endif
JKRExpHeap* JKRExpHeap::createRoot(int maxHeaps, bool errorFlag) { JKRExpHeap* JKRExpHeap::createRoot(int maxHeaps, bool errorFlag) {
JKRExpHeap* heap = NULL; JKRExpHeap* heap = NULL;
@@ -71,21 +76,49 @@ JKRExpHeap* JKRExpHeap::create(u32 size, JKRHeap* parent, bool errorFlag) {
u32 alignedSize = ALIGN_PREV(size, 0x10); u32 alignedSize = ALIGN_PREV(size, 0x10);
if (alignedSize < expHeapSize + blockSize) if (alignedSize < expHeapSize + blockSize) {
return NULL; return NULL;
}
#if TARGET_PC
u8* vmemBase = (u8*)dusk::vmem_arena_alloc(JKR_HEAP_VIRTUAL_RESERVE);
if (!vmemBase) {
return NULL;
}
const size_t pageSize = dusk::vmem_page_size();
size_t commitSize = ALIGN_NEXT((size_t)alignedSize, pageSize);
if (!dusk::vmem_commit(vmemBase, commitSize)) {
dusk::vmem_arena_free(vmemBase, JKR_HEAP_VIRTUAL_RESERVE);
return NULL;
}
u8* memory = vmemBase;
u8* dataPtr = memory + expHeapSize;
newHeap = JKR_NEW_ARGS(memory) JKRExpHeap(dataPtr, alignedSize - expHeapSize, parent, errorFlag);
if (newHeap == NULL) {
dusk::vmem_arena_free(vmemBase, JKR_HEAP_VIRTUAL_RESERVE);
return NULL;
}
newHeap->mVmemBase = vmemBase;
newHeap->mVmemCapacity = JKR_HEAP_VIRTUAL_RESERVE;
newHeap->mVmemCommitted = commitSize;
#else
u8* memory = (u8*)JKRAllocFromHeap(parent, alignedSize, 0x10); u8* memory = (u8*)JKRAllocFromHeap(parent, alignedSize, 0x10);
u8* dataPtr = (memory + expHeapSize); u8* dataPtr = memory + expHeapSize;
if (!memory) { if (!memory) {
return NULL; return NULL;
} }
newHeap = JKR_NEW_ARGS (memory) JKRExpHeap(dataPtr, alignedSize - expHeapSize, parent, errorFlag); newHeap = JKR_NEW_ARGS(memory) JKRExpHeap(dataPtr, alignedSize - expHeapSize, parent, errorFlag);
if (newHeap == NULL) { if (newHeap == NULL) {
JKRFree(memory); JKRFree(memory);
return NULL; return NULL;
} }
#endif
#if DEBUG #if DEBUG
if (newHeap) { if (newHeap) {
u8* local_30 = dataPtr + sizeof(CMemBlock); u8* local_30 = dataPtr + sizeof(CMemBlock);
@@ -102,9 +135,16 @@ JKRExpHeap* JKRExpHeap::create(u32 size, JKRHeap* parent, bool errorFlag) {
JKRExpHeap* JKRExpHeap::create(void* ptr, u32 size, JKRHeap* parent, bool errorFlag) { JKRExpHeap* JKRExpHeap::create(void* ptr, u32 size, JKRHeap* parent, bool errorFlag) {
JKRHeap* parent2; JKRHeap* parent2;
if (parent == NULL) { if (parent == NULL) {
#if TARGET_PC
// VM-backed heaps live outside the root heap's address range, so find() fails
// findAllHeap() searches the full tree
parent2 = getRootHeap()->findAllHeap(ptr);
#else
parent2 = getRootHeap()->find(ptr); parent2 = getRootHeap()->find(ptr);
if (!parent2) #endif
if (!parent2) {
return NULL; return NULL;
}
} else { } else {
parent2 = parent; parent2 = parent;
} }
@@ -136,6 +176,15 @@ JKRExpHeap* JKRExpHeap::create(void* ptr, u32 size, JKRHeap* parent, bool errorF
} }
void JKRExpHeap::do_destroy() { void JKRExpHeap::do_destroy() {
#if TARGET_PC
if (mVmemBase) {
void* vmemBase = mVmemBase;
size_t vmemCapacity = mVmemCapacity;
this->~JKRExpHeap();
dusk::vmem_arena_free(vmemBase, vmemCapacity);
return;
}
#endif
if (!field_0x6e) { if (!field_0x6e) {
JKRHeap* heap = getParent(); JKRHeap* heap = getParent();
if (heap) { if (heap) {
@@ -163,6 +212,11 @@ JKRExpHeap::JKRExpHeap(void* data, u32 size, JKRHeap* parent, bool errorFlag)
mHeadFreeList->initiate(NULL, NULL, size - sizeof(CMemBlock), 0, 0); mHeadFreeList->initiate(NULL, NULL, size - sizeof(CMemBlock), 0, 0);
mHeadUsedList = NULL; mHeadUsedList = NULL;
mTailUsedList = NULL; mTailUsedList = NULL;
#if TARGET_PC
mVmemBase = nullptr;
mVmemCapacity = 0;
mVmemCommitted = 0;
#endif
} }
JKRExpHeap::~JKRExpHeap() { JKRExpHeap::~JKRExpHeap() {
@@ -214,6 +268,24 @@ void* JKRExpHeap::do_alloc(u32 size, int alignment) {
#endif #endif
#if TARGET_PC #if TARGET_PC
if (!ptr && mVmemBase) {
// Heap is full, commit the next chunk of reserved VM and retry
if (growHeap(size)) {
if (alignment >= 0) {
if (alignment <= 4) {
ptr = allocFromHead(size);
} else {
ptr = allocFromHead(size, alignment);
}
} else {
if (-alignment <= 4) {
ptr = allocFromTail(size);
} else {
ptr = allocFromTail(size, -alignment);
}
}
}
}
if (!ptr) { if (!ptr) {
// Allocation failed. // Allocation failed.
OSReport_Error( OSReport_Error(
@@ -222,11 +294,16 @@ void* JKRExpHeap::do_alloc(u32 size, int alignment) {
OSReport_Error("Free block list as follows:\n"); OSReport_Error("Free block list as follows:\n");
OSReport_Error("Start | End | Size \n"); OSReport_Error("Start | End | Size \n");
int i = 0;
for (const CMemBlock* block = mHeadFreeList; block; block = block->mNext) { for (const CMemBlock* block = mHeadFreeList; block; block = block->mNext) {
if (block->mMagic) { if (block->mMagic) {
// Allocated, ignore. // Allocated, ignore.
continue; continue;
} }
if (i++ > 10) {
OSReport_Error("<more>\n");
break;
}
auto blockStart = (uintptr_t)block - (uintptr_t)mStart; auto blockStart = (uintptr_t)block - (uintptr_t)mStart;
auto blockEnd = (uintptr_t)block + block->size - (uintptr_t)mStart; auto blockEnd = (uintptr_t)block + block->size - (uintptr_t)mStart;
@@ -234,14 +311,6 @@ void* JKRExpHeap::do_alloc(u32 size, int alignment) {
OSReport_Error("%08X | %08X | %08X\n", (u32) blockStart, (u32) blockEnd, (u32) blockSize); OSReport_Error("%08X | %08X | %08X\n", (u32) blockStart, (u32) blockEnd, (u32) blockSize);
} }
OSReport_Error("Child heaps as follows:\n");
OSReport_Error("Start | End | Name \n");
const JSUTree<JKRHeap>& tree = getHeapTree();
for (JSUTreeIterator iter(tree.getFirstChild()); iter != tree.getEndChild(); ++iter) {
OSReport_Error("%08X | %08X | %s\n", iter->getStartAddr(), iter->getEndAddr(), iter->getName());
}
CRASH("Aborting due to allocation failure!"); CRASH("Aborting due to allocation failure!");
} }
#else #else
@@ -494,6 +563,49 @@ static void dummy() {
OS_REPORT("newSize > 0"); OS_REPORT("newSize > 0");
} }
#if TARGET_PC
bool JKRExpHeap::growHeap(u32 needed) {
// Determine how much to commit
// Always grow by at least JKR_HEAP_GROW_CHUNK
const size_t pageSize = dusk::vmem_page_size();
size_t wantBytes = (size_t)needed + sizeof(CMemBlock);
size_t growAmount = std::max(wantBytes, JKR_HEAP_GROW_CHUNK);
growAmount = ALIGN_NEXT(growAmount, pageSize);
size_t remaining = mVmemCapacity - mVmemCommitted;
if (growAmount > remaining) {
// Clamp to whatever reservation is left
growAmount = ALIGN_PREV(remaining, pageSize);
if (growAmount < wantBytes) {
return false;
}
}
void* commitBase = (u8*)mVmemBase + mVmemCommitted;
if (!dusk::vmem_commit(commitBase, growAmount)) {
return false;
}
// Splice the new committed region into the free list as a single block at mEnd
CMemBlock* newBlock = (CMemBlock*)mEnd;
newBlock->size = (u32)(growAmount - sizeof(CMemBlock));
newBlock->mFlags = 0;
mEnd = (u8*)mEnd + growAmount;
mSize += (u32)growAmount;
mVmemCommitted += growAmount;
recycleFreeBlock(newBlock);
DuskLog.debug("[JKRExpHeap] '{}' grew by {} MB (committed: {} MB / reserved: {} MB)\n",
getName(),
growAmount / (1024 * 1024),
mVmemCommitted / (1024 * 1024),
mVmemCapacity / (1024 * 1024));
return true;
}
#endif
void JKRExpHeap::do_freeAll() { void JKRExpHeap::do_freeAll() {
lock(); lock();
JKRHeap::callAllDisposer(); JKRHeap::callAllDisposer();
+115 -3
View File
@@ -1,4 +1,4 @@
#include "JSystem/JSystem.h" // IWYU pragma: keep #include "JSystem/JSystem.h" // IWYU pragma: keep
#include "JSystem/JKernel/JKRSolidHeap.h" #include "JSystem/JKernel/JKRSolidHeap.h"
#include "JSystem/JGadget/binary.h" #include "JSystem/JGadget/binary.h"
@@ -7,6 +7,11 @@
#include "global.h" #include "global.h"
#include <stdint.h> #include <stdint.h>
#include <cstdlib> #include <cstdlib>
#if TARGET_PC
#include "dusk/vmem.h"
#include <algorithm>
#include "dusk/logging.h"
#endif
JKRSolidHeap* JKRSolidHeap::create(u32 size, JKRHeap* heap, bool useErrorHandler) { JKRSolidHeap* JKRSolidHeap::create(u32 size, JKRHeap* heap, bool useErrorHandler) {
if (!heap) { if (!heap) {
@@ -19,18 +24,56 @@ JKRSolidHeap* JKRSolidHeap::create(u32 size, JKRHeap* heap, bool useErrorHandler
} }
u32 alignedSize = ALIGN_PREV(size, 0x10); u32 alignedSize = ALIGN_PREV(size, 0x10);
if (alignedSize < solidHeapSize) if (alignedSize < solidHeapSize) {
return NULL; return NULL;
}
#if TARGET_PC
u8* vmemBase = (u8*)dusk::vmem_arena_alloc(JKR_HEAP_VIRTUAL_RESERVE);
if (!vmemBase) {
return NULL;
}
const size_t pageSize = dusk::vmem_page_size();
size_t commitSize = ALIGN_NEXT((size_t)alignedSize, pageSize);
if (!dusk::vmem_commit(vmemBase, commitSize)) {
dusk::vmem_arena_free(vmemBase, JKR_HEAP_VIRTUAL_RESERVE);
return NULL;
}
u8* mem = vmemBase;
void* dataPtr = mem + solidHeapSize;
JKRSolidHeap* newHeap = JKR_NEW_ARGS(mem) JKRSolidHeap(dataPtr, alignedSize - solidHeapSize, heap, useErrorHandler);
if (newHeap == NULL) {
dusk::vmem_arena_free(vmemBase, JKR_HEAP_VIRTUAL_RESERVE);
return NULL;
}
newHeap->mVmemBase = vmemBase;
newHeap->mVmemCapacity = JKR_HEAP_VIRTUAL_RESERVE;
newHeap->mVmemCommitted = commitSize;
return newHeap;
#else
u8* mem = (u8*)JKRAllocFromHeap(heap, alignedSize, 0x10); u8* mem = (u8*)JKRAllocFromHeap(heap, alignedSize, 0x10);
void* dataPtr = mem + solidHeapSize; void* dataPtr = mem + solidHeapSize;
if (!mem) if (!mem) {
return NULL; return NULL;
}
return JKR_NEW_ARGS (mem) JKRSolidHeap(dataPtr, alignedSize - solidHeapSize, heap, useErrorHandler); return JKR_NEW_ARGS (mem) JKRSolidHeap(dataPtr, alignedSize - solidHeapSize, heap, useErrorHandler);
#endif
} }
void JKRSolidHeap::do_destroy(void) { void JKRSolidHeap::do_destroy(void) {
#if TARGET_PC
if (mVmemBase) {
void* vmemBase = mVmemBase;
size_t vmemCapacity = mVmemCapacity;
this->~JKRSolidHeap();
dusk::vmem_arena_free(vmemBase, vmemCapacity);
return;
}
#endif
JKRHeap* parent = getParent(); JKRHeap* parent = getParent();
if (parent) { if (parent) {
this->~JKRSolidHeap(); this->~JKRSolidHeap();
@@ -44,6 +87,11 @@ JKRSolidHeap::JKRSolidHeap(void* start, u32 size, JKRHeap* parent, bool useError
mSolidHead = (u8*)mStart; mSolidHead = (u8*)mStart;
mSolidTail = (u8*)mEnd; mSolidTail = (u8*)mEnd;
field_0x78 = NULL; field_0x78 = NULL;
#if TARGET_PC
mVmemBase = nullptr;
mVmemCapacity = 0;
mVmemCommitted = 0;
#endif
#if DEBUG #if DEBUG
if (mDebugFill) { if (mDebugFill) {
JKRFillMemory(mStart, mSize, JKRValue_DEBUGFILL_NOTUSE); JKRFillMemory(mStart, mSize, JKRValue_DEBUGFILL_NOTUSE);
@@ -59,6 +107,15 @@ s32 JKRSolidHeap::adjustSize(void) {
int r25 = 0; int r25 = 0;
JKRHeap* parent = getParent(); JKRHeap* parent = getParent();
if (parent) { if (parent) {
#if TARGET_PC
if (mVmemBase) {
// VM-backed heap, can't resize in parent, but this is not a failure
// Return what the trimmed size would have been so the caller doesn't log an error
u32 thisSize = (uintptr_t)mStart - (uintptr_t)this;
u32 newSize = ALIGN_NEXT(mSolidHead - mStart, 0x20);
return (s32)(thisSize + newSize);
}
#endif
lock(); lock();
u32 thisSize = (uintptr_t)mStart - (uintptr_t)this; u32 thisSize = (uintptr_t)mStart - (uintptr_t)this;
u32 newSize = ALIGN_NEXT(mSolidHead - mStart, 0x20); u32 newSize = ALIGN_NEXT(mSolidHead - mStart, 0x20);
@@ -110,6 +167,11 @@ void* JKRSolidHeap::allocFromHead(u32 size, int alignment) {
void* ptr = NULL; void* ptr = NULL;
uintptr_t alignedStart = (alignment - 1 + (uintptr_t)mSolidHead) & ~(alignment - 1); uintptr_t alignedStart = (alignment - 1 + (uintptr_t)mSolidHead) & ~(alignment - 1);
u32 totalSize = size + (alignedStart - (uintptr_t)mSolidHead); u32 totalSize = size + (alignedStart - (uintptr_t)mSolidHead);
#if TARGET_PC
if (totalSize > mFreeSize && mVmemBase) {
growHeap(totalSize);
}
#endif
if (totalSize <= mFreeSize) { if (totalSize <= mFreeSize) {
#if DEBUG #if DEBUG
if (mCheckMemoryFilled) { if (mCheckMemoryFilled) {
@@ -137,6 +199,15 @@ void* JKRSolidHeap::allocFromTail(u32 size, int alignment) {
void* ptr = NULL; void* ptr = NULL;
uintptr_t alignedStart = ALIGN_PREV((uintptr_t)mSolidTail - size, alignment); uintptr_t alignedStart = ALIGN_PREV((uintptr_t)mSolidTail - size, alignment);
u32 totalSize = (uintptr_t)mSolidTail - (uintptr_t)alignedStart; u32 totalSize = (uintptr_t)mSolidTail - (uintptr_t)alignedStart;
#if TARGET_PC
if (totalSize > mFreeSize && mVmemBase) {
if (growHeap(totalSize)) {
// mSolidTail moved to new mEnd; recompute from the new tail position
alignedStart = ALIGN_PREV((uintptr_t)mSolidTail - size, alignment);
totalSize = (uintptr_t)mSolidTail - (uintptr_t)alignedStart;
}
}
#endif
if (totalSize <= mFreeSize) { if (totalSize <= mFreeSize) {
ptr = (void*)alignedStart; ptr = (void*)alignedStart;
mSolidTail -= totalSize; mSolidTail -= totalSize;
@@ -158,6 +229,47 @@ void* JKRSolidHeap::allocFromTail(u32 size, int alignment) {
return ptr; return ptr;
} }
#if TARGET_PC
bool JKRSolidHeap::growHeap(u32 needed) {
// Growth is only safe when no tail allocations exist yet
if (mSolidTail != mEnd) {
return false;
}
const size_t pageSize = dusk::vmem_page_size();
size_t wantBytes = (size_t)needed;
size_t growAmount = std::max(wantBytes, JKR_HEAP_GROW_CHUNK);
growAmount = ALIGN_NEXT(growAmount, pageSize);
size_t remaining = mVmemCapacity - mVmemCommitted;
if (growAmount > remaining) {
growAmount = ALIGN_PREV(remaining, pageSize);
if (growAmount < wantBytes) {
return false;
}
}
void* commitBase = (u8*)mVmemBase + mVmemCommitted;
if (!dusk::vmem_commit(commitBase, growAmount)) {
return false;
}
// Extend the heap end and the tail pointer
mEnd = (u8*)mEnd + growAmount;
mSolidTail = mEnd;
mFreeSize += (u32)growAmount;
mSize += (u32)growAmount;
mVmemCommitted += growAmount;
DuskLog.debug("[JKRSolidHeap] '{}' grew by {} MB (committed: {} MB / reserved: {} MB)\n",
getName(),
growAmount / (1024 * 1024),
mVmemCommitted / (1024 * 1024),
mVmemCapacity / (1024 * 1024));
return true;
}
#endif
void JKRSolidHeap::do_free(void* ptr) { void JKRSolidHeap::do_free(void* ptr) {
JUTWarningConsole_f("free: cannot free memory block (%08x)\n", ptr); JUTWarningConsole_f("free: cannot free memory block (%08x)\n", ptr);
} }
+105 -247
View File
@@ -9,9 +9,6 @@
#include <mtx.h> #include <mtx.h>
#include <gx.h> #include <gx.h>
#if TARGET_PC
#include "dusk/frame_interpolation.h"
#endif
#include "tracy/Tracy.hpp" #include "tracy/Tracy.hpp"
void JPASetPointSize(JPAEmitterWorkData* work) { void JPASetPointSize(JPAEmitterWorkData* work) {
@@ -421,95 +418,50 @@ static projectionFunc p_prj[3] = {
loadPrjAnm, loadPrjAnm,
}; };
#if TARGET_PC void JPADrawBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
void JPAInterpBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) { if (param_1->checkStatus(JPAPtclStts_Invisible)) {
Mtx ptclPosMtx;
MTXTrans(ptclPosMtx, ptcl->mPosition.x, ptcl->mPosition.y, ptcl->mPosition.z);
dusk::frame_interp::record_final_mtx(ptclPosMtx, ptcl);
}
void JPAInterpRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
Mtx ptclPosMtx;
f32 sinRot = JMASSin(ptcl->mRotateAngle);
f32 cosRot = JMASCos(ptcl->mRotateAngle);
MTXTrans(ptclPosMtx, ptcl->mPosition.x, ptcl->mPosition.y, ptcl->mPosition.z);
ptclPosMtx[0][0] = cosRot;
ptclPosMtx[0][1] = -sinRot;
ptclPosMtx[1][0] = sinRot;
ptclPosMtx[1][1] = cosRot;
dusk::frame_interp::record_final_mtx(ptclPosMtx, ptcl);
}
#endif
void JPADrawBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
return; return;
} }
JGeometry::TVec3<f32> pos; JGeometry::TVec3<f32> local_48;
#if TARGET_PC MTXMultVec(work->mPosCamMtx, &param_1->mPosition, &local_48);
Mtx ptclPosMtx; Mtx local_38;
if (dusk::frame_interp::lookup_replacement(ptcl, ptclPosMtx)) { local_38[0][0] = work->mGlobalPtclScl.x * param_1->mParticleScaleX;
pos.set(ptclPosMtx[0][3], ptclPosMtx[1][3], ptclPosMtx[2][3]); local_38[0][3] = local_48.x;
MTXMultVec(work->mPosCamMtx, &pos, &pos); local_38[1][1] = work->mGlobalPtclScl.y * param_1->mParticleScaleY;
} else local_38[1][3] = local_48.y;
#endif local_38[2][2] = 1.0f;
{ local_38[2][3] = local_48.z;
MTXMultVec(work->mPosCamMtx, &ptcl->mPosition, &pos); local_38[0][1] = local_38[0][2] = local_38[1][0] = local_38[1][2] = local_38[2][0] = local_38[2][1] = 0.0f;
} GXLoadPosMtxImm(local_38, 0);
Mtx posMtx; p_prj[work->mPrjType](work, local_38);
posMtx[0][0] = work->mGlobalPtclScl.x * ptcl->mParticleScaleX;
posMtx[0][3] = pos.x;
posMtx[1][1] = work->mGlobalPtclScl.y * ptcl->mParticleScaleY;
posMtx[1][3] = pos.y;
posMtx[2][2] = 1.0f;
posMtx[2][3] = pos.z;
posMtx[0][1] = posMtx[0][2] = posMtx[1][0] = posMtx[1][2] = posMtx[2][0] = posMtx[2][1] = 0.0f;
GXLoadPosMtxImm(posMtx, GX_PNMTX0);
p_prj[work->mPrjType](work, posMtx);
GXCallDisplayList(jpa_dl, sizeof(jpa_dl)); GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
} }
void JPADrawRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) { void JPADrawRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
if (ptcl->checkStatus(JPAPtclStts_Invisible)) { if (param_1->checkStatus(JPAPtclStts_Invisible)) {
return; return;
} }
if (work->mpRes->getUsrIdx() == 0x89d7) { JGeometry::TVec3<f32> local_48;
int a = 0; MTXMultVec(work->mPosCamMtx, &param_1->mPosition, &local_48);
} f32 sinRot = JMASSin(param_1->mRotateAngle);
f32 cosRot = JMASCos(param_1->mRotateAngle);
f32 particleX = work->mGlobalPtclScl.x * param_1->mParticleScaleX;
f32 particleY = work->mGlobalPtclScl.y * param_1->mParticleScaleY;
JGeometry::TVec3<f32> pos; Mtx local_38;
f32 sinRot, cosRot; local_38[0][0] = cosRot * particleX;
#if TARGET_PC local_38[0][1] = -sinRot * particleY;
Mtx ptclPosMtx; local_38[0][3] = local_48.x;
MTXTrans(ptclPosMtx, ptcl->mPosition.x, ptcl->mPosition.y, ptcl->mPosition.z); local_38[1][0] = sinRot * particleX;
if (dusk::frame_interp::lookup_replacement(ptcl, ptclPosMtx)) { local_38[1][1] = cosRot * particleY;
pos.set(ptclPosMtx[0][3], ptclPosMtx[1][3], ptclPosMtx[2][3]); local_38[1][3] = local_48.y;
sinRot = ptclPosMtx[1][0]; local_38[2][2] = 1.0f;
cosRot = ptclPosMtx[0][0]; local_38[2][3] = local_48.z;
MTXMultVec(work->mPosCamMtx, &pos, &pos); local_38[0][2] = local_38[1][2] = local_38[2][0] = local_38[2][1] = 0.0f;
} else GXLoadPosMtxImm(local_38, 0);
#endif p_prj[work->mPrjType](work, local_38);
{
MTXMultVec(work->mPosCamMtx, &ptcl->mPosition, &pos);
sinRot = JMASSin(ptcl->mRotateAngle);
cosRot = JMASCos(ptcl->mRotateAngle);
}
f32 particleX = work->mGlobalPtclScl.x * ptcl->mParticleScaleX;
f32 particleY = work->mGlobalPtclScl.y * ptcl->mParticleScaleY;
Mtx posMtx;
posMtx[0][0] = cosRot * particleX;
posMtx[0][1] = -sinRot * particleY;
posMtx[0][3] = pos.x;
posMtx[1][0] = sinRot * particleX;
posMtx[1][1] = cosRot * particleY;
posMtx[1][3] = pos.y;
posMtx[2][2] = 1.0f;
posMtx[2][3] = pos.z;
posMtx[0][2] = posMtx[1][2] = posMtx[2][0] = posMtx[2][1] = 0.0f;
GXLoadPosMtxImm(posMtx, GX_PNMTX0);
p_prj[work->mPrjType](work, posMtx);
GXCallDisplayList(jpa_dl, sizeof(jpa_dl)); GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
} }
@@ -532,7 +484,7 @@ void JPADrawYBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
local_38[2][2] = work->mYBBCamMtx[2][2]; local_38[2][2] = work->mYBBCamMtx[2][2];
local_38[2][3] = local_48.z; local_38[2][3] = local_48.z;
local_38[0][1] = local_38[0][2] = local_38[1][0] = local_38[2][0] = 0.0f; local_38[0][1] = local_38[0][2] = local_38[1][0] = local_38[2][0] = 0.0f;
GXLoadPosMtxImm(local_38, GX_PNMTX0); GXLoadPosMtxImm(local_38, 0);
p_prj[work->mPrjType](work, local_38); p_prj[work->mPrjType](work, local_38);
GXCallDisplayList(jpa_dl, sizeof(jpa_dl)); GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
} }
@@ -565,7 +517,7 @@ void JPADrawRotYBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
local_38[2][1] = local_94 * fVar1; local_38[2][1] = local_94 * fVar1;
local_38[2][2] = local_90; local_38[2][2] = local_90;
local_38[2][3] = local_48.z; local_38[2][3] = local_48.z;
GXLoadPosMtxImm(local_38, GX_PNMTX0); GXLoadPosMtxImm(local_38, 0);
p_prj[work->mPrjType](work, local_38); p_prj[work->mPrjType](work, local_38);
GXCallDisplayList(jpa_dl, sizeof(jpa_dl)); GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
} }
@@ -729,197 +681,103 @@ static u8* p_dl[2] = {
jpa_dl_x, jpa_dl_x,
}; };
#if TARGET_PC void JPADrawDirection(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
void JPAInterpDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) { if (param_1->checkStatus(JPAPtclStts_Invisible)) {
JGeometry::TVec3<f32> axisY;
JGeometry::TVec3<f32> axisZ;
p_direction[work->mDirType](work, ptcl, &axisY);
if (axisY.isZero()) {
return;
}
axisY.normalize();
axisZ.cross(ptcl->mBaseAxis, axisY);
if (axisZ.isZero()) {
return;
}
axisZ.normalize();
ptcl->mBaseAxis.cross(axisY, axisZ);
ptcl->mBaseAxis.normalize();
Mtx posMtx;
f32 scaleX = work->mGlobalPtclScl.x * ptcl->mParticleScaleX;
f32 scaleY = work->mGlobalPtclScl.y * ptcl->mParticleScaleY;
posMtx[0][0] = ptcl->mBaseAxis.x;
posMtx[0][1] = axisY.x;
posMtx[0][2] = axisZ.x;
posMtx[0][3] = ptcl->mPosition.x;
posMtx[1][0] = ptcl->mBaseAxis.y;
posMtx[1][1] = axisY.y;
posMtx[1][2] = axisZ.y;
posMtx[1][3] = ptcl->mPosition.y;
posMtx[2][0] = ptcl->mBaseAxis.z;
posMtx[2][1] = axisY.z;
posMtx[2][2] = axisZ.z;
posMtx[2][3] = ptcl->mPosition.z;
p_plane[work->mPlaneType](posMtx, scaleX, scaleY);
dusk::frame_interp::record_final_mtx(posMtx, ptcl);
}
void JPAInterpRotDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
f32 sinRot = JMASSin(ptcl->mRotateAngle);
f32 cosRot = JMASCos(ptcl->mRotateAngle);
JGeometry::TVec3<f32> axisY;
JGeometry::TVec3<f32> axisZ;
p_direction[work->mDirType](work, ptcl, &axisY);
if (axisY.isZero()) {
return;
}
axisY.normalize();
axisZ.cross(ptcl->mBaseAxis, axisY);
if (axisZ.isZero()) {
return;
}
axisZ.normalize();
ptcl->mBaseAxis.cross(axisY, axisZ);
ptcl->mBaseAxis.normalize();
f32 scaleX = work->mGlobalPtclScl.x * ptcl->mParticleScaleX;
f32 scaleY = work->mGlobalPtclScl.y * ptcl->mParticleScaleY;
Mtx mtx1;
Mtx mtx2;
p_rot[work->mRotType](sinRot, cosRot, mtx1);
p_plane[work->mPlaneType](mtx1, scaleX, scaleY);
mtx2[0][0] = ptcl->mBaseAxis.x;
mtx2[0][1] = axisY.x;
mtx2[0][2] = axisZ.x;
mtx2[0][3] = ptcl->mPosition.x;
mtx2[1][0] = ptcl->mBaseAxis.y;
mtx2[1][1] = axisY.y;
mtx2[1][2] = axisZ.y;
mtx2[1][3] = ptcl->mPosition.y;
mtx2[2][0] = ptcl->mBaseAxis.z;
mtx2[2][1] = axisY.z;
mtx2[2][2] = axisZ.z;
mtx2[2][3] = ptcl->mPosition.z;
MTXConcat(mtx2, mtx1, mtx1);
dusk::frame_interp::record_final_mtx(mtx1, ptcl);
}
#endif
void JPADrawDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
return; return;
} }
ZoneScoped; ZoneScoped;
Mtx posMtx; JGeometry::TVec3<f32> local_6c;
#if TARGET_PC JGeometry::TVec3<f32> local_78;
if (!dusk::frame_interp::lookup_replacement(ptcl, posMtx)) p_direction[param_0->mDirType](param_0, param_1, &local_6c);
#endif
{
JGeometry::TVec3<f32> axisY;
JGeometry::TVec3<f32> axisZ;
p_direction[work->mDirType](work, ptcl, &axisY);
if (axisY.isZero()) { if (local_6c.isZero()) {
return; return;
} }
axisY.normalize(); local_6c.normalize();
axisZ.cross(ptcl->mBaseAxis, axisY); local_78.cross(param_1->mBaseAxis, local_6c);
if (axisZ.isZero()) { if (local_78.isZero()) {
return; return;
} }
axisZ.normalize(); local_78.normalize();
ptcl->mBaseAxis.cross(axisY, axisZ); param_1->mBaseAxis.cross(local_6c, local_78);
ptcl->mBaseAxis.normalize(); param_1->mBaseAxis.normalize();
f32 scaleX = work->mGlobalPtclScl.x * ptcl->mParticleScaleX; Mtx local_60;
f32 scaleY = work->mGlobalPtclScl.y * ptcl->mParticleScaleY; f32 fVar1 = param_0->mGlobalPtclScl.x * param_1->mParticleScaleX;
posMtx[0][0] = ptcl->mBaseAxis.x; f32 fVar2 = param_0->mGlobalPtclScl.y * param_1->mParticleScaleY;
posMtx[0][1] = axisY.x; local_60[0][0] = param_1->mBaseAxis.x;
posMtx[0][2] = axisZ.x; local_60[0][1] = local_6c.x;
posMtx[0][3] = ptcl->mPosition.x; local_60[0][2] = local_78.x;
posMtx[1][0] = ptcl->mBaseAxis.y; local_60[0][3] = param_1->mPosition.x;
posMtx[1][1] = axisY.y; local_60[1][0] = param_1->mBaseAxis.y;
posMtx[1][2] = axisZ.y; local_60[1][1] = local_6c.y;
posMtx[1][3] = ptcl->mPosition.y; local_60[1][2] = local_78.y;
posMtx[2][0] = ptcl->mBaseAxis.z; local_60[1][3] = param_1->mPosition.y;
posMtx[2][1] = axisY.z; local_60[2][0] = param_1->mBaseAxis.z;
posMtx[2][2] = axisZ.z; local_60[2][1] = local_6c.z;
posMtx[2][3] = ptcl->mPosition.z; local_60[2][2] = local_78.z;
p_plane[work->mPlaneType](posMtx, scaleX, scaleY); local_60[2][3] = param_1->mPosition.z;
} p_plane[param_0->mPlaneType](local_60, fVar1, fVar2);
MTXConcat(param_0->mPosCamMtx, local_60, local_60);
MTXConcat(work->mPosCamMtx, posMtx, posMtx); GXLoadPosMtxImm(local_60, 0);
GXLoadPosMtxImm(posMtx, GX_PNMTX0); p_prj[param_0->mPrjType](param_0, local_60);
p_prj[work->mPrjType](work, posMtx); GXCallDisplayList(p_dl[param_0->mDLType], sizeof(jpa_dl));
GXCallDisplayList(p_dl[work->mDLType], sizeof(jpa_dl));
} }
void JPADrawRotDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) { void JPADrawRotDirection(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
if (ptcl->checkStatus(JPAPtclStts_Invisible)) { if (param_1->checkStatus(JPAPtclStts_Invisible)) {
return; return;
} }
ZoneScoped; ZoneScoped;
Mtx mtx1; f32 sinRot = JMASSin(param_1->mRotateAngle);
Mtx mtx2; f32 cosRot = JMASCos(param_1->mRotateAngle);
#if TARGET_PC JGeometry::TVec3<f32> local_6c;
if (!dusk::frame_interp::lookup_replacement(ptcl, mtx1)) JGeometry::TVec3<f32> local_78;
#endif p_direction[param_0->mDirType](param_0, param_1, &local_6c);
{
f32 sinRot = JMASSin(ptcl->mRotateAngle);
f32 cosRot = JMASCos(ptcl->mRotateAngle);
JGeometry::TVec3<f32> axisY;
JGeometry::TVec3<f32> axisZ;
p_direction[work->mDirType](work, ptcl, &axisY);
if (axisY.isZero()) { if (local_6c.isZero()) {
return; return;
} }
axisY.normalize(); local_6c.normalize();
axisZ.cross(ptcl->mBaseAxis, axisY); local_78.cross(param_1->mBaseAxis, local_6c);
if (axisZ.isZero()) { if (local_78.isZero()) {
return; return;
} }
axisZ.normalize(); local_78.normalize();
ptcl->mBaseAxis.cross(axisY, axisZ); param_1->mBaseAxis.cross(local_6c, local_78);
ptcl->mBaseAxis.normalize(); param_1->mBaseAxis.normalize();
f32 scaleX = work->mGlobalPtclScl.x * ptcl->mParticleScaleX; f32 particleX = param_0->mGlobalPtclScl.x * param_1->mParticleScaleX;
f32 scaleY = work->mGlobalPtclScl.y * ptcl->mParticleScaleY; f32 particleY = param_0->mGlobalPtclScl.y * param_1->mParticleScaleY;
p_rot[work->mRotType](sinRot, cosRot, mtx1); Mtx auStack_80;
p_plane[work->mPlaneType](mtx1, scaleX, scaleY); Mtx local_60;
mtx2[0][0] = ptcl->mBaseAxis.x; p_rot[param_0->mRotType](sinRot, cosRot, auStack_80);
mtx2[0][1] = axisY.x; p_plane[param_0->mPlaneType](auStack_80, particleX, particleY);
mtx2[0][2] = axisZ.x; local_60[0][0] = param_1->mBaseAxis.x;
mtx2[0][3] = ptcl->mPosition.x; local_60[0][1] = local_6c.x;
mtx2[1][0] = ptcl->mBaseAxis.y; local_60[0][2] = local_78.x;
mtx2[1][1] = axisY.y; local_60[0][3] = param_1->mPosition.x;
mtx2[1][2] = axisZ.y; local_60[1][0] = param_1->mBaseAxis.y;
mtx2[1][3] = ptcl->mPosition.y; local_60[1][1] = local_6c.y;
mtx2[2][0] = ptcl->mBaseAxis.z; local_60[1][2] = local_78.y;
mtx2[2][1] = axisY.z; local_60[1][3] = param_1->mPosition.y;
mtx2[2][2] = axisZ.z; local_60[2][0] = param_1->mBaseAxis.z;
mtx2[2][3] = ptcl->mPosition.z; local_60[2][1] = local_6c.z;
MTXConcat(mtx2, mtx1, mtx1); local_60[2][2] = local_78.z;
} local_60[2][3] = param_1->mPosition.z;
MTXConcat(work->mPosCamMtx, mtx1, mtx2); MTXConcat(local_60, auStack_80, auStack_80);
GXLoadPosMtxImm(mtx2, GX_PNMTX0); MTXConcat(param_0->mPosCamMtx, auStack_80, local_60);
p_prj[work->mPrjType](work, mtx2); GXLoadPosMtxImm(local_60, 0);
GXCallDisplayList(p_dl[work->mDLType], sizeof(jpa_dl)); p_prj[param_0->mPrjType](param_0, local_60);
GXCallDisplayList(p_dl[param_0->mDLType], sizeof(jpa_dl));
} }
void JPADrawDBillboard(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) { void JPADrawDBillboard(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
@@ -204,28 +204,6 @@ void JPABaseParticle::init_c(JPAEmitterWorkData* work, JPABaseParticle* parent)
mTexAnmIdx = 0; mTexAnmIdx = 0;
} }
#if TARGET_PC
void JPABaseParticle::interp(JPAEmitterWorkData* work, void const* drawFunc) {
static bool enable = false;
if (!enable)
return;
// don't interpolate the first frame
if (mAge == 0)
return;
if (drawFunc == JPADrawBillboard) {
JPAInterpBillboard(work, this);
} else if (drawFunc == JPADrawRotBillboard) {
JPAInterpRotBillboard(work, this);
} else if (drawFunc == JPADrawDirection) {
JPAInterpDirection(work, this);
} else if (drawFunc == JPADrawRotDirection) {
JPAInterpRotDirection(work, this);
}
}
#endif
bool JPABaseParticle::calc_p(JPAEmitterWorkData* work) { bool JPABaseParticle::calc_p(JPAEmitterWorkData* work) {
if (++mAge >= mLifeTime) { if (++mAge >= mLifeTime) {
return true; return true;
@@ -269,17 +247,6 @@ bool JPABaseParticle::calc_p(JPAEmitterWorkData* work) {
mOffsetPosition.y + mLocalPosition.y * work->mPublicScale.y, mOffsetPosition.y + mLocalPosition.y * work->mPublicScale.y,
mOffsetPosition.z + mLocalPosition.z * work->mPublicScale.z); mOffsetPosition.z + mLocalPosition.z * work->mPublicScale.z);
#if TARGET_PC
JPABaseShape* pBsp = work->mpRes->getBsp();
work->mGlobalPtclScl.x = work->mpEmtr->mGlobalPScl.x * pBsp->getBaseSizeX();
work->mGlobalPtclScl.y = work->mpEmtr->mGlobalPScl.y * pBsp->getBaseSizeY();
work->mDirType = pBsp->getDirType();
work->mRotType = pBsp->getRotType();
work->mDLType = pBsp->getType() == 4 || pBsp->getType() == 8;
work->mPlaneType = work->mDLType ? 2 : pBsp->getBasePlaneType();
interp(work, (void const*)work->mpRes->mpDrawParticleFuncList[0]);
#endif
return false; return false;
} }
@@ -322,23 +289,6 @@ bool JPABaseParticle::calc_c(JPAEmitterWorkData* work) {
mOffsetPosition.y + mLocalPosition.y * work->mPublicScale.y, mOffsetPosition.y + mLocalPosition.y * work->mPublicScale.y,
mOffsetPosition.z + mLocalPosition.z * work->mPublicScale.z); mOffsetPosition.z + mLocalPosition.z * work->mPublicScale.z);
#if TARGET_PC
JPABaseShape* pBsp = work->mpRes->getBsp();
JPAChildShape* pCsp = work->mpRes->getCsp();
if (pCsp->isScaleInherited()) {
work->mGlobalPtclScl.x = work->mpEmtr->mGlobalPScl.x * pBsp->getBaseSizeX();
work->mGlobalPtclScl.y = work->mpEmtr->mGlobalPScl.y * pBsp->getBaseSizeY();
} else {
work->mGlobalPtclScl.x = work->mpEmtr->mGlobalPScl.x * pCsp->getScaleX();
work->mGlobalPtclScl.y = work->mpEmtr->mGlobalPScl.y * pCsp->getScaleY();
}
work->mDirType = pCsp->getDirType();
work->mRotType = pCsp->getRotType();
work->mDLType = pCsp->getType() == 4 || pCsp->getType() == 8;
work->mPlaneType = work->mDLType ? 2 : pCsp->getBasePlaneType();
interp(work, (void const*)work->mpRes->mpDrawParticleChildFuncList[0]);
#endif
return false; return false;
} }
-6
View File
@@ -38,9 +38,3 @@ bool JUTPalette::load() {
return check; return check;
} }
#if TARGET_PC
void JUTPalette::dataUploaded() {
GXInitTlutObjData(&mTlutObj, (void*)mColorTable);
}
#endif
+9 -9
View File
@@ -27,7 +27,7 @@ void JUTTexture::storeTIMG(ResTIMG const* param_0, u8 param_1) {
mTexData = (void*)((intptr_t)mTexInfo + 0x20); mTexData = (void*)((intptr_t)mTexInfo + 0x20);
} }
mPalette = NULL; field_0x2c = NULL;
mTlutName = 0; mTlutName = 0;
mWrapS = mTexInfo->wrapS; mWrapS = mTexInfo->wrapS;
mWrapT = mTexInfo->wrapT; mWrapT = mTexInfo->wrapT;
@@ -95,7 +95,7 @@ void JUTTexture::storeTIMG(ResTIMG const* param_0, JUTPalette* param_1, GXTlut p
} }
mEmbPalette = param_1; mEmbPalette = param_1;
setEmbPaletteDelFlag(false); setEmbPaletteDelFlag(false);
mPalette = NULL; field_0x2c = NULL;
if (param_1 != NULL) { if (param_1 != NULL) {
mTlutName = param_2; mTlutName = param_2;
if (param_2 != param_1->getTlutName()) { if (param_2 != param_1->getTlutName()) {
@@ -120,11 +120,11 @@ void JUTTexture::storeTIMG(ResTIMG const* param_0, JUTPalette* param_1, GXTlut p
void JUTTexture::attachPalette(JUTPalette* param_0) { void JUTTexture::attachPalette(JUTPalette* param_0) {
if (mTexInfo->indexTexture) { if (mTexInfo->indexTexture) {
if (param_0 == NULL && mEmbPalette != NULL) { if (param_0 == NULL && mEmbPalette != NULL) {
mPalette = mEmbPalette; field_0x2c = mEmbPalette;
} else { } else {
mPalette = param_0; field_0x2c = param_0;
} }
initTexObj(mPalette->getTlutName()); initTexObj(field_0x2c->getTlutName());
} }
} }
@@ -133,9 +133,9 @@ void JUTTexture::init() {
initTexObj(); initTexObj();
} else { } else {
if (mEmbPalette != NULL) { if (mEmbPalette != NULL) {
mPalette = mEmbPalette; field_0x2c = mEmbPalette;
initTexObj(mPalette->getTlutName()); initTexObj(field_0x2c->getTlutName());
} else { } else {
OS_REPORT("This texture is CI-Format, but EmbPalette is NULL.\n"); OS_REPORT("This texture is CI-Format, but EmbPalette is NULL.\n");
} }
@@ -179,8 +179,8 @@ void JUTTexture::initTexObj(GXTlut param_0) {
} }
void JUTTexture::load(GXTexMapID param_0) { void JUTTexture::load(GXTexMapID param_0) {
if (mPalette) { if (field_0x2c) {
mPalette->load(); field_0x2c->load();
} }
GXLoadTexObj(&mTexObj, param_0); GXLoadTexObj(&mTexObj, param_0);
} }
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 457 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 188 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 MiB

-147
View File
@@ -1,147 +0,0 @@
*, *:before, *:after {
box-sizing: border-box;
}
body {
overflow: visible;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
font-family: "Fira Sans Condensed";
font-size: 24dp;
color: #FFFFFF;
display: flex;
flex-direction: column;
justify-content: flex-end;
align-items: stretch;
}
.overlay-root {
width: 100%;
min-height: 45%;
display: flex;
flex-direction: column;
justify-content: flex-end;
align-items: stretch;
decorator: vertical-gradient(#00000000 #151610F2);
padding: 48dp 0 40dp 0;
filter: opacity(0);
transition: filter 0.2s linear-in-out;
}
.overlay-root[open] {
filter: opacity(1);
}
.overlay {
width: 100%;
max-width: 1216dp;
margin-left: auto;
margin-right: auto;
display: flex;
flex-direction: column;
gap: 24dp;
padding: 0 32dp;
}
@media (max-height: 800dp) {
.overlay-root {
min-height: 38%;
padding: 32dp 0 28dp 0;
}
.overlay {
gap: 16dp;
padding: 0 24dp;
}
}
.header {
display: flex;
justify-content: space-between;
align-items: center;
gap: 24dp;
}
.carousel-container {
flex: 1 1 auto;
display: flex;
justify-content: flex-end;
min-width: 0;
}
.description {
font-size: 18dp;
line-height: 22dp;
color: rgba(255, 255, 255, 50%);
}
.divider {
margin: 1dp 0;
border-top: 1dp rgba(217, 217, 217, 50%);
}
.footer {
display: flex;
justify-content: space-between;
align-items: center;
gap: 24dp;
}
footer-button {
display: block;
width: 100%;
max-width: 220dp;
border: 0;
padding: 0;
background-color: transparent;
font-family: "Fira Sans Condensed";
font-weight: bold;
font-size: 20dp;
line-height: 24dp;
text-transform: uppercase;
color: #FFFFFF;
opacity: 1;
cursor: pointer;
}
footer-button.return {
text-align: left;
}
footer-button.reset {
text-align: right;
}
.stepped-carousel {
display: flex;
align-items: center;
justify-content: center;
gap: 16dp;
width: auto;
min-width: 246dp;
padding: 0;
background-color: transparent;
font-family: "Fira Sans Condensed";
font-weight: bold;
}
.stepped-carousel-value {
line-height: 29dp;
min-width: 166dp;
text-align: center;
white-space: nowrap;
opacity: 0.9;
}
.stepped-carousel-arrow {
width: 24dp;
height: 24dp;
min-width: 24dp;
padding: 0;
border: 0;
background-color: transparent;
opacity: 1;
cursor: pointer;
}
-45
View File
@@ -1,45 +0,0 @@
*, *:before, *:after {
box-sizing: border-box;
}
body {
overflow: visible;
width: 100%;
height: 100%;
margin: 0;
padding: 0;
font-family: "Fira Sans Condensed";
font-weight: bold;
font-size: 18dp;
color: #E0DBC8;
}
button {
cursor: pointer;
focus: auto;
}
popup {
width: 100%;
display: flex;
align-items: stretch;
height: 64dp;
background-color: rgba(21, 22, 16, 80%);
border-bottom: 2dp #92875B;
backdrop-filter: blur(5dp);
transform: translateY(-64dp);
transition: transform 0.2s cubic-in-out;
}
popup[open] {
transform: translateY(0);
}
popup tab-bar {
flex: 1 1 0;
}
popup tab-bar tab {
opacity: 0.35;
color: #E0DBC8;
}
-187
View File
@@ -1,187 +0,0 @@
*, *:before, *:after {
box-sizing: border-box;
}
body {
width: 100%;
height: 100%;
font-family: "Fira Sans";
font-weight: normal;
font-size: 20dp;
color: #FFFFFF;
background-color: #000000;
decorator: image(../prelaunch-bg.png cover left center);
filter: opacity(0);
transition: filter 1s 0.1s linear-in-out;
}
body[open] {
filter: opacity(1);
}
content {
display: block;
width: 100%;
height: 100%;
filter: opacity(0);
transition: filter 0.2s linear-in-out;
}
content[open] {
filter: opacity(1);
}
menu {
position: absolute;
left: 96dp;
top: 50%;
transform: translateY(-50%);
/* Scale based on a reference screen width, 428/1216 */
width: 35.230264vw;
min-width: 428dp;
max-width: 856dp;
height: auto;
display: flex;
flex-direction: column;
gap: 48dp;
}
hero {
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
gap: 8dp;
}
hero img {
width: 100%;
}
.eyebrow {
font-family: "Alegreya SC";
font-size: 32dp;
}
@media (min-width: 1216dp) {
.eyebrow {
/* Same logic as .menu, 32/1216 */
font-size: 2.631579vw;
}
}
.eyebrow span {
font-weight: bold;
}
#menu-list {
display: flex;
flex-direction: column;
gap: 12dp;
}
#menu-list button {
width: 428dp;
height: 54dp;
padding: 8dp 16dp;
border-radius: 8dp;
text-transform: uppercase;
font-family: "Fira Sans Condensed";
font-size: 32dp;
font-weight: normal;
cursor: pointer;
/* Define a fully transparent gradient as the default state, otherwise a white flash occurs */
decorator: horizontal-gradient(#00000000 #00000000);
}
#menu-list button.anim-done {
transition: decorator color 0.1s linear-in-out;
}
#menu-list button:hover,
#menu-list button:focus-visible {
color: black;
decorator: horizontal-gradient(#FEE685FF #FEE68500);
}
disk-status {
position: absolute;
left: 96dp;
bottom: 72dp;
display: flex;
flex-direction: column;
gap: 8dp;
}
version-info {
position: absolute;
right: 96dp;
bottom: 72dp;
display: flex;
flex-direction: column;
gap: 8dp;
text-align: right;
}
.status,
.version {
font-size: 24dp;
}
.status,
.update {
color: #D8F999;
}
.status[bad] {
color: #FFC9C9;
}
/* TODO: Hidden until an actual update checker is introduced */
.update {
display: none;
font-size: 16dp;
font-weight: bold;
cursor: pointer;
}
.detail,
.update span {
color: #A6A09B;
}
/* Startup animation */
.intro-item {
opacity: 0;
transform: translateY(10dp);
transition: opacity transform 0.3s 0.1s cubic-in-out;
}
body.animate-in .intro-item {
opacity: 1;
transform: translateY(0dp);
}
.delay-0 {
transition: opacity transform 0.3s 0.1s cubic-in-out;
}
.delay-1 {
transition: opacity transform 0.3s 0.2s cubic-in-out;
}
.delay-2 {
transition: opacity transform 0.3s 0.3s cubic-in-out;
}
.delay-3 {
transition: opacity transform 0.3s 0.4s cubic-in-out;
}
.delay-4 {
transition: opacity transform 0.3s 0.5s cubic-in-out;
}
.delay-5 {
transition: opacity transform 0.3s 0.6s cubic-in-out;
}
-33
View File
@@ -1,33 +0,0 @@
tab-bar {
display: flex;
min-width: 0;
overflow: auto hidden;
text-transform: uppercase;
}
tab-bar tab {
flex: 0 0 auto;
padding: 0 24dp;
line-height: 64dp;
white-space: nowrap;
decorator: vertical-gradient(#c2a42d00 #c2a42d00);
transition: decorator 0.1s linear-in-out, opacity 0.1s linear-in-out;
cursor: pointer;
}
tab-bar tab:selected {
opacity: 1;
border-bottom: 4dp #C2A42D;
font-effect: glow(0dp 4dp 0dp 4dp black);
}
tab-bar tab:focus-visible,
tab-bar tab:hover {
opacity: 1;
font-effect: glow(0dp 4dp 0dp 4dp black);
decorator: vertical-gradient(#c2a42d00 #c2a42d26);
}
tab-bar tab:active {
decorator: vertical-gradient(#c2a42d10 #c2a42d40);
}
-239
View File
@@ -1,239 +0,0 @@
*, *:before, *:after {
box-sizing: border-box;
}
body {
width: 100%;
height: 100%;
padding: 64dp;
font-family: "Fira Sans";
font-weight: normal;
font-style: normal;
font-size: 15dp;
color: #E0DBC8;
}
window {
display: flex;
flex-flow: column;
height: 100%;
max-width: 1088dp;
max-height: 768dp;
margin: auto;
border-radius: 14dp;
overflow: hidden;
border: 2dp #92875B;
backdrop-filter: blur(5dp);
box-shadow: 0 0 25dp 5dp;
background-color: rgba(21, 22, 16, 90%);
filter: opacity(0);
transform: scale(0.9);
transform-origin: center;
transition: filter transform 0.2s cubic-in-out;
}
window[open] {
filter: opacity(1);
transform: scale(1);
}
@media (max-height: 640dp) {
body {
padding: 16dp;
}
window {
box-shadow: none;
}
}
window tab-bar {
flex: 0 0 64dp;
height: 64dp;
background-color: rgba(217, 217, 217, 10%);
font-family: "Fira Sans Condensed";
font-weight: bold;
font-size: 18dp;
border-bottom: 2dp #92875B;
}
window tab-bar tab {
opacity: 0.25;
}
window content {
display: flex;
flex: 1 1 0;
min-width: 0;
min-height: 0;
overflow: hidden;
}
window content pane {
display: flex;
flex-flow: column;
flex: 1 1 0;
height: 100%;
min-width: 0;
min-height: 0;
padding: 24dp;
padding-bottom: 0dp;
gap: 8dp;
overflow: hidden auto;
font-size: 20dp;
}
window content pane:not(:last-of-type) {
border-right: 1dp #92875B;
}
window content pane > * {
flex: 0 0 auto;
}
window content pane > spacer {
display: block;
/* Completes the 24dp bottom inset after the pane's 8dp gap. */
flex: 0 0 16dp;
height: 16dp;
pointer-events: none;
}
scrollbarvertical {
width: 8dp;
margin: 4dp 4dp 4dp 0;
}
scrollbarvertical sliderarrowdec,
scrollbarvertical sliderarrowinc {
width: 0;
height: 0;
}
scrollbarvertical slidertrack {
width: 8dp;
}
scrollbarvertical sliderbar {
width: 8dp;
min-height: 24dp;
background-color: rgba(224, 219, 200, 45%);
border-radius: 2dp;
transition: background-color 0.2s cubic-in-out;
}
scrollbarvertical sliderbar:hover,
scrollbarvertical sliderbar:active {
background-color: rgba(194, 164, 45, 80%);
}
scrollbarhorizontal {
height: 0;
}
scrollbarhorizontal sliderarrowdec,
scrollbarhorizontal sliderarrowinc {
width: 0;
height: 0;
}
scrollbarhorizontal slidertrack,
scrollbarhorizontal sliderbar {
width: 0;
height: 0;
}
.section-heading {
font-family: "Fira Sans Condensed";
font-weight: bold;
text-transform: uppercase;
font-size: 22dp;
opacity: 0.25;
}
.section-heading:not(:first-of-type) {
padding-top: 12dp;
}
button {
text-align: center;
background-color: rgba(17, 16, 10, 20%);
opacity: 0.9;
padding: 8dp 16dp;
border-radius: 14dp;
box-shadow: rgba(146, 135, 91, 25%) 0 0 0 1dp;
font-size: 20dp;
transition: background-color 0.1s linear-in-out, opacity 0.1s linear-in-out;
cursor: pointer;
focus: auto;
}
button:not(:disabled):hover,
button:not(:disabled):focus-visible {
background-color: rgba(204, 184, 119, 20%);
box-shadow: #C2A42D 0 0 0 2dp;
}
button:not(:disabled):selected {
opacity: 1;
background-color: rgba(204, 184, 119, 40%);
}
button:not(:disabled):active {
opacity: 1;
background-color: rgba(204, 184, 119, 40%);
box-shadow: #C2A42D 0 0 0 2dp;
}
select-button {
display: flex;
align-items: center;
gap: 8dp;
background-color: rgba(17, 16, 10, 20%);
opacity: 0.9;
padding: 8dp 16dp;
border-radius: 14dp;
box-shadow: rgba(146, 135, 91, 25%) 0 0 0 1dp;
transition: background-color 0.1s linear-in-out, opacity 0.1s linear-in-out;
cursor: pointer;
focus: auto;
}
select-button:not(:disabled):hover,
select-button:not(:disabled):focus-visible {
background-color: rgba(204, 184, 119, 20%);
box-shadow: #C2A42D 0 0 0 2dp;
}
select-button:not(:disabled):selected {
opacity: 1;
background-color: rgba(204, 184, 119, 40%);
}
select-button:not(:disabled):active {
opacity: 1;
background-color: rgba(204, 184, 119, 40%);
box-shadow: #C2A42D 0 0 0 2dp;
}
select-button:disabled {
opacity: 0.35;
cursor: default;
}
select-button key {
font-family: "Fira Sans Condensed";
font-weight: bold;
font-size: 18dp;
text-transform: uppercase;
flex: 1 0 auto;
}
select-button value {
margin-left: auto;
font-size: 20dp;
}
select-button input {
text-align: right;
font-size: 20dp;
}
-17
View File
@@ -1,9 +1,5 @@
#include "Z2AudioLib/Z2Audience.h" #include "Z2AudioLib/Z2Audience.h"
#include "Z2AudioLib/Z2SoundInfo.h" #include "Z2AudioLib/Z2SoundInfo.h"
#if TARGET_PC
#include "dusk/audio/DuskDsp.hpp"
#include <cmath>
#endif
#include "Z2AudioLib/Z2Calc.h" #include "Z2AudioLib/Z2Calc.h"
#include "Z2AudioLib/Z2Param.h" #include "Z2AudioLib/Z2Param.h"
#include "JSystem/JAudio2/JAISound.h" #include "JSystem/JAudio2/JAISound.h"
@@ -738,19 +734,6 @@ f32 Z2Audience::calcRelPosPan(const Vec& param_0, int camID) {
f32 Z2Audience::calcRelPosDolby(const Vec& param_0, int camID) { f32 Z2Audience::calcRelPosDolby(const Vec& param_0, int camID) {
f32 fVar1 = param_0.z + mAudioCamera[camID].getDolbyCenterZ(); f32 fVar1 = param_0.z + mAudioCamera[camID].getDolbyCenterZ();
#if TARGET_PC
if (dusk::audio::EnableHrtf) {
// Normalize the direction so result is purely front/back orientation,
// independent of how far away the sound is
f32 lenSq = param_0.x * param_0.x + param_0.y * param_0.y + param_0.z * param_0.z;
if (lenSq < 0.0001f) {
return 0.5f;
}
f32 zNorm = param_0.z / sqrtf(lenSq);
f32 t = (zNorm + 1.0f) * 0.5f;
return 0.5f - 0.5f * cosf(t * static_cast<f32>(M_PI));
}
#endif
if (fVar1 > mSetting.field_0x48) { if (fVar1 > mSetting.field_0x48) {
return 1.0f; return 1.0f;
} }
+1 -4
View File
@@ -4962,16 +4962,13 @@ int daAlink_c::create() {
setArcName(checkWolf()); setArcName(checkWolf());
setOriginalHeap(&mpArcHeap, 0xA2800); setOriginalHeap(&mpArcHeap, 0xA2800);
JKRHEAP_NAME(mpArcHeap, "Alink ArcHeap");
if (dComIfG_resLoad(&mPhaseReq, mArcName, mpArcHeap) != cPhs_COMPLEATE_e) { if (dComIfG_resLoad(&mPhaseReq, mArcName, mpArcHeap) != cPhs_COMPLEATE_e) {
return cPhs_INIT_e; return cPhs_INIT_e;
} }
setShieldArcName(); setShieldArcName();
setOriginalHeap(&mpShieldArcHeap, 0x7000); setOriginalHeap(&mpShieldArcHeap, 0x7000);
JKRHEAP_NAME(mpShieldArcHeap, "Alink ShieldArcHeap"); if (dComIfG_resLoad(&mShieldPhaseReq, mShieldArcName, mpShieldArcHeap) != cPhs_COMPLEATE_e) {
if (dComIfG_resLoad(&mShieldPhaseReq, mShieldArcName, mpShieldArcHeap) != cPhs_COMPLEATE_e)
{
return cPhs_INIT_e; return cPhs_INIT_e;
} }
-13
View File
@@ -8,10 +8,6 @@
#include "d/actor/d_a_horse.h" #include "d/actor/d_a_horse.h"
#include "d/actor/d_a_crod.h" #include "d/actor/d_a_crod.h"
#include "d/d_msg_object.h" #include "d/d_msg_object.h"
#ifdef TARGET_PC
#include "d/actor/d_a_obj_carry.h"
#include "dusk/achievements.h"
#endif
#if DEBUG #if DEBUG
#include "d/d_s_menu.h" #include "d/d_s_menu.h"
@@ -682,15 +678,6 @@ BOOL daAlink_c::checkDamageAction() {
setDamagePoint(dmg, at_mtrl == dCcD_MTRL_FIRE || at_mtrl == dCcD_MTRL_ICE, TRUE, 0); setDamagePoint(dmg, at_mtrl == dCcD_MTRL_FIRE || at_mtrl == dCcD_MTRL_ICE, TRUE, 0);
#ifdef TARGET_PC
if (tghit_ac_name == fpcNm_Obj_Carry_e) {
auto* carry = static_cast<daObjCarry_c*>(tghit_ac);
if (carry->prm_chk_type_ironball() && carry->checkCannon()) {
dusk::AchievementSystem::get().signal("iron_ball_hit_player");
}
}
#endif
if (armor_no_dmg && at_mtrl != dCcD_MTRL_ELECTRIC && at_mtrl != dCcD_MTRL_ICE) { if (armor_no_dmg && at_mtrl != dCcD_MTRL_ELECTRIC && at_mtrl != dCcD_MTRL_ICE) {
setGuardSe(var_r29); setGuardSe(var_r29);
} else if (at_mtrl == dCcD_MTRL_FIRE) { } else if (at_mtrl == dCcD_MTRL_FIRE) {
-4
View File
@@ -18,10 +18,6 @@ enum {
}; };
void daAlink_c::hsChainShape_c::draw() { void daAlink_c::hsChainShape_c::draw() {
if (dusk::getSettings().game.superClawshot) {
return;
}
static const int dummy = 0; static const int dummy = 0;
daAlink_c* alink = (daAlink_c*)getUserArea(); daAlink_c* alink = (daAlink_c*)getUserArea();
+1
View File
@@ -46,6 +46,7 @@ void daAlink_c::setOriginalHeap(JKRExpHeap** i_ppheap, u32 i_size) {
JKRHeap* parent = mDoExt_getGameHeap(); JKRHeap* parent = mDoExt_getGameHeap();
JKRExpHeap* heap = JKRExpHeap::create(size + (var_r29 + var_r28), parent, true); JKRExpHeap* heap = JKRExpHeap::create(size + (var_r29 + var_r28), parent, true);
JKRHEAP_NAME(heap, "Alink original");
*i_ppheap = heap; *i_ppheap = heap;
} }
} }
+1 -3
View File
@@ -14,8 +14,6 @@
#include "JSystem/J2DGraph/J2DAnmLoader.h" #include "JSystem/J2DGraph/J2DAnmLoader.h"
#include <cstring> #include <cstring>
#include "dusk/memory.h"
class daCoach2D_HIO_c : public mDoHIO_entry_c { class daCoach2D_HIO_c : public mDoHIO_entry_c {
public: public:
struct Param { struct Param {
@@ -155,7 +153,7 @@ int daCoach2D_c::createHeap() {
int daCoach2D_c::create() { int daCoach2D_c::create() {
int phase_state = dComIfG_resLoad(this, l_arcName); int phase_state = dComIfG_resLoad(this, l_arcName);
if (phase_state == cPhs_COMPLEATE_e) { if (phase_state == cPhs_COMPLEATE_e) {
if (!fopAcM_entrySolidHeap(this, daCoach2D_createHeap, HEAP_SIZE(0x5050, 0x6000))) { if (!fopAcM_entrySolidHeap(this, daCoach2D_createHeap, 0x5050)) {
return cPhs_ERROR_e; return cPhs_ERROR_e;
} }
-11
View File
@@ -17,11 +17,6 @@
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#if TARGET_PC
#include <f_ap/f_ap_game.h>
#include <dusk/autosave.h>
#endif
char* daDoor20_c::getStopBmdName() { char* daDoor20_c::getStopBmdName() {
switch (door_param2_c::getKind(this)) { switch (door_param2_c::getKind(this)) {
case 3: case 3:
@@ -201,7 +196,6 @@ void daDoor20_c::setEventPrm() {
} else { } else {
roomNo = FRoomNo; roomNo = FRoomNo;
} }
if (dComIfGp_roomControl_checkStatusFlag(roomNo, 1)) { if (dComIfGp_roomControl_checkStatusFlag(roomNo, 1)) {
if (door_param2_c::getKind(this) == 9) { if (door_param2_c::getKind(this) == 9) {
if (daPy_py_c::checkNowWolf()) { if (daPy_py_c::checkNowWolf()) {
@@ -570,11 +564,6 @@ int daDoor20_c::openEnd(int param_1) {
openEnd_1(); openEnd_1();
break; break;
} }
#if TARGET_PC
triggerAutoSave();
#endif
return 1; return 1;
} }
-5
View File
@@ -282,11 +282,6 @@ static void e_th_spin_B(e_th_class* i_this) {
i_this->current.pos += spC; i_this->current.pos += spC;
f32 speed_target; f32 speed_target;
#if AVOID_UB
speed_target = 0;
#endif
f32 anm_frame = i_this->mpModelMorf->getFrame(); f32 anm_frame = i_this->mpModelMorf->getFrame();
switch (i_this->mMode) { switch (i_this->mMode) {
-17
View File
@@ -463,23 +463,6 @@ int daMidna_c::createHeap() {
JKRReadIdxResource(mBckHeap[0].getBuffer(), mBckHeap[0].getBufferSize(), 0x1DC, dComIfGp_getAnmArchive()); JKRReadIdxResource(mBckHeap[0].getBuffer(), mBckHeap[0].getBufferSize(), 0x1DC, dComIfGp_getAnmArchive());
J3DAnmTransform* md_anm = (J3DAnmTransform*)J3DAnmLoaderDataBase::load(mBckHeap[0].getBuffer()); J3DAnmTransform* md_anm = (J3DAnmTransform*)J3DAnmLoaderDataBase::load(mBckHeap[0].getBuffer());
modelData = (J3DModelData*)dComIfG_getObjectRes(l_arcName, 14); modelData = (J3DModelData*)dComIfG_getObjectRes(l_arcName, 14);
#if TARGET_PC
J3DTexture* tex = modelData->getTexture();
JUTNameTab* nametable = modelData->getTextureName();
if (tex != NULL && nametable != NULL) {
for (u16 i = 0; i < tex->getNum(); i++) {
const char* name = nametable->getName(i);
if (name != NULL && strcmp(name, "midona_eye") == 0) {
ResTIMG* timg = tex->getResTIMG(i);
timg->mipmapEnabled = false;
tex->loadGXTexObj(i);
break;
}
}
}
#endif
JUT_ASSERT(852, modelData != NULL); JUT_ASSERT(852, modelData != NULL);
mpMorf = JKR_NEW mDoExt_McaMorfSO(modelData, &mMorfCB, NULL, md_anm, J3DFrameCtrl::EMode_LOOP, 1.0f, 0, -1, NULL, 0, 0x11000284); mpMorf = JKR_NEW mDoExt_McaMorfSO(modelData, &mMorfCB, NULL, md_anm, J3DFrameCtrl::EMode_LOOP, 1.0f, 0, -1, NULL, 0, 0x11000284);
if (mpMorf == NULL || mpMorf->getModel() == NULL) { if (mpMorf == NULL || mpMorf->getModel() == NULL) {
+7 -17
View File
@@ -40,7 +40,6 @@ dMirror_packet_c::dMirror_packet_c() {
void dMirror_packet_c::reset() { void dMirror_packet_c::reset() {
#if TARGET_PC #if TARGET_PC
mbReset = true; mbReset = true;
mbHadEntry = false;
#else #else
mModelCount = 0; mModelCount = 0;
#endif #endif
@@ -85,21 +84,11 @@ void dMirror_packet_c::calcMinMax() {
} }
int dMirror_packet_c::entryModel(J3DModel* i_model) { int dMirror_packet_c::entryModel(J3DModel* i_model) {
#if TARGET_PC
if (mbReset) {
mModelCount = 0;
mbReset = false;
}
#endif
if (mModelCount >= 0x40) { if (mModelCount >= 0x40) {
return 0; return 0;
} }
mModels[mModelCount++] = i_model; mModels[mModelCount++] = i_model;
#if TARGET_PC
mbHadEntry = true;
#endif
return 1; return 1;
} }
@@ -603,6 +592,13 @@ int daMirror_c::execute() {
return 1; return 1;
} }
#if TARGET_PC
if (mPacket.mbReset) {
mPacket.mModelCount = 0;
mPacket.mbReset = false;
}
#endif
daPy_py_c* player = daPy_getLinkPlayerActorClass(); daPy_py_c* player = daPy_getLinkPlayerActorClass();
JUT_ASSERT(0, player != NULL); JUT_ASSERT(0, player != NULL);
@@ -628,12 +624,6 @@ int daMirror_c::draw() {
mDoExt_modelUpdateDL(mpModel); mDoExt_modelUpdateDL(mpModel);
} }
#if TARGET_PC
if (mPacket.mbReset && !mPacket.mbHadEntry) {
mPacket.mModelCount = 0;
}
mPacket.mbHadEntry = true;
#endif
dComIfGd_getOpaListBG()->entryImm(&mPacket, 0); dComIfGd_getOpaListBG()->entryImm(&mPacket, 0);
return 1; return 1;
} }
+7 -11
View File
@@ -62,16 +62,6 @@ void daObj_Balloon_c::saveBestScore() {
dComIfGp_setMessageCountNumber(m_balloon_score); dComIfGp_setMessageCountNumber(m_balloon_score);
} }
#if TARGET_PC
static void minigameReset() {
// !@bug d_a_obj_balloon.rel unload used to zero these file-statics; with static linking they dangle across scenes.
m_combo_type = 0xFFFFFFFF;
m_combo_count = 0;
m_combo_next_score = 0;
m_balloon_score = 0;
}
#endif
static u8 hio_set; static u8 hio_set;
static daObj_Balloon_HIO_c l_HIO; static daObj_Balloon_HIO_c l_HIO;
@@ -215,6 +205,13 @@ int daObj_Balloon_c::_delete() {
Z2GetAudioMgr()->seStop(Z2SE_OBJ_WATERMILL_ROUND, 0); Z2GetAudioMgr()->seStop(Z2SE_OBJ_WATERMILL_ROUND, 0);
if (mHIOInit) { if (mHIOInit) {
hio_set = false; hio_set = false;
#ifdef TARGET_PC
// !@bug d_a_obj_balloon.rel unload used to zero these file-statics; with static linking they dangle across scenes.
m_combo_type = 0xFFFFFFFF;
m_combo_count = 0;
m_combo_next_score = 0;
m_balloon_score = 0;
#endif
} }
return 1; return 1;
} }
@@ -256,7 +253,6 @@ int daObj_Balloon_c::create() {
} }
if (!hio_set) { if (!hio_set) {
IF_DUSK(minigameReset());
mHIOInit = true; mHIOInit = true;
hio_set = true; hio_set = true;
l_HIO.field_0x04 = -1; l_HIO.field_0x04 = -1;
+38 -50
View File
@@ -1175,12 +1175,6 @@ bool dCamera_c::Run() {
clrFlag(0x200000); clrFlag(0x200000);
} }
} else { } else {
#if TARGET_PC
if (mCamParam.Algorythmn(mCamStyle) != 1) {
mCamParam.mManualMode = 0;
}
#endif
sp0F = (this->*engine_tbl[mCamParam.Algorythmn(mCamStyle)])(mCamStyle); sp0F = (this->*engine_tbl[mCamParam.Algorythmn(mCamStyle)])(mCamStyle);
field_0x170++; field_0x170++;
@@ -1487,7 +1481,7 @@ void dCamera_c::CalcTrimSize() {
mTrimHeight += -mTrimHeight * 0.25f; mTrimHeight += -mTrimHeight * 0.25f;
break; break;
case 2: case 2:
#if !TARGET_PC && WIDESCREEN_SUPPORT #if WIDESCREEN_SUPPORT
if (mDoGph_gInf_c::isWide() && mDoGph_gInf_c::isWideZoom()) { if (mDoGph_gInf_c::isWide() && mDoGph_gInf_c::isWideZoom()) {
mTrimHeight += (16.0f - mTrimHeight) * 0.25f; mTrimHeight += (16.0f - mTrimHeight) * 0.25f;
break; break;
@@ -3095,6 +3089,10 @@ bool dCamera_c::bumpCheck(u32 i_flags) {
field_0x968 *= mMonitor.field_0xc / 5.0f; field_0x968 *= mMonitor.field_0xc / 5.0f;
} }
#if TARGET_PC
if (!dusk::getSettings().game.freeCamera || !mCamParam.mManualMode) {
#endif
f32 tmp = field_0x96c * (mIsWolf == 1 ? 30.0f : 30.0f); f32 tmp = field_0x96c * (mIsWolf == 1 ? 30.0f : 30.0f);
center += vec3.norm() * (tmp * globe.V().Sin()); center += vec3.norm() * (tmp * globe.V().Sin());
cSGlobe globe2(vec2 - center); cSGlobe globe2(vec2 - center);
@@ -3108,6 +3106,10 @@ bool dCamera_c::bumpCheck(u32 i_flags) {
vec = lin_chk1.GetCross(); vec = lin_chk1.GetCross();
} }
#if TARGET_PC
}
#endif
#if DEBUG #if DEBUG
if (mCamSetup.CheckFlag(0x8000)) { if (mCamSetup.CheckFlag(0x8000)) {
dDbVw_Report(20, 235, " U"); dDbVw_Report(20, 235, " U");
@@ -3518,6 +3520,12 @@ void dCamera_c::checkGroundInfo() {
} }
bool dCamera_c::chaseCamera(s32 param_0) { bool dCamera_c::chaseCamera(s32 param_0) {
#if TARGET_PC
if (freeCamera()) {
return 1;
}
#endif
static f32 JumpCushion = 0.9f; static f32 JumpCushion = 0.9f;
f32 charge_latitude = mCamSetup.ChargeLatitude(); f32 charge_latitude = mCamSetup.ChargeLatitude();
int charge_timer = mCamSetup.ChargeTimer(); int charge_timer = mCamSetup.ChargeTimer();
@@ -4199,11 +4207,6 @@ bool dCamera_c::chaseCamera(s32 param_0) {
chase->field_0x8 -= chase->field_0xc; chase->field_0x8 -= chase->field_0xc;
chase->field_0x8c = 0; chase->field_0x8c = 0;
chase->field_0x90 = false; chase->field_0x90 = false;
#if TARGET_PC
freeCamera();
#endif
return true; return true;
} }
@@ -4641,11 +4644,6 @@ bool dCamera_c::chaseCamera(s32 param_0) {
if (chase->field_0x1c != 0) { if (chase->field_0x1c != 0) {
chase->field_0x1c--; chase->field_0x1c--;
} }
#if TARGET_PC
freeCamera();
#endif
return true; return true;
} }
@@ -7093,13 +7091,11 @@ bool dCamera_c::subjectCamera(s32 param_0) {
cXyz sp1E0(val0, val2, val1); cXyz sp1E0(val0, val2, val1);
#if TARGET_PC #if TARGET_PC
if (sp13) {
f32 aspect = mDoGph_gInf_c::getAspect(); f32 aspect = mDoGph_gInf_c::getAspect();
f32 baseAspect = FB_WIDTH / FB_HEIGHT; f32 baseAspect = FB_WIDTH / FB_HEIGHT;
if (aspect > baseAspect) { if (aspect > baseAspect) {
sp1E0.z += (aspect - baseAspect) * 4; sp1E0.z += (aspect - baseAspect) * 4;
} }
}
#endif #endif
sp1D4 = dCamMath::xyzRotateX(sp1E0, angle_x); sp1D4 = dCamMath::xyzRotateX(sp1E0, angle_x);
@@ -7476,47 +7472,52 @@ bool dCamera_c::test2Camera(s32 param_0) {
#if TARGET_PC #if TARGET_PC
bool dCamera_c::freeCamera() { bool dCamera_c::freeCamera() {
if (dusk::getSettings().game.freeCamera && mGear == 1) { if (!dusk::getSettings().game.freeCamera) {
mGear = 0;
}
if (!dusk::getSettings().game.freeCamera || mCamStyle == 70)
{
mCamParam.mManualMode = 0; mCamParam.mManualMode = 0;
return false; return false;
} }
if (!mCamParam.mManualMode) {
mCamParam.freeXAngle = mViewCache.mDirection.mAzimuth.Degree(); mCamParam.freeXAngle = mViewCache.mDirection.mAzimuth.Degree();
mCamParam.freeYAngle = mViewCache.mDirection.mInclination.Degree(); mCamParam.freeYAngle = mViewCache.mDirection.mInclination.Degree();
}
cXyz camMovement = {mPadInfo.mCStick.mLastPosX, mPadInfo.mCStick.mLastPosY, 0.0f}; cXyz camMovement = {mPadInfo.mCStick.mLastPosX, mPadInfo.mCStick.mLastPosY, 0.0f};
f32 magnitude = sqrt(mPadInfo.mCStick.mLastPosX * mPadInfo.mCStick.mLastPosX + mPadInfo.mCStick.mLastPosY * mPadInfo.mCStick.mLastPosY); f32 magnitude = sqrt(mPadInfo.mCStick.mLastPosX * mPadInfo.mCStick.mLastPosX + mPadInfo.mCStick.mLastPosY * mPadInfo.mCStick.mLastPosY);
if (mPadInfo.mCStick.mLastPosX != 0 || mPadInfo.mCStick.mLastPosY != 0) { if (mPadInfo.mCStick.mLastPosX != 0 || mPadInfo.mCStick.mLastPosY != 0) {
if (!mCamParam.mManualMode) {
mCamParam.mManualMode = 1; mCamParam.mManualMode = 1;
camMovement = camMovement.normalize(); mCamParam.freeXAngle = mViewCache.mDirection.mAzimuth.Degree();
camMovement.y *= dusk::getSettings().game.invertCameraYAxis ? 1.0f : -1.0f; mCamParam.freeYAngle = mViewCache.mDirection.mInclination.Degree();
mCamParam.freeXAngle += camMovement.x * magnitude * dusk::getSettings().game.freeCameraSensitivity * 5.0f;
mCamParam.freeYAngle += camMovement.y * magnitude * dusk::getSettings().game.freeCameraSensitivity * 5.0f;
} }
fopAc_ac_c* player = dComIfGp_getPlayer(0); camMovement = camMovement.normalize();
if (!mCamParam.mManualMode || player == nullptr) { camMovement.y *= dusk::getSettings().game.invertCameraYAxis ? 1.0f : -1.0f;
mCamParam.freeXAngle += camMovement.x * magnitude * dusk::getSettings().game.freeCameraSensitivity * 4.0f;
mCamParam.freeYAngle += camMovement.y * magnitude * dusk::getSettings().game.freeCameraSensitivity * 4.0f;
}
if (!mCamParam.mManualMode) {
return false; return false;
} }
f32 minYAngle = -30.0f; f32 minYAngle = -10.0f;
f32 maxAngle = 50.0f; f32 maxAngle = 50.0f;
mCamParam.freeYAngle = std::clamp(mCamParam.freeYAngle, minYAngle, maxAngle); mCamParam.freeYAngle = std::clamp(mCamParam.freeYAngle, minYAngle, maxAngle);
mViewCache.mDirection.mAzimuth = cSAngle(mCamParam.freeXAngle); mViewCache.mDirection.mAzimuth = cSAngle(mCamParam.freeXAngle);
mViewCache.mDirection.mInclination = cSAngle(mCamParam.freeYAngle); mViewCache.mDirection.mInclination = cSAngle(mCamParam.freeYAngle);
f32 currentLerp = (mCamParam.freeYAngle - minYAngle) / (maxAngle - minYAngle);
mViewCache.mDirection.mRadius = std::lerp(200.0f, 1000.0f, currentLerp);
cXyz finalEye = mViewCache.mCenter + mViewCache.mDirection.Xyz(); cXyz finalCenter = mpPlayerActor->current.pos;
finalCenter.y += mIsWolf ? 90.0f : 100.0f;
mViewCache.mCenter = finalCenter;
cXyz finalEye = finalCenter + mViewCache.mDirection.Xyz();
mViewCache.mEye = finalEye; mViewCache.mEye = finalEye;
mViewCache.mFovy = 60.0f;
return true; return true;
} }
#endif #endif
@@ -11160,25 +11161,12 @@ static int camera_draw(camera_process_class* i_this) {
} }
#endif #endif
int trim_height = body->TrimHeight();
#if TARGET_PC #if TARGET_PC
auto trim_height = body->TrimHeight();
if (mDoGph_gInf_c::isWideZoom()) {
const auto target_ar = FB_WIDTH / (FB_HEIGHT - trim_height * 2.0f);
const auto current_ar = mDoGph_gInf_c::m_safeWidthF / mDoGph_gInf_c::m_safeHeightF;
if (current_ar < target_ar) {
trim_height = FB_HEIGHT / 2.0f * (1.0f - current_ar / target_ar);
} else {
trim_height = 0.0f;
}
}
trim_height *= viewport->height / FB_HEIGHT; trim_height *= viewport->height / FB_HEIGHT;
window->setScissor(0.0f, trim_height, viewport->width, viewport->height - trim_height * 2.0f); window->setScissor(0.0f, trim_height, viewport->width, viewport->height - trim_height * 2.0f);
#else #else
int trim_height = body->TrimHeight();
window->setScissor(0.0f, trim_height, FB_WIDTH, FB_HEIGHT - trim_height * 2.0f); window->setScissor(0.0f, trim_height, FB_WIDTH, FB_HEIGHT - trim_height * 2.0f);
#endif #endif
+6 -42
View File
@@ -22,10 +22,6 @@
#include "dusk/frame_interpolation.h" #include "dusk/frame_interpolation.h"
#include "dusk/gx_helper.h" #include "dusk/gx_helper.h"
#include "dusk/logging.h" #include "dusk/logging.h"
static const void* getInterpKey(const void* base, int idx) {
return reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(base) ^ idx);
}
#endif #endif
class dDlst_2Dm_c { class dDlst_2Dm_c {
@@ -1066,15 +1062,7 @@ void dDlst_shadowReal_c::reset() {
} }
void dDlst_shadowReal_c::imageDraw(Mtx param_0) { void dDlst_shadowReal_c::imageDraw(Mtx param_0) {
#ifdef TARGET_PC
Mtx render_proj_mtx;
if (dusk::frame_interp::lookup_replacement(getInterpKey(mpModels[0], 2), render_proj_mtx)) {
GXSetProjection(render_proj_mtx, GX_ORTHOGRAPHIC);
} else
#endif
{
GXSetProjection(mRenderProjMtx, GX_ORTHOGRAPHIC); GXSetProjection(mRenderProjMtx, GX_ORTHOGRAPHIC);
}
JUT_ASSERT(1916, mModelNum); JUT_ASSERT(1916, mModelNum);
J3DModelData* model_data; J3DModelData* model_data;
J3DModel** models = mpModels; J3DModel** models = mpModels;
@@ -1087,15 +1075,7 @@ void dDlst_shadowReal_c::imageDraw(Mtx param_0) {
for (u16 j = 0; j < model_data->getShapeNum(); j++) { for (u16 j = 0; j < model_data->getShapeNum(); j++) {
if (!model_data->getShapeNodePointer(j)->checkFlag(1)) { if (!model_data->getShapeNodePointer(j)->checkFlag(1)) {
shape_pkt = (*models)->getShapePacket(j); shape_pkt = (*models)->getShapePacket(j);
#ifdef TARGET_PC
Mtx view_mtx;
if (dusk::frame_interp::lookup_replacement(getInterpKey(mpModels[0], 1), view_mtx)) {
shape_pkt->setBaseMtxPtr(&view_mtx);
} else
#endif
{
shape_pkt->setBaseMtxPtr(&mViewMtx); shape_pkt->setBaseMtxPtr(&mViewMtx);
}
shape_pkt->drawFast(); shape_pkt->drawFast();
shape_pkt->setBaseMtxPtr((Mtx*)param_0); shape_pkt->setBaseMtxPtr((Mtx*)param_0);
} }
@@ -1116,18 +1096,7 @@ void dDlst_shadowReal_c::draw() {
GXSetVtxDesc(GX_VA_POS, GX_DIRECT); GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0); GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
GXSetCurrentMtx(GX_PNMTX0); GXSetCurrentMtx(GX_PNMTX0);
#ifdef TARGET_PC
Mtx view_mtx, recv_proj_mtx;
const auto have_view_mtx = dusk::frame_interp::lookup_replacement(getInterpKey(mpModels[0], 1), view_mtx);
const auto have_recv_proj_mtx = dusk::frame_interp::lookup_replacement(getInterpKey(mpModels[0], 3), recv_proj_mtx);
if (have_view_mtx && have_recv_proj_mtx) {
cMtx_concat(recv_proj_mtx, view_mtx, recv_proj_mtx);
GXLoadTexMtxImm(recv_proj_mtx, GX_TEXMTX0, GX_MTX3x4);
} else
#endif
{
GXLoadTexMtxImm(mReceiverProjMtx, GX_TEXMTX0, GX_MTX3x4); GXLoadTexMtxImm(mReceiverProjMtx, GX_TEXMTX0, GX_MTX3x4);
}
mShadowRealPoly.draw(); mShadowRealPoly.draw();
} }
@@ -1284,13 +1253,6 @@ u8 dDlst_shadowReal_c::setShadowRealMtx(cXyz* param_0, cXyz* param_1, f32 param_
cMtx_lookAt(mViewMtx, &local_64, param_1, 0); cMtx_lookAt(mViewMtx, &local_64, param_1, 0);
C_MTXOrtho(mRenderProjMtx, param_2, -param_2, -param_2, param_2, 1.0f, 10000.0f); C_MTXOrtho(mRenderProjMtx, param_2, -param_2, -param_2, param_2, 1.0f, 10000.0f);
C_MTXLightOrtho(mReceiverProjMtx, param_2, -param_2, -param_2, param_2, 0.5f, -0.5f, 0.5f, 0.5f); C_MTXLightOrtho(mReceiverProjMtx, param_2, -param_2, -param_2, param_2, 0.5f, -0.5f, 0.5f, 0.5f);
#ifdef TARGET_PC
const auto keybase = mpModels[0];
dusk::frame_interp::record_final_mtx(mViewMtx, getInterpKey(keybase, 1));
dusk::frame_interp::record_final_mtx(mRenderProjMtx, getInterpKey(keybase, 2));
dusk::frame_interp::record_final_mtx(mReceiverProjMtx, getInterpKey(keybase, 3));
#endif
cMtx_concat(mReceiverProjMtx, mViewMtx, mReceiverProjMtx); cMtx_concat(mReceiverProjMtx, mViewMtx, mReceiverProjMtx);
return r29; return r29;
} }
@@ -1315,10 +1277,6 @@ u32 dDlst_shadowReal_c::set(u32 i_key, J3DModel* i_model, cXyz* param_2, f32 par
} }
} }
#ifdef TARGET_PC
// provide a stable key for interpolation
mpModels[0] = i_model;
#endif
field_0x1 = setShadowRealMtx(&sp60, param_2, param_3, param_4, param_7, param_5); field_0x1 = setShadowRealMtx(&sp60, param_2, param_3, param_4, param_7, param_5);
if (!field_0x1) { if (!field_0x1) {
@@ -1412,6 +1370,12 @@ void dDlst_shadowSimple_c::draw() {
GXCallDisplayList(l_shadowVolumeDL, 0x40); GXCallDisplayList(l_shadowVolumeDL, 0x40);
} }
#if TARGET_PC
static const void* getInterpKey(const void* base, int idx) {
return reinterpret_cast<const void*>(reinterpret_cast<uintptr_t>(base) ^ idx);
}
#endif
void dDlst_shadowSimple_c::set(cXyz* param_0, f32 param_1, f32 param_2, cXyz* param_3, void dDlst_shadowSimple_c::set(cXyz* param_0, f32 param_1, f32 param_2, cXyz* param_3,
s16 param_4, f32 param_5, TGXTexObj* param_6) { s16 param_4, f32 param_5, TGXTexObj* param_6) {
if (param_5 < 0.0f) { if (param_5 < 0.0f) {
+7
View File
@@ -78,7 +78,14 @@ void dEyeHL_mng_c::remove(dEyeHL_c* i_obj) {
next = m_obj; next = m_obj;
} }
#if TARGET_PC
// Skip the write if the heap owning m_timg was already destroyed
if (JKRHeap::findFromRoot(i_obj->m_timg) != nullptr) {
i_obj->m_timg->LODBias = i_obj->m_lodBias; i_obj->m_timg->LODBias = i_obj->m_lodBias;
}
#else
i_obj->m_timg->LODBias = i_obj->m_lodBias;
#endif
i_obj->m_timg = NULL; i_obj->m_timg = NULL;
i_obj->m_pre = NULL; i_obj->m_pre = NULL;
i_obj->m_next = NULL; i_obj->m_next = NULL;
+1 -2
View File
@@ -6,7 +6,6 @@
#include "d/dolzel.h" // IWYU pragma: keep #include "d/dolzel.h" // IWYU pragma: keep
#include "d/d_k_wmark.h" #include "d/d_k_wmark.h"
#include "dusk/memory.h"
#include "JSystem/J3DGraphBase/J3DMaterial.h" #include "JSystem/J3DGraphBase/J3DMaterial.h"
#include "SSystem/SComponent/c_math.h" #include "SSystem/SComponent/c_math.h"
#include "d/actor/d_a_player.h" #include "d/actor/d_a_player.h"
@@ -34,7 +33,7 @@ int dkWmark_c::create() {
mColorType = this->parameters; mColorType = this->parameters;
} }
mpHeap = mDoExt_createSolidHeapFromGameToCurrent(HEAP_SIZE(0x880, 0x1100), 0x20); mpHeap = mDoExt_createSolidHeapFromGameToCurrent(0x880, 0x20);
if (mpHeap != NULL) { if (mpHeap != NULL) {
JKRHEAP_NAME(mpHeap, "dkWmark_c::mpHeap"); JKRHEAP_NAME(mpHeap, "dkWmark_c::mpHeap");
J3DModelData* modelData = (J3DModelData*)dComIfG_getObjectRes("Alink", 0x23); J3DModelData* modelData = (J3DModelData*)dComIfG_getObjectRes("Alink", 0x23);
+1 -2
View File
@@ -1,7 +1,6 @@
#include "d/dolzel.h" // IWYU pragma: keep #include "d/dolzel.h" // IWYU pragma: keep
#include "d/d_kankyo.h" #include "d/d_kankyo.h"
#include "dusk/memory.h"
#ifdef __REVOLUTION_SDK__ #ifdef __REVOLUTION_SDK__
#include <revolution.h> #include <revolution.h>
#else #else
@@ -1186,7 +1185,7 @@ static void undwater_init() {
J3DModelData* modelData2 = (J3DModelData*)dComIfG_getObjectRes("Always", 0x1D); J3DModelData* modelData2 = (J3DModelData*)dComIfG_getObjectRes("Always", 0x1D);
JUT_ASSERT(1867, modelData2 != NULL); JUT_ASSERT(1867, modelData2 != NULL);
g_env_light.undwater_ef_heap = mDoExt_createSolidHeapFromGameToCurrent(HEAP_SIZE(0x600, 0xC00), 0x20); g_env_light.undwater_ef_heap = mDoExt_createSolidHeapFromGameToCurrent(0x600, 0x20);
JKRHEAP_NAME(g_env_light.undwater_ef_heap, "g_env_light.undwater_ef_heap"); JKRHEAP_NAME(g_env_light.undwater_ef_heap, "g_env_light.undwater_ef_heap");
if (g_env_light.undwater_ef_heap != NULL) { if (g_env_light.undwater_ef_heap != NULL) {
-43
View File
@@ -16,7 +16,6 @@
#ifdef TARGET_PC #ifdef TARGET_PC
constexpr u16 kMapResolutionMultiplier = 4; constexpr u16 kMapResolutionMultiplier = 4;
constexpr u16 kMapCircleSize = 16 * kMapResolutionMultiplier;
#endif #endif
void dMpath_n::dTexObjAggregate_c::create() { void dMpath_n::dTexObjAggregate_c::create() {
@@ -33,48 +32,6 @@ void dMpath_n::dTexObjAggregate_c::create() {
JUT_ASSERT(74, image->magFilter == GX_NEAR); JUT_ASSERT(74, image->magFilter == GX_NEAR);
mDoLib_setResTimgObj(image, mp_texObj[lp1], 0, NULL); mDoLib_setResTimgObj(image, mp_texObj[lp1], 0, NULL);
} }
#if TARGET_PC
auto hqCircle = JKR_NEW TGXTexObj();
static bool hqCircleDrawn = false;
static u8 hqCircleData[kMapCircleSize * kMapCircleSize];
if (!hqCircleDrawn) {
const auto center = kMapCircleSize / 2.0f;
const auto radiusSq = center * center;
const auto blocksAcross = kMapCircleSize >> 3;
const auto totalPixels = sizeof(hqCircleData);
for (size_t i = 0; i < totalPixels; i++) {
// 8x4 block swizzling for I8
const auto blockIdx = i >> 5;
const auto localIdx = i & 31;
const auto blockY = blockIdx / blocksAcross;
const auto blockX = blockIdx % blocksAcross;
const auto localY = localIdx >> 3;
const auto localX = localIdx & 7;
const auto x = (blockX << 3) + localX;
const auto y = (blockY << 2) + localY;
const auto dx = (x + 0.5f) - center;
const auto dy = (y + 0.5f) - center;
// the original texture is in I4 format and uses 1 to indicate if inside the circle
// so we scale to I8 range: 255 / 15 = 17
hqCircleData[i] = (dx * dx + dy * dy < radiusSq) ? 17 : 0;
}
hqCircleDrawn = true;
}
GXInitTexObj(hqCircle, hqCircleData, kMapCircleSize, kMapCircleSize, GX_TF_I8, GX_CLAMP,
GX_CLAMP, GX_FALSE);
GXInitTexObjLOD(hqCircle, GX_NEAR, GX_NEAR, 0.0f, 0.0f, 0.0f, GX_FALSE, GX_FALSE, GX_ANISO_1);
mp_texObj[6] = hqCircle;
#endif
} }
void dMpath_n::dTexObjAggregate_c::remove() { void dMpath_n::dTexObjAggregate_c::remove() {
-39
View File
@@ -856,46 +856,7 @@ void dMenu_DmapBg_c::decGoldFrameAlphaRate() {
setGoldFrameAlphaRate(rate); setGoldFrameAlphaRate(rate);
} }
void dMenu_DmapBg_c::dMapBgWide() {
// Scale Base HUD
mBaseScreen->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f);
mBaseScreen->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f);
// Boss Key, Compass & Map icons
mBaseScreen->search(MULTI_CHAR('key_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
mBaseScreen->search(MULTI_CHAR('con_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
mBaseScreen->search(MULTI_CHAR('map_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
// Text Header
mBaseScreen->search(MULTI_CHAR('t_t00'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
mBaseScreen->search(MULTI_CHAR('f_t_00'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
// C Button
mBaseScreen->search(MULTI_CHAR('c_btn2'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
// Scale Buttons HUD
mButtonScreen->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f);
mButtonScreen->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f);
// Buttons
mButtonScreen->search(MULTI_CHAR('cont_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
// C Button
mButtonScreen->search(MULTI_CHAR('c_btn'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
mButtonScreen->search(MULTI_CHAR('c_text_s'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
mButtonScreen->search(MULTI_CHAR('c_text'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
mButtonScreen->search(MULTI_CHAR('f_text_s'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
mButtonScreen->search(MULTI_CHAR('f_text'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
// Decorations
mButtonScreen->search(MULTI_CHAR('kazari_n'))->scale(mDoGph_gInf_c::hudAspectScaleDown, 1.0f);
}
void dMenu_DmapBg_c::draw() { void dMenu_DmapBg_c::draw() {
#if TARGET_PC
dMapBgWide();
#endif
u32 scissor_left; u32 scissor_left;
u32 scissor_top; u32 scissor_top;
u32 scissor_width; u32 scissor_width;
+1 -2
View File
@@ -21,7 +21,6 @@
#include "d/d_msg_object.h" #include "d/d_msg_object.h"
#include "d/d_msg_scrn_explain.h" #include "d/d_msg_scrn_explain.h"
#include "d/d_stage.h" #include "d/d_stage.h"
#include "dusk/memory.h"
#include "f_op/f_op_msg_mng.h" #include "f_op/f_op_msg_mng.h"
static dMf_HIO_c g_fmHIO; static dMf_HIO_c g_fmHIO;
@@ -190,7 +189,7 @@ dMenu_Fmap_c::dMenu_Fmap_c(JKRExpHeap* i_heap, STControl* i_stick, CSTControl* i
field_0x148[i] = 0.0f; field_0x148[i] = 0.0f;
} }
mpTalkHeap = JKRCreateExpHeap(HEAP_SIZE(0x32000, 0x40000), mpHeap, false); mpTalkHeap = JKRCreateExpHeap(0x32000, mpHeap, false);
JUT_ASSERT(359, mpTalkHeap != NULL); JUT_ASSERT(359, mpTalkHeap != NULL);
JKRHEAP_NAME(mpTalkHeap, "dMenu_Fmap_c::mpTalkHeap"); JKRHEAP_NAME(mpTalkHeap, "dMenu_Fmap_c::mpTalkHeap");
field_0x200 = 0; field_0x200 = 0;
+1 -34
View File
@@ -20,15 +20,6 @@
#include "dusk/frame_interpolation.h" #include "dusk/frame_interpolation.h"
#include <cstring> #include <cstring>
#if TARGET_PC
void dMenu_Fmap2DBack_c::fMapBackWide() {
mpBaseScreen->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f);
mpBaseScreen->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f);
mpBackScreen->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f);
mpBackScreen->translate(mDoGph_gInf_c::getSafeMinXF(), 0.0f);
}
#endif
dMenu_Fmap2DBack_c::dMenu_Fmap2DBack_c() { dMenu_Fmap2DBack_c::dMenu_Fmap2DBack_c() {
dMeter2Info_setMapDrugFlag(0); dMeter2Info_setMapDrugFlag(0);
@@ -276,10 +267,6 @@ dMenu_Fmap2DBack_c::~dMenu_Fmap2DBack_c() {
} }
void dMenu_Fmap2DBack_c::draw() { void dMenu_Fmap2DBack_c::draw() {
#if TARGET_PC
fMapBackWide();
#endif
calcBlink(); calcBlink();
J2DGrafContext* grafPort = dComIfGp_getCurrentGrafPort(); J2DGrafContext* grafPort = dComIfGp_getCurrentGrafPort();
@@ -1212,7 +1199,7 @@ f32 dMenu_Fmap2DBack_c::getMapScissorAreaSizeX() {
} }
f32 dMenu_Fmap2DBack_c::getMapScissorAreaSizeRealX() { f32 dMenu_Fmap2DBack_c::getMapScissorAreaSizeRealX() {
#if PLATFORM_GCN #if PLATFORM_GCN && !TARGET_PC
return getMapScissorAreaSizeX(); return getMapScissorAreaSizeX();
#else #else
return getMapScissorAreaSizeX() * mDoGph_gInf_c::getScale(); return getMapScissorAreaSizeX() * mDoGph_gInf_c::getScale();
@@ -1420,11 +1407,6 @@ void dMenu_Fmap2DBack_c::stageTextureDraw() {
mpSpotTexture->setAlpha(mAlphaRate * 255.0f * field_0xfa8 * mSpotTextureFadeAlpha); mpSpotTexture->setAlpha(mAlphaRate * 255.0f * field_0xfa8 * mSpotTextureFadeAlpha);
} }
#if TARGET_PC
JUTPalette* pPalette = mpSpotTexture->getTexture(0)->getPalette();
pPalette->dataUploaded();
#endif
mpSpotTexture->draw(mTransX + getMapScissorAreaLX(), mTransZ + getMapScissorAreaLY(), mpSpotTexture->draw(mTransX + getMapScissorAreaLX(), mTransZ + getMapScissorAreaLY(),
getMapScissorAreaSizeRealX(), getMapScissorAreaSizeRealY(), false, false, getMapScissorAreaSizeRealX(), getMapScissorAreaSizeRealY(), false, false,
false); false);
@@ -2197,17 +2179,6 @@ void dMenu_Fmap2DBack_c::setArrowPosAxis(f32 i_posX, f32 i_posZ) {
control_ypos = 0.0f; control_ypos = 0.0f;
} }
#if TARGET_PC
void dMenu_Fmap2DTop_c::fMapTopWide() {
mpTitleScreen->search(MULTI_CHAR('spot0_n'))->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f);
mpTitleScreen->search(MULTI_CHAR('spot2_n'))->scale(mDoGph_gInf_c::hudAspectScaleUp, 1.0f);
mpTitleScreen->search(MULTI_CHAR('name_n'))->translate(mDoGph_gInf_c::ScaleHUDXLeft(-243.0f), -169.0f);
mpTitleScreen->search(MULTI_CHAR('sub_n_n'))->translate(mDoGph_gInf_c::ScaleHUDXLeft(-80.0f), -154.0f);
mpTitleScreen->search(MULTI_CHAR('btn_i_n'))->translate(mDoGph_gInf_c::ScaleHUDXLeft(-241.0f), 177.0f);
mpTitleScreen->search(MULTI_CHAR('cont_n'))->translate(mDoGph_gInf_c::ScaleHUDXRight(515.0f), 83.0f);
}
#endif
dMenu_Fmap2DTop_c::dMenu_Fmap2DTop_c(JKRExpHeap* i_heap, STControl* i_stick) { dMenu_Fmap2DTop_c::dMenu_Fmap2DTop_c(JKRExpHeap* i_heap, STControl* i_stick) {
mpHeap = i_heap; mpHeap = i_heap;
mTransX = 0.0f; mTransX = 0.0f;
@@ -2601,10 +2572,6 @@ void dMenu_Fmap2DTop_c::setAllAlphaRate(f32 i_rate, bool i_init) {
} }
void dMenu_Fmap2DTop_c::draw() { void dMenu_Fmap2DTop_c::draw() {
#if TARGET_PC
fMapTopWide();
#endif
u32 scissor_left, scissor_top, scissor_width, scissor_height; u32 scissor_left, scissor_top, scissor_width, scissor_height;
J2DOrthoGraph* ctx = static_cast<J2DOrthoGraph*>(dComIfGp_getCurrentGrafPort()); J2DOrthoGraph* ctx = static_cast<J2DOrthoGraph*>(dComIfGp_getCurrentGrafPort());
ctx->setup2D(); ctx->setup2D();
-8
View File
@@ -17,10 +17,6 @@
#include "d/d_msg_scrn_arrow.h" #include "d/d_msg_scrn_arrow.h"
#include "d/d_lib.h" #include "d/d_lib.h"
#ifdef TARGET_PC
#include "dusk/achievements.h"
#endif
#if VERSION == VERSION_GCN_JPN #if VERSION == VERSION_GCN_JPN
#define D_MENU_LETTER_LINE_MAX 9 #define D_MENU_LETTER_LINE_MAX 9
#else #else
@@ -518,10 +514,6 @@ void dMenu_Letter_c::read_open_init() {
setAButtonString(0); setAButtonString(0);
setBButtonString(0); setBButtonString(0);
mpBlackTex->setAlpha(0); mpBlackTex->setAlpha(0);
#ifdef TARGET_PC
dusk::AchievementSystem::get().signal("open_letter");
#endif
} }
void dMenu_Letter_c::read_open_move() { void dMenu_Letter_c::read_open_move() {
+3 -7
View File
@@ -24,16 +24,12 @@
#include "d/actor/d_a_horse.h" #include "d/actor/d_a_horse.h"
#include <cstring> #include <cstring>
#include "dusk/memory.h"
#include "dusk/memory.h"
int dMeter2_c::_create() { int dMeter2_c::_create() {
stage_stag_info_class* stag_info = dComIfGp_getStageStagInfo(); stage_stag_info_class* stag_info = dComIfGp_getStageStagInfo();
if (dStage_stagInfo_GetUpButton(stag_info) == 1) { if (dStage_stagInfo_GetUpButton(stag_info) == 1) {
mpHeap = fopMsgM_createExpHeap(HEAP_SIZE(0x5A400, 0xA0000), NULL); mpHeap = fopMsgM_createExpHeap(0x5A400, NULL);
} else { } else {
mpHeap = fopMsgM_createExpHeap(HEAP_SIZE(0x60800, 0xC1000), NULL); mpHeap = fopMsgM_createExpHeap(0x60800, NULL);
} }
JKRHEAP_NAME(mpHeap, "dMeter2_c"); JKRHEAP_NAME(mpHeap, "dMeter2_c");
@@ -236,7 +232,7 @@ int dMeter2_c::_create() {
dMeter2Info_setMeterMapClass(mpMap); dMeter2Info_setMeterMapClass(mpMap);
mpHeap->getTotalFreeSize(); mpHeap->getTotalFreeSize();
mpSubHeap = fopMsgM_createExpHeap(HEAP_SIZE(0x5000, 0x6500), mpHeap); mpSubHeap = fopMsgM_createExpHeap(0x5000, mpHeap);
JKRHEAP_NAME(mpSubHeap, "dMeter2_c mpSubHeap"); JKRHEAP_NAME(mpSubHeap, "dMeter2_c mpSubHeap");
field_0x108 = NULL; field_0x108 = NULL;
mpSubContents = NULL; mpSubContents = NULL;
-4
View File
@@ -2306,10 +2306,6 @@ void dMeter_drawHIO_c::updateOnWide() {
// River Canoe Minigame // River Canoe Minigame
g_drawHIO.mMiniGame.mCounterPosX[1] = mDoGph_gInf_c::ScaleHUDXRight(g_drawHIO.mMiniGame.mCounterPosX[1]); g_drawHIO.mMiniGame.mCounterPosX[1] = mDoGph_gInf_c::ScaleHUDXRight(g_drawHIO.mMiniGame.mCounterPosX[1]);
g_drawHIO.mMiniGame.mIconPosX[1] = mDoGph_gInf_c::ScaleHUDXRight(g_drawHIO.mMiniGame.mIconPosX[1]); g_drawHIO.mMiniGame.mIconPosX[1] = mDoGph_gInf_c::ScaleHUDXRight(g_drawHIO.mMiniGame.mIconPosX[1]);
// Bulblin Count in Hidden Village
g_drawHIO.mMiniGame.mCounterPosX[2] = mDoGph_gInf_c::ScaleHUDXRight(g_drawHIO.mMiniGame.mCounterPosX[2]);
g_drawHIO.mMiniGame.mIconPosX[2] = mDoGph_gInf_c::ScaleHUDXRight(g_drawHIO.mMiniGame.mIconPosX[2]);
#endif #endif
} }
+8 -1
View File
@@ -1987,6 +1987,13 @@ bool jmessage_tSequenceProcessor::do_isReady() {
} }
#endif #endif
#if TARGET_PC
if (dusk::getSettings().game.instantText && mDoCPd_c::getHoldB(0)) {
field_0xb2 = 1;
pReference->setSendTimer(0);
}
#endif
if (dComIfGp_checkMesgBgm()) { if (dComIfGp_checkMesgBgm()) {
bool isItemMusicPlaying = true; bool isItemMusicPlaying = true;
if (mDoAud_checkPlayingSubBgmFlag() != Z2BGM_ITEM_GET && if (mDoAud_checkPlayingSubBgmFlag() != Z2BGM_ITEM_GET &&
@@ -2059,7 +2066,7 @@ bool jmessage_tSequenceProcessor::do_isReady() {
case 0: case 0:
case 5: case 5:
case 6: case 6:
if (mDoCPd_c::getTrigA(PAD_1) || field_0xb2 != 0 IF_DUSK(|| (dusk::getSettings().game.instantText && mDoCPd_c::getHoldB(0)))) { if (mDoCPd_c::getTrigA(PAD_1) || field_0xb2 != 0) {
field_0xa4 = 0; field_0xa4 = 0;
pReference->onBatchFlag(); pReference->onBatchFlag();
pReference->setCharCnt(D_MSG_CLASS_CHAR_CNT_MAX); pReference->setCharCnt(D_MSG_CLASS_CHAR_CNT_MAX);
+1 -38
View File
@@ -32,9 +32,6 @@
#if TARGET_PC #if TARGET_PC
#include "dusk/settings.h" #include "dusk/settings.h"
#include <vector>
#include <array>
#include <algorithm>
#endif #endif
static void dMsgObject_addFundRaising(s16 param_0); static void dMsgObject_addFundRaising(s16 param_0);
@@ -1597,7 +1594,7 @@ u8 dMsgObject_c::isSend() {
return 2; return 2;
} }
} else { } else {
if (IF_DUSK((dusk::getSettings().game.instantText && mDoCPd_c::getHoldB(0) && !isShopItemMessage()) ||) if (IF_DUSK((dusk::getSettings().game.instantText && mDoCPd_c::getHoldB(0)) ||)
mDoCPd_c::getTrigA(0) != 0 || mDoCPd_c::getTrigB(0) != 0) { mDoCPd_c::getTrigA(0) != 0 || mDoCPd_c::getTrigB(0) != 0) {
return 2; return 2;
} }
@@ -1869,40 +1866,6 @@ bool dMsgObject_c::isTalkMessage() {
return true; return true;
} }
#if TARGET_PC
bool dMsgObject_c::isShopItemMessage() {
// Probably a better way to do this than just listing every message id, but this works for now
// Note: Keep contents sorted so we can use binary search
const auto shopMsgIds = std::to_array<std::vector<s16>>({
{},
// zel_01.bmg - Seras Shop
{7001, 7003, 7004, 7005, 7006, 7007, 7008, 7009, 7010, 7013, 7014, 7022, 7023, 7028, 7029,
7044, 7045, 7053},
// zel_02.bmg - Kakariko Shops
{5251, 5253, 5254, 5256, 5258, 5259, 5653, 5654, 5656, 5660, 5661, 5664, 5665, 5697, 5698,
5699, 5803, 5804, 5806, 5810, 5811, 5812, 5814, 5821, 5823, 5824, 5987, 5988, 5989, 5990,
5991, 5992, 5993, 5994, 5995, 5996, 5997, 5998, 5999},
// zel_03.bmg - Death Mountain Shop
{5303, 5304, 5306, 5310, 5311, 5314, 5315, 5322, 5323, 5324, 5496, 5497, 5498, 5499},
// zel_04.bmg - Castle Town Shops
{5407, 5408, 5409, 5410, 5411, 5412, 5413, 5414, 5415, 5416, 5417, 5418, 5419, 5420, 5431,
5432, 5433, 5434, 5435, 5436, 5437, 5438, 5439, 5440, 5441, 5444, 5449, 5450, 5451, 5452,
5462},
// zel_05.bmg - Oocca Shop
{9428, 9429, 9430, 9431, 9432, 9437, 9443, 9448, 9449, 9451, 9459}
});
u16 id = mMessageID;
s16 group = dMsgObject_getGroupID();
if (group < shopMsgIds.size()) {
return std::ranges::binary_search(shopMsgIds[group], id);
}
return false;
}
#endif
const char* dMsgObject_c::getSmellName() { const char* dMsgObject_c::getSmellName() {
JMSMesgInfo_c* info_header_p = (JMSMesgInfo_c*)((char*)mpMsgRes + 0x20); JMSMesgInfo_c* info_header_p = (JMSMesgInfo_c*)((char*)mpMsgRes + 0x20);
char* data_ptr = (char*)info_header_p + info_header_p->header.size; char* data_ptr = (char*)info_header_p + info_header_p->header.size;
+12
View File
@@ -36,15 +36,27 @@ dRes_info_c::dRes_info_c() {
dRes_info_c::~dRes_info_c() { dRes_info_c::~dRes_info_c() {
if (mDMCommand != NULL) { if (mDMCommand != NULL) {
#if TARGET_PC
if (JKRHeap::findFromRoot(mDMCommand) != nullptr) {
#endif
mDMCommand->destroy(); mDMCommand->destroy();
#if TARGET_PC
}
#endif
mDMCommand = NULL; mDMCommand = NULL;
} else if (mArchive != NULL) { } else if (mArchive != NULL) {
#if TARGET_PC
if (JKRHeap::findFromRoot(mArchive) != nullptr) {
#endif
deleteArchiveRes(); deleteArchiveRes();
if (mDataHeap != NULL) { if (mDataHeap != NULL) {
mDoExt_destroySolidHeap(mDataHeap); mDoExt_destroySolidHeap(mDataHeap);
mDataHeap = NULL; mDataHeap = NULL;
mArchive->unmount(); mArchive->unmount();
} }
#if TARGET_PC
}
#endif
mRes = NULL; mRes = NULL;
mArchive = NULL; mArchive = NULL;
} }
+1 -2
View File
@@ -10,7 +10,6 @@
#include "d/d_meter2_info.h" #include "d/d_meter2_info.h"
#include "d/d_s_name.h" #include "d/d_s_name.h"
#include "dusk/imgui/ImGuiConsole.hpp" #include "dusk/imgui/ImGuiConsole.hpp"
#include "dusk/memory.h"
#include "dusk/settings.h" #include "dusk/settings.h"
#include "f_op/f_op_overlap_mng.h" #include "f_op/f_op_overlap_mng.h"
#include "f_op/f_op_scene_mng.h" #include "f_op/f_op_scene_mng.h"
@@ -77,7 +76,7 @@ static s32 resLoad(request_of_phase_process_class* i_phase, char* i_resName) {
s32 dScnName_c::create() { s32 dScnName_c::create() {
int phase_state = resLoad(&phase, "fileSel"); int phase_state = resLoad(&phase, "fileSel");
if (phase_state == cPhs_COMPLEATE_e) { if (phase_state == cPhs_COMPLEATE_e) {
mHeap = JKRCreateExpHeap(HEAP_SIZE(0x180000, 0x1C0000), mDoExt_getGameHeap(), false); mHeap = JKRCreateExpHeap(0x180000, mDoExt_getGameHeap(), false);
JUT_ASSERT(289, mHeap != NULL); JUT_ASSERT(289, mHeap != NULL);
JKRHEAP_NAME(mHeap, "File select"); JKRHEAP_NAME(mHeap, "File select");
+2 -25
View File
@@ -39,11 +39,6 @@
#include "JSystem/JKernel/JKRAram.h" #include "JSystem/JKernel/JKRAram.h"
#include "JSystem/JKernel/JKRAramArchive.h" #include "JSystem/JKernel/JKRAramArchive.h"
#if TARGET_PC
#include "dusk/memory.h"
#include <dusk/autosave.h>
#endif
#if DEBUG #if DEBUG
#include "d/d_s_menu.h" #include "d/d_s_menu.h"
#include "d/d_debug_pad.h" #include "d/d_debug_pad.h"
@@ -701,10 +696,6 @@ static u8 lbl_8074CAE4;
static u32 l_sceneChangeStartTick; static u32 l_sceneChangeStartTick;
#endif #endif
#if TARGET_PC
static BOOL autoSaved;
#endif
static int dScnPly_Execute(dScnPly_c* i_this) { static int dScnPly_Execute(dScnPly_c* i_this) {
#if DEBUG #if DEBUG
fapGm_HIO_c::startCpuTimer(); fapGm_HIO_c::startCpuTimer();
@@ -747,15 +738,6 @@ static int dScnPly_Execute(dScnPly_c* i_this) {
} }
} }
#if TARGET_PC
if (!dComIfGp_event_runCheck() && !fopOvlpM_IsPeek() && !dComIfG_resetToOpening(i_this) &&
!dComIfGp_isEnableNextStage() && autoSaved == FALSE)
{
triggerAutoSave();
autoSaved = TRUE;
}
#endif
dKy_itudemo_se(); dKy_itudemo_se();
#if DEBUG #if DEBUG
@@ -1438,7 +1420,7 @@ static int phase_4(dScnPly_c* i_this) {
dComIfGd_setViewport(NULL); dComIfGd_setViewport(NULL);
dComIfGd_setView(NULL); dComIfGd_setView(NULL);
JKRExpHeap* heap = fopMsgM_createExpHeap(HEAP_SIZE(0xBB800, 0x177000), NULL); JKRExpHeap* heap = fopMsgM_createExpHeap(0xBB800, NULL);
#if TARGET_PC #if TARGET_PC
heap->setName("Scene2DHeap"); heap->setName("Scene2DHeap");
#endif #endif
@@ -1446,7 +1428,7 @@ static int phase_4(dScnPly_c* i_this) {
JUT_ASSERT(2704, heap != NULL); JUT_ASSERT(2704, heap != NULL);
dComIfGp_setExpHeap2D(heap); dComIfGp_setExpHeap2D(heap);
JKRExpHeap* heap2 = fopMsgM_createExpHeap(HEAP_SIZE(0xA800, 0x15000), NULL); JKRExpHeap* heap2 = fopMsgM_createExpHeap(0xA800, NULL);
#if TARGET_PC #if TARGET_PC
heap2->setName("SceneMsgHeap"); heap2->setName("SceneMsgHeap");
#endif #endif
@@ -1607,11 +1589,6 @@ static int dScnPly_Create(scene_class* i_this) {
dScnPly_c* a_this = (dScnPly_c*)i_this; dScnPly_c* a_this = (dScnPly_c*)i_this;
int phase_state = dComLbG_PhaseHandler(&a_this->field_0x1c4, l_method, a_this); int phase_state = dComLbG_PhaseHandler(&a_this->field_0x1c4, l_method, a_this);
#if TARGET_PC
autoSaved = FALSE;
#endif
return phase_state; return phase_state;
} }
-8
View File
@@ -27,11 +27,7 @@
#include "lingcod/lingcod.h" #include "lingcod/lingcod.h"
#endif #endif
#if TARGET_PC
#include "dusk/settings.h" #include "dusk/settings.h"
#include <f_ap/f_ap_game.h>
#include <dusk/autosave.h>
#endif
static u8 dSv_item_rename(u8 i_itemNo) { static u8 dSv_item_rename(u8 i_itemNo) {
switch (i_itemNo) { switch (i_itemNo) {
@@ -349,10 +345,6 @@ void dSv_player_item_c::setItem(int i_slotNo, u8 i_itemNo) {
dComIfGp_setSelectItem(i); dComIfGp_setSelectItem(i);
} }
} }
#if TARGET_PC
triggerAutoSave();
#endif
} }
u8 dSv_player_item_c::getItem(int i_slotNo, bool i_checkCombo) const { u8 dSv_player_item_c::getItem(int i_slotNo, bool i_checkCombo) const {
-91
View File
@@ -1,91 +0,0 @@
#include "aurora/lib/logging.hpp"
#include "os_report.h"
aurora::Module Log("dusk::osReport");
bool dusk::OSReportReallyForceEnable = false;
u8 __OSReport_disable;
void OSReportDisable() {
__OSReport_disable = true;
}
void OSReportEnable() {
__OSReport_disable = false;
}
static bool checkEnabled() {
return !__OSReport_disable || dusk::OSReportReallyForceEnable;
}
static std::string FormatToString(const char* msg, va_list list) {
int ret = vsnprintf(nullptr, 0, msg, list);
std::string buf(ret, '\0');
vsnprintf(buf.data(), buf.size(), msg, list);
buf.pop_back();
return buf;
}
void OSReport_Error(const char* fmt, ...) {
if (!checkEnabled()) {
return;
}
va_list args;
va_start(args, fmt);
const auto str = FormatToString(fmt, args);
va_end(args);
Log.error("{}", str);
}
void OSReport_FatalError(const char* fmt, ...) {
if (!checkEnabled()) {
return;
}
va_list args;
va_start(args, fmt);
const auto str = FormatToString(fmt, args);
va_end(args);
Log.fatal("{}", str);
}
void OSReport_Warning(const char* fmt, ...) {
if (!checkEnabled()) {
return;
}
va_list args;
va_start(args, fmt);
const auto str = FormatToString(fmt, args);
va_end(args);
Log.warn("{}", str);
}
void OSReport_System(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
OSVAttention(fmt, args);
va_end(args);
}
void OSVAttention(const char* fmt, va_list args) {
if (!checkEnabled()) {
return;
}
const auto str = FormatToString(fmt, args);
Log.info("{}", str);
}
void OSAttention(const char* fmt, ...) {
va_list args;
va_start(args, fmt);
OSVAttention(fmt, args);
va_end(args);
}
+8 -127
View File
@@ -8,7 +8,6 @@
#include "d/actor/d_a_player.h" #include "d/actor/d_a_player.h"
#include "d/d_demo.h" #include "d/d_demo.h"
#include "f_pc/f_pc_name.h" #include "f_pc/f_pc_name.h"
#include "f_op/f_op_actor_mng.h"
#include <filesystem> #include <filesystem>
#include <algorithm> #include <algorithm>
@@ -47,21 +46,6 @@ std::vector<AchievementSystem::Entry> AchievementSystem::makeEntries() {
}, },
{} {}
}, },
{
{
"plumm_max",
"Thank You Berry Much",
"Score 61,454 points in the Plumm minigame.",
AchievementCategory::Minigame,
false, 0, 0, false
},
[](Achievement& a, json&) {
if (dComIfGs_getBalloonScore() >= 61454) {
a.progress = 1;
}
},
{}
},
{ {
{ {
"rollgoal_8", "rollgoal_8",
@@ -274,58 +258,6 @@ std::vector<AchievementSystem::Entry> AchievementSystem::makeEntries() {
}, },
{} {}
}, },
{
{
"friendly_fire",
"Friendly Fire",
"Get hit by your own cannonball.",
AchievementCategory::Misc,
false, 0, 0, false
},
[](Achievement& a, json&) {
if (AchievementSystem::get().hasSignal("iron_ball_hit_player")) {
a.progress = 1;
}
},
{}
},
{
{
"long_jump_attack",
"Long Jump Attack",
"Travel more than 20 meters in a single jump attack before landing.",
AchievementCategory::Misc,
false, 0, 0, false
},
[](Achievement& a, json&) {
static bool inJump = false;
static float startX = 0.0f, startZ = 0.0f;
const auto* link = static_cast<const daAlink_c*>(daPy_getPlayerActorClass());
if (link == nullptr) {
inJump = false;
return;
}
if (!inJump) {
if (link->mProcID == daAlink_c::PROC_CUT_JUMP) {
inJump = true;
startX = link->current.pos.x;
startZ = link->current.pos.z;
}
} else if (link->mProcID == daAlink_c::PROC_CUT_JUMP_LAND) {
inJump = false;
const float dx = link->current.pos.x - startX;
const float dz = link->current.pos.z - startZ;
if (dx * dx + dz * dz >= 2000.0f * 2000.0f) {
a.progress = 1;
}
} else if (link->mProcID != daAlink_c::PROC_CUT_JUMP) {
inJump = false;
}
},
{}
},
{ {
{ {
"back_in_time", "back_in_time",
@@ -335,14 +267,19 @@ std::vector<AchievementSystem::Entry> AchievementSystem::makeEntries() {
false, 0, 0, false false, 0, 0, false
}, },
[](Achievement& a, json&) { [](Achievement& a, json&) {
static int titleNoDemoFrames = 0;
if (fopAcM_SearchByName(fpcNm_TITLE_e) == nullptr) { if (fopAcM_SearchByName(fpcNm_TITLE_e) == nullptr) {
titleNoDemoFrames = 0;
return; return;
} }
const auto* player = static_cast<const daPy_py_c*>(daPy_getPlayerActorClass()); const auto* link = static_cast<const daAlink_c*>(daPy_getPlayerActorClass());
if (link != nullptr && dDemo_c::getMode() == 0) {
if (player != nullptr && player->mDemo.getDemoMode() == 1) { if (++titleNoDemoFrames >= 60) {
a.progress = 1; a.progress = 1;
} }
} else {
titleNoDemoFrames = 0;
}
}, },
{} {}
}, },
@@ -408,41 +345,6 @@ std::vector<AchievementSystem::Entry> AchievementSystem::makeEntries() {
} }
}, },
{} {}
},
{
{
"email_me",
"Email Me",
"Read a letter during the Dark Beast Ganon fight.",
AchievementCategory::Misc,
false, 0, 0, false
},
[](Achievement& a, json&) {
void* dbgExists = fopAcM_SearchByName(fpcNm_B_MGN_e);
if (dbgExists && AchievementSystem::get().hasSignal("open_letter")) {
a.progress = 1;
}
},
{}
},
{
{
"heavy-hitter",
"Heavy Hitter",
"Wear the Iron Boots during the end credits.",
AchievementCategory::Misc,
false, 0, 0, false
},
[](Achievement& a, json&) {
const auto* link = static_cast<const daAlink_c*>(daPy_getPlayerActorClass());
if (link == nullptr || link->mProcID != daAlink_c::PROC_GANON_FINISH) {
return;
}
if (daPy_getPlayerActorClass()->checkEquipHeavyBoots()) {
a.progress = 1;
}
},
{}
} }
}; };
} }
@@ -524,26 +426,6 @@ void AchievementSystem::clearAll() {
save(); save();
} }
void AchievementSystem::signal(const char* key) {
m_signals.insert(key);
}
bool AchievementSystem::hasSignal(const char* key) const {
return m_signals.count(key) > 0;
}
void AchievementSystem::clearOne(const char* key) {
for (auto& e : m_entries) {
if (std::string(e.achievement.key) == key) {
e.achievement.progress = 0;
e.achievement.unlocked = false;
e.extra = {};
break;
}
}
save();
}
void AchievementSystem::processEntry(Entry& e) { void AchievementSystem::processEntry(Entry& e) {
if (e.achievement.unlocked) { if (e.achievement.unlocked) {
return; return;
@@ -576,7 +458,6 @@ void AchievementSystem::tick() {
for (auto& e : m_entries) { for (auto& e : m_entries) {
processEntry(e); processEntry(e);
} }
m_signals.clear();
if (m_dirty) { if (m_dirty) {
save(); save();
m_dirty = false; m_dirty = false;
-54
View File
@@ -48,20 +48,6 @@ f32 dusk::audio::MasterVolume = 1.0f;
f32 dusk::audio::PrevMasterVolume = 1.0f; f32 dusk::audio::PrevMasterVolume = 1.0f;
bool dusk::audio::EnableReverb = true; bool dusk::audio::EnableReverb = true;
bool dusk::audio::DumpAudio = false; bool dusk::audio::DumpAudio = false;
bool dusk::audio::EnableHrtf = false;
f32 dusk::audio::HrtfGain = 0.5f;
// 3dB at 5kHz.
static constexpr f32 HRTF_LP_K = 0.75f;
static constexpr f32 HRTF_ALLPASS_G = 0.3f;
// Front never drops below (1 - HRTF_EXTRACT_MAX).
static constexpr f32 HRTF_EXTRACT_MAX = 0.6f;
static f32 sHrtfLp1 = 0.0f;
static f32 sHrtfLp2 = 0.0f;
static f32 sHrtfApIn1 = 0.0f;
static f32 sHrtfApOut1 = 0.0f;
/** /**
* Validate that a DSP channel's format is actually something we know how to play. * Validate that a DSP channel's format is actually something we know how to play.
@@ -297,9 +283,6 @@ void dusk::audio::DspRender(OutputSubframe& subframe) {
DspSubframe reverbInputR = {}; DspSubframe reverbInputR = {};
bool anyReverbInput = false; bool anyReverbInput = false;
DspSubframe surroundBus = {};
bool anySurroundInput = false;
for (int i = 0; i < channels.size(); i++) { for (int i = 0; i < channels.size(); i++) {
auto& channel = channels[i]; auto& channel = channels[i];
auto& channelAux = ChannelAux[i]; auto& channelAux = ChannelAux[i];
@@ -341,21 +324,6 @@ void dusk::audio::DspRender(OutputSubframe& subframe) {
} }
} }
if (EnableHrtf && channel.mAutoMixerBeenSet) {
f32 dolby = (channel.mAutoMixerPanDolby & 0xFF) / 127.0f;
if (dolby > 0.0f) {
anySurroundInput = true;
f32 extract = dolby * HRTF_EXTRACT_MAX;
f32 frontScale = 1.0f - extract;
for (int j = 0; j < DSP_SUBFRAME_SIZE; j++) {
f32 mono = (channelSubframe.channels[0][j] + channelSubframe.channels[1][j]) * 0.5f;
surroundBus[j] += mono * extract;
channelSubframe.channels[0][j] *= frontScale;
channelSubframe.channels[1][j] *= frontScale;
}
}
}
if (DumpAudio && sChannelDumpFiles[i]) { if (DumpAudio && sChannelDumpFiles[i]) {
f32 interleaved[DSP_SUBFRAME_SIZE * 2]; f32 interleaved[DSP_SUBFRAME_SIZE * 2];
for (int j = 0; j < DSP_SUBFRAME_SIZE; j++) { for (int j = 0; j < DSP_SUBFRAME_SIZE; j++) {
@@ -381,28 +349,6 @@ void dusk::audio::DspRender(OutputSubframe& subframe) {
ReverbHasTail = wetEnergy >= REVERB_ENERGY_EPSILON; ReverbHasTail = wetEnergy >= REVERB_ENERGY_EPSILON;
} }
if (EnableHrtf && anySurroundInput) {
// Two-pole LPF: -12 dB/oct above 3 kHz
for (int j = 0; j < DSP_SUBFRAME_SIZE; j++) {
sHrtfLp1 = (1.0f - HRTF_LP_K) * sHrtfLp1 + HRTF_LP_K * surroundBus[j];
sHrtfLp2 = (1.0f - HRTF_LP_K) * sHrtfLp2 + HRTF_LP_K * sHrtfLp1;
surroundBus[j] = sHrtfLp2;
}
// Mix into L and R
// L gets the filtered signal directly; R gets it allpass for mild decorrelation
for (int j = 0; j < DSP_SUBFRAME_SIZE; j++) {
f32 s = surroundBus[j];
subframe.channels[0][j] += s * HrtfGain;
f32 r = -HRTF_ALLPASS_G * s + sHrtfApIn1 + HRTF_ALLPASS_G * sHrtfApOut1;
sHrtfApIn1 = s;
sHrtfApOut1 = r;
subframe.channels[1][j] += r * HrtfGain;
}
}
for (auto& channel : subframe.channels) { for (auto& channel : subframe.channels) {
ApplyVolume(channel, channel, PrevMasterVolume, MasterVolume); ApplyVolume(channel, channel, PrevMasterVolume, MasterVolume);
} }
-2
View File
@@ -133,6 +133,4 @@ namespace dusk::audio {
extern f32 PrevMasterVolume; extern f32 PrevMasterVolume;
extern bool EnableReverb; extern bool EnableReverb;
extern bool DumpAudio; extern bool DumpAudio;
extern bool EnableHrtf;
extern f32 HrtfGain;
} }
-88
View File
@@ -1,88 +0,0 @@
#include "dusk/autosave.h"
#include "imgui/ImGuiConsole.hpp"
u8 mSaveBuffer[QUEST_LOG_SIZE * 3];
u8 mAutoSaveProc = 0;
int autoSaveWriteState = 0;
typedef void (*AutoSaveFuncs)();
static AutoSaveFuncs AutoSaveFuncsProc[] = {
noAutoSave, enterAutoSave, autoSaving, waitingForWrite, endAutoSave,
};
void noAutoSave() {}
void triggerAutoSave() {
if (dusk::getSettings().game.autoSave && mAutoSaveProc == 0 &&
strcmp(dComIfGp_getStartStageName(), "F_SP102") != 0)
{
mAutoSaveProc = 1;
}
}
void updateAutoSave() {
(AutoSaveFuncsProc[mAutoSaveProc])();
}
void writeAutoSave() {
int stageNo = dStage_stagInfo_GetSaveTbl(dComIfGp_getStageStagInfo());
dComIfGs_putSave(stageNo);
dComIfGs_setMemoryToCard(mSaveBuffer, dComIfGs_getDataNum());
mDoMemCdRWm_SetCheckSumGameData(mSaveBuffer, dComIfGs_getDataNum());
u8* save = mSaveBuffer;
for (int i = 0; i < 3; i++) {
mDoMemCdRWm_TestCheckSumGameData(save);
save += QUEST_LOG_SIZE;
}
g_mDoMemCd_control.save(mSaveBuffer, sizeof(mSaveBuffer), 0);
}
void autoSaving() {
int cardState = g_mDoMemCd_control.LoadSync(mSaveBuffer, sizeof(mSaveBuffer), 0);
if (cardState != 0) {
if (cardState == 2) {
mAutoSaveProc = 1;
} else if (cardState == 1) {
writeAutoSave();
mAutoSaveProc = 3;
}
}
}
void enterAutoSave() {
u32 cardStatus = g_mDoMemCd_control.getStatus(0);
if (cardStatus != 14) {
switch (cardStatus) {
case 2:
g_mDoMemCd_control.load();
mAutoSaveProc = 2;
break;
case 3:
case 4:
case 5:
break;
default:
mAutoSaveProc = 0;
break;
}
}
}
void waitingForWrite() {
autoSaveWriteState = g_mDoMemCd_control.SaveSync();
if (autoSaveWriteState == 2) {
mAutoSaveProc = 0;
} else if (autoSaveWriteState == 1) {
mAutoSaveProc = 4;
}
}
void endAutoSave() {
dusk::g_imguiConsole.AddToast("Saving...", 2.0f);
mAutoSaveProc = 0;
}
+3 -20
View File
@@ -76,8 +76,8 @@ void ImGuiAchievements::draw(bool& open) {
return; return;
} }
ImGui::SetNextWindowSizeConstraints(ImVec2(800, 200), ImVec2(1280, 900)); ImGui::SetNextWindowSizeConstraints(ImVec2(640, 200), ImVec2(800, 900));
ImGui::SetNextWindowSize(ImVec2(800, 480), ImGuiCond_FirstUseEver); ImGui::SetNextWindowSize(ImVec2(640, 480), ImGuiCond_FirstUseEver);
if (!ImGui::Begin( if (!ImGui::Begin(
"Achievements", &open, "Achievements", &open,
@@ -111,7 +111,6 @@ void ImGuiAchievements::draw(bool& open) {
{AchievementCategory::Collection, "Collection", ImVec4(0.3f, 0.85f, 0.4f, 1.0f)}, {AchievementCategory::Collection, "Collection", ImVec4(0.3f, 0.85f, 0.4f, 1.0f)},
{AchievementCategory::Challenge, "Challenge", ImVec4(1.0f, 0.65f, 0.15f, 1.0f)}, {AchievementCategory::Challenge, "Challenge", ImVec4(1.0f, 0.65f, 0.15f, 1.0f)},
{AchievementCategory::Minigame, "Minigame", ImVec4(0.5f, 0.85f, 1.0f, 1.0f)}, {AchievementCategory::Minigame, "Minigame", ImVec4(0.5f, 0.85f, 1.0f, 1.0f)},
{AchievementCategory::Misc, "Misc", ImVec4(0.65f, 0.65f, 0.65f, 1.0f)},
{AchievementCategory::Glitched, "Glitched", ImVec4(0.75f, 0.4f, 1.0f, 1.0f)}, {AchievementCategory::Glitched, "Glitched", ImVec4(0.75f, 0.4f, 1.0f, 1.0f)},
}; };
@@ -132,7 +131,7 @@ void ImGuiAchievements::draw(bool& open) {
continue; continue;
} }
const std::string tabLabel = fmt::format("{} ({}/{})###{}", catInfo.label, catUnlocked, catTotal, catInfo.label); const std::string tabLabel = fmt::format("{} ({}/{})", catInfo.label, catUnlocked, catTotal);
ImGui::PushStyleColor(ImGuiCol_Text, catInfo.color); ImGui::PushStyleColor(ImGuiCol_Text, catInfo.color);
const bool tabOpen = ImGui::BeginTabItem(tabLabel.c_str()); const bool tabOpen = ImGui::BeginTabItem(tabLabel.c_str());
@@ -153,7 +152,6 @@ void ImGuiAchievements::draw(bool& open) {
continue; continue;
} }
ImGui::PushID(a.key); ImGui::PushID(a.key);
ImGui::BeginGroup();
ImGui::PushStyleColor( ImGui::PushStyleColor(
ImGuiCol_Text, ImGuiCol_Text,
@@ -192,21 +190,6 @@ void ImGuiAchievements::draw(bool& open) {
ImGui::PopStyleColor(); ImGui::PopStyleColor();
} }
ImGui::EndGroup();
if (ImGui::IsItemHovered() && ImGui::IsMouseClicked(ImGuiMouseButton_Right)) {
ImGui::OpenPopup("##ctx");
}
if (ImGui::BeginPopup("##ctx")) {
ImGui::TextDisabled("%s", a.name);
ImGui::Separator();
if (ImGui::MenuItem("Clear Achievement")) {
AchievementSystem::get().clearOne(a.key);
}
ImGui::EndPopup();
}
ImGui::Spacing(); ImGui::Spacing();
ImGui::PopID(); ImGui::PopID();
} }
+142
View File
@@ -0,0 +1,142 @@
#include "imgui.h"
#include "ImGuiMenuTools.hpp"
#include "d/actor/d_a_alink.h"
#include "d/d_com_inf_game.h"
#include "f_op/f_op_actor_mng.h"
#include "SSystem/SComponent/c_sxyz.h"
#include "SSystem/SComponent/c_xyz.h"
namespace dusk {
namespace {
struct ActorSpawnerState {
int actorId = 0;
int params = -1;
int argument = -1;
int angleX = 0;
int angleY = 0;
int angleZ = 0;
float scaleX = 1.0f;
float scaleY = 1.0f;
float scaleZ = 1.0f;
bool usePlayerRoom = true;
int manualRoom = 0;
int spawnCount = 1;
bool hasResult = false;
unsigned int lastResult = 0;
int lastAttempted = 0;
};
ActorSpawnerState s_state;
} // namespace
void ImGuiMenuTools::ShowActorSpawner() {
if (!m_showActorSpawner) {
return;
}
if (!ImGui::Begin("Actor Spawner", &m_showActorSpawner)) {
ImGui::End();
return;
}
daAlink_c* player = (daAlink_c*)dComIfGp_getPlayer(0);
ImGui::SeparatorText("Actor");
ImGui::InputInt("Actor ID", &s_state.actorId);
ImGui::InputInt("Params (hex)", &s_state.params, 0, 0, ImGuiInputTextFlags_CharsHexadecimal);
ImGui::InputInt("Argument", &s_state.argument);
s_state.argument = (s_state.argument < -128) ? -128 : (s_state.argument > 127) ? 127 : s_state.argument;
ImGui::SeparatorText("Angle");
ImGui::InputInt("Angle X", &s_state.angleX);
ImGui::InputInt("Angle Y", &s_state.angleY);
ImGui::InputInt("Angle Z", &s_state.angleZ);
ImGui::SeparatorText("Scale");
ImGui::InputFloat("Scale X", &s_state.scaleX, 0.1f, 1.0f);
ImGui::InputFloat("Scale Y", &s_state.scaleY, 0.1f, 1.0f);
ImGui::InputFloat("Scale Z", &s_state.scaleZ, 0.1f, 1.0f);
ImGui::SeparatorText("Spawn");
ImGui::InputInt("Count", &s_state.spawnCount);
if (s_state.spawnCount < 1) {
s_state.spawnCount = 1;
}
ImGui::SeparatorText("Position");
ImGui::Checkbox("Use player room", &s_state.usePlayerRoom);
if (!s_state.usePlayerRoom) {
ImGui::InputInt("Room No", &s_state.manualRoom);
}
if (player != nullptr) {
ImGui::Text("Spawn pos: %.2f, %.2f, %.2f",
player->current.pos.x, player->current.pos.y, player->current.pos.z);
} else {
ImGui::TextDisabled("Player not available");
}
ImGui::Separator();
bool canSpawn = player != nullptr;
if (!canSpawn) {
ImGui::BeginDisabled();
}
if (ImGui::Button("Spawn", ImVec2(-1, 0))) {
cXyz pos = player->current.pos;
csXyz angle;
angle.set((s16)s_state.angleX, (s16)s_state.angleY, (s16)s_state.angleZ);
cXyz scale(s_state.scaleX, s_state.scaleY, s_state.scaleZ);
int roomNo = s_state.usePlayerRoom ? player->current.roomNo : s_state.manualRoom;
layer_class* savedLayer = fpcLy_CurrentLayer();
base_process_class* playScene = fpcM_SearchByName(fpcNm_PLAY_SCENE_e);
if (playScene != nullptr) {
fpcLy_SetCurrentLayer(&((process_node_class*)playScene)->layer);
}
s_state.lastResult = 0;
s_state.lastAttempted = s_state.spawnCount;
for (int i = 0; i < s_state.spawnCount; ++i) {
unsigned int result = fopAcM_create(
(s16)s_state.actorId,
(u32)s_state.params,
&pos,
roomNo,
&angle,
&scale,
(s8)s_state.argument
);
if (result != 0) {
s_state.lastResult = result;
}
}
s_state.hasResult = true;
fpcLy_SetCurrentLayer(savedLayer);
}
if (!canSpawn) {
ImGui::EndDisabled();
}
if (s_state.hasResult) {
if (s_state.lastResult != 0) {
if (s_state.lastAttempted == 1) {
ImGui::Text("Spawned: proc ID %u", s_state.lastResult);
} else {
ImGui::Text("Spawned %d (last proc ID %u)", s_state.lastAttempted, s_state.lastResult);
}
} else {
ImGui::TextColored(ImVec4(1, 0.4f, 0.4f, 1), "Spawn failed (returned 0)");
}
}
ImGui::End();
}
} // namespace dusk
+1 -74
View File
@@ -1,7 +1,5 @@
#include "ImGuiConsole.hpp" #include "ImGuiConsole.hpp"
#include "ImGuiMenuTools.hpp" #include "ImGuiMenuTools.hpp"
#include <cmath>
#include "JSystem/JAudio2/JAISeq.h"
#include "JSystem/JAudio2/JAISeMgr.h" #include "JSystem/JAudio2/JAISeMgr.h"
#include "JSystem/JAudio2/JAISeqMgr.h" #include "JSystem/JAudio2/JAISeqMgr.h"
#include "JSystem/JAudio2/JAIStreamMgr.h" #include "JSystem/JAudio2/JAIStreamMgr.h"
@@ -17,24 +15,6 @@ static std::array<u32, DSP_CHANNELS> lastResetCounts = {};
static bool sortUpdateCount = true; static bool sortUpdateCount = true;
static void DrawDirectionGauge(float pan, float dolby) {
constexpr float R = 20.0f;
constexpr float SIZE = R * 2.0f + 4.0f;
ImVec2 origin = ImGui::GetCursorScreenPos();
ImGui::Dummy(ImVec2(SIZE, SIZE));
ImDrawList* dl = ImGui::GetWindowDrawList();
ImVec2 c = ImVec2(origin.x + SIZE * 0.5f, origin.y + SIZE * 0.5f);
dl->AddCircle(c, R, IM_COL32(90, 90, 90, 255), 32);
float dx = (pan - 0.5f) * 2.0f;
float dy = dolby * 2.0f - 1.0f;
float len = sqrtf(dx * dx + dy * dy);
if (len > 1.0f) { dx /= len; dy /= len; }
dl->AddLine(c, ImVec2(c.x + dx * R, c.y + dy * R), IM_COL32(255, 200, 50, 255), 1.5f);
}
static void DisplayDspChannel(int i) { static void DisplayDspChannel(int i) {
using namespace dusk::audio; using namespace dusk::audio;
@@ -72,10 +52,8 @@ static void DisplayDspChannel(int i) {
auto fxMix = (channel.mAutoMixerFxMix >> 8) / 127.5f; auto fxMix = (channel.mAutoMixerFxMix >> 8) / 127.5f;
auto volume = VolumeFromU16(channel.mAutoMixerVolume); auto volume = VolumeFromU16(channel.mAutoMixerVolume);
auto pitch = channel.mPitch / 4096.0f; auto pitch = channel.mPitch / 4096.0f;
DrawDirectionGauge(pan, dolby);
ImGui::SameLine();
ImGui::Text( ImGui::Text(
"pan: %.2f dolby: %.2f\nfx: %.2f vol: %.2f pitch: %.2f", "Auto mixer active (pan: %f, dolby: %f, fx: %f, volume: %f, pitch %f)",
pan, dolby, fxMix, volume, pitch); pan, dolby, fxMix, volume, pitch);
} else { } else {
ImGui::Text( ImGui::Text(
@@ -205,10 +183,6 @@ static void ShowAllJAISes() {
if (ImGui::Button("Pause All")) { if (ImGui::Button("Pause All")) {
category->pause(true); category->pause(true);
} }
ImGui::SameLine();
if (ImGui::Button("Resume All")) {
category->pause(false);
}
for (auto seLink = category->getSeList()->getFirst(); seLink != nullptr; seLink = seLink->getNext()) { for (auto seLink = category->getSeList()->getFirst(); seLink != nullptr; seLink = seLink->getNext()) {
const auto se = seLink->getObject(); const auto se = seLink->getObject();
@@ -222,33 +196,6 @@ static void ShowAllJAISes() {
} }
static void ShowSeqTracks(JAISeq& seq) {
JASTrack& root = seq.inner_.outputTrack;
for (int group = 0; group < 2; group++) {
JASTrack* groupTrack = root.getChild(group);
if (groupTrack == nullptr) {
continue;
}
for (int j = 0; j < JASTrack::MAX_CHILDREN; j++) {
JASTrack* track = groupTrack->getChild(j);
if (track == nullptr) {
continue;
}
int trackIdx = group * 16 + j;
char label[64];
snprintf(label, sizeof(label), "Track %d (bank %hu, prog %hu)##%p",
trackIdx, track->getBankNumber(), track->getProgNumber(), track);
bool muted = track->mFlags.mute;
if (ImGui::Checkbox(label, &muted)) {
track->mute(muted);
}
}
}
}
static void ShowAllJAISeqs() { static void ShowAllJAISeqs() {
auto& mgr = *JAISeqMgr::getInstance(); auto& mgr = *JAISeqMgr::getInstance();
@@ -259,26 +206,6 @@ static void ShowAllJAISeqs() {
if (ImGui::Button("Unpause")) { if (ImGui::Button("Unpause")) {
mgr.pause(false); mgr.pause(false);
} }
ImGui::Text("Active sequences: %d", mgr.getNumActiveSeqs());
auto* seqList = mgr.getSeqList();
for (auto* link = seqList->getFirst(); link != nullptr; link = link->getNext()) {
JAISeq* seq = link->getObject();
if (seq == nullptr) {
continue;
}
char buf[32];
snprintf(buf, sizeof(buf), "%p", seq);
if (ImGui::BeginChild(buf, ImVec2(), ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY)) {
ImGui::Text("Seq [%p]", seq);
ShowSeqTracks(*seq);
}
ImGui::EndChild();
}
} }
void dusk::ImGuiMenuTools::ShowAudioDebug() { void dusk::ImGuiMenuTools::ShowAudioDebug() {
+12 -11
View File
@@ -324,19 +324,19 @@ namespace dusk {
ImGuiMenuGame::ToggleFullscreen(); ImGuiMenuGame::ToggleFullscreen();
} }
// if (!dusk::IsGameLaunched) { if (!dusk::IsGameLaunched) {
// m_preLaunchWindow.draw(); m_preLaunchWindow.draw();
// } }
m_isHidden = !getSettings().backend.duskMenuOpen; m_isHidden = !getSettings().backend.duskMenuOpen;
if (ImGui::GetIO().KeyShift && ImGui::IsKeyPressed(ImGuiKey_F1)) { bool showMenu = !dusk::IsGameLaunched || !CheckMenuViewToggle(ImGuiKey_F1, m_isHidden);
m_isHidden = !m_isHidden; if (dusk::IsGameLaunched) {
} const bool menuOpen = !m_isHidden;
bool showMenu = !m_isHidden; if (getSettings().backend.duskMenuOpen != menuOpen) {
if (getSettings().backend.duskMenuOpen != showMenu) { getSettings().backend.duskMenuOpen.setValue(menuOpen);
getSettings().backend.duskMenuOpen.setValue(showMenu);
Save(); Save();
} }
}
// The menu bar renders with ImGuiCol_WindowBg behind it. We just want ImGuiCol_MenuBarBg, // The menu bar renders with ImGuiCol_WindowBg behind it. We just want ImGuiCol_MenuBarBg,
// so make the window bg fully transparent temporarily // so make the window bg fully transparent temporarily
@@ -365,10 +365,10 @@ namespace dusk {
} }
if (dusk::IsGameLaunched && !m_isLaunchInitialized) { if (dusk::IsGameLaunched && !m_isLaunchInitialized) {
AddToast(ImGui::GetIO().MouseSource == ImGuiMouseSource_TouchScreen ? m_toasts.emplace_back(ImGui::GetIO().MouseSource == ImGuiMouseSource_TouchScreen ?
"Tap to toggle menu"s : "Tap to toggle menu"s :
"Press F1 to toggle menu"s, "Press F1 to toggle menu"s,
4.f); 2.5f);
m_isLaunchInitialized = true; m_isLaunchInitialized = true;
if (getSettings().game.liveSplitEnabled) { if (getSettings().game.liveSplitEnabled) {
dusk::speedrun::connectLiveSplit(); dusk::speedrun::connectLiveSplit();
@@ -401,6 +401,7 @@ namespace dusk {
m_menuTools.ShowAudioDebug(); m_menuTools.ShowAudioDebug();
m_menuTools.ShowSaveEditor(); m_menuTools.ShowSaveEditor();
m_menuTools.ShowStateShare(); m_menuTools.ShowStateShare();
m_menuTools.ShowActorSpawner();
} }
m_menuTools.ShowAchievements(); m_menuTools.ShowAchievements();
DuskDebugPad(); // temporary, remove later DuskDebugPad(); // temporary, remove later
File diff suppressed because it is too large Load Diff
-1
View File
@@ -44,7 +44,6 @@ static void ApplyPresetDusk() {
s.game.enableFrameInterpolation.setValue(true); s.game.enableFrameInterpolation.setValue(true);
s.game.sunsSong.setValue(true); s.game.sunsSong.setValue(true);
s.game.bloomMode.setValue(BloomMode::Dusk); s.game.bloomMode.setValue(BloomMode::Dusk);
s.game.autoSave.setValue(true);
} }
// ========================================================================= // =========================================================================
+28 -3
View File
@@ -6,6 +6,7 @@
#include "JSystem/JFramework/JFWSystem.h" #include "JSystem/JFramework/JFWSystem.h"
#include "JSystem/JKernel/JKRExpHeap.h" #include "JSystem/JKernel/JKRExpHeap.h"
#include "JSystem/JKernel/JKRHeap.h" #include "JSystem/JKernel/JKRHeap.h"
#include "JSystem/JKernel/JKRSolidHeap.h"
#include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_map.h"
#include "imgui.h" #include "imgui.h"
@@ -178,9 +179,9 @@ namespace dusk {
} }
void ShowHeapDetailed(JKRHeap* heap, OpenHeapData& data, bool& open) { void ShowHeapDetailed(JKRHeap* heap, OpenHeapData& data, bool& open) {
const char* heapName = data.Safe ? heap->getName() : "INVALID";
char title[128]; char title[128];
const char* name = data.Safe ? heap->getName() : "INVALID"; snprintf(title, sizeof(title), "Heap %s##%p", heapName, static_cast<const void*>(heap));
snprintf(title, sizeof(title), "Heap %s##%p", name, static_cast<const void*>(heap));
if (!ImGui::Begin(title, &open)) { if (!ImGui::Begin(title, &open)) {
ImGui::End(); ImGui::End();
@@ -195,11 +196,35 @@ namespace dusk {
heap->lock(); heap->lock();
ImGui::Text("Name: %s", name); ImGui::Text("Name: %s", heap->getName());
const auto size = BytesToString(heap->getSize()); const auto size = BytesToString(heap->getSize());
const auto freeSize = BytesToString(heap->getFreeSize()); const auto freeSize = BytesToString(heap->getFreeSize());
ImGui::Text("Size: %08X (%s), free: %08X (%s)", heap->getSize(), size.c_str(), heap->getFreeSize(), freeSize.c_str()); ImGui::Text("Size: %08X (%s), free: %08X (%s)", heap->getSize(), size.c_str(), heap->getFreeSize(), freeSize.c_str());
{
void* vmemBase = nullptr;
size_t vmemCapacity = 0;
size_t vmemCommitted = 0;
if (heap->getHeapType() == 'EXPH') {
auto* h = static_cast<JKRExpHeap*>(heap);
vmemBase = h->mVmemBase; vmemCapacity = h->mVmemCapacity; vmemCommitted = h->mVmemCommitted;
} else if (heap->getHeapType() == 'SLID') {
auto* h = static_cast<JKRSolidHeap*>(heap);
vmemBase = h->mVmemBase; vmemCapacity = h->mVmemCapacity; vmemCommitted = h->mVmemCommitted;
}
if (vmemBase) {
ImGui::SeparatorText("Virtual Memory");
ImGui::Text("Base: %p", vmemBase);
const auto committedStr = BytesToString(vmemCommitted);
const auto capacityStr = BytesToString(vmemCapacity);
ImGui::Text("Committed: %s / %s reserved", committedStr.c_str(), capacityStr.c_str());
float pct = vmemCapacity > 0 ? (float)vmemCommitted / (float)vmemCapacity : 0.0f;
char overlayBuf[32];
snprintf(overlayBuf, sizeof(overlayBuf), "%.1f%%", pct * 100.0f);
ImGui::ProgressBar(pct, ImVec2(-1.0f, 0.0f), overlayBuf);
}
}
if (ImGui::Button("Check")) { if (ImGui::Button("Check")) {
data.HeapCheckFailed = !heap->check(); data.HeapCheckFailed = !heap->check();
data.HeapCheckRan = true; data.HeapCheckRan = true;
+478 -3
View File
@@ -3,13 +3,31 @@
#include "ImGuiEngine.hpp" #include "ImGuiEngine.hpp"
#include "ImGuiConsole.hpp" #include "ImGuiConsole.hpp"
#include "ImGuiMenuGame.hpp"
#include "ImGuiConfig.hpp" #include "ImGuiConfig.hpp"
#include "JSystem/JUtility/JUTGamePad.h"
#include "dusk/audio/DuskAudioSystem.h"
#include "dusk/audio/DuskDsp.hpp"
#include "dusk/main.h" #include "dusk/main.h"
#include "dusk/hotkeys.h" #include "dusk/hotkeys.h"
#include "dusk/settings.h"
#include "dusk/livesplit.h"
#include "m_Do/m_Do_controller_pad.h"
#include "m_Do/m_Do_graphic.h"
#include <aurora/gfx.h>
#include <SDL3/SDL_gamepad.h>
#include "m_Do/m_Do_main.h" #include "m_Do/m_Do_main.h"
#include <SDL3/SDL_gamepad.h> namespace {
constexpr int kInternalResolutionScaleMax = 12;
} // namespace
namespace aurora::gx {
extern bool enableLodBias;
}
namespace dusk { namespace dusk {
void ImGuiMenuGame::ToggleFullscreen() { void ImGuiMenuGame::ToggleFullscreen() {
@@ -22,17 +40,475 @@ namespace dusk {
void ImGuiMenuGame::draw() { void ImGuiMenuGame::draw() {
if (ImGui::BeginMenu("Settings")) { if (ImGui::BeginMenu("Settings")) {
// TODO: Remove this once Controller Config exists in RmlUi drawAudioMenu();
drawCheatsMenu();
drawGameplayMenu();
drawGraphicsMenu();
drawInputMenu();
drawInterfaceMenu();
ImGui::Separator();
if (ImGui::MenuItem("Reset", hotkeys::DO_RESET)) {
JUTGamePad::C3ButtonReset::sResetSwitchPushing = true;
}
if (!IsMobile && ImGui::MenuItem("Exit")) {
dusk::IsRunning = false;
}
ImGui::EndMenu();
}
}
void ImGuiMenuGame::drawGraphicsMenu() {
if (ImGui::BeginMenu("Graphics")) {
ImGui::SeparatorText("Display");
if (!IsMobile) {
if (ImGui::MenuItem("Toggle Fullscreen", hotkeys::TOGGLE_FULLSCREEN)) {
ToggleFullscreen();
}
if (ImGui::Button("Restore Default Window Size")) {
getSettings().video.enableFullscreen.setValue(false);
VISetWindowFullscreen(false);
VISetWindowSize(FB_WIDTH * 2, FB_HEIGHT * 2);
VICenterWindow();
}
}
ImGui::Separator();
bool vsync = getSettings().video.enableVsync;
if (ImGui::Checkbox("Enable VSync", &vsync)) {
getSettings().video.enableVsync.setValue(vsync);
aurora_enable_vsync(vsync);
config::Save();
}
bool lockAspect = getSettings().video.lockAspectRatio;
if (ImGui::Checkbox("Force 4:3 Aspect Ratio", &lockAspect)) {
getSettings().video.lockAspectRatio.setValue(lockAspect);
if (lockAspect) {
AuroraSetViewportPolicy(AURORA_VIEWPORT_FIT);
} else {
AuroraSetViewportPolicy(AURORA_VIEWPORT_STRETCH);
}
config::Save();
}
ImGui::SeparatorText("Resolution");
u32 internalResolutionWidth = 0;
u32 internalResolutionHeight = 0;
AuroraGetRenderSize(&internalResolutionWidth, &internalResolutionHeight);
ImGui::TextDisabled("Current internal resolution: %ux%u", internalResolutionWidth,
internalResolutionHeight);
int scale = std::clamp(getSettings().game.internalResolutionScale.getValue(), 0,
kInternalResolutionScaleMax);
if (ImGui::SliderInt("Internal Resolution", &scale, 0, kInternalResolutionScaleMax,
scale == 0 ? "Auto" : "%dx"))
{
getSettings().game.internalResolutionScale.setValue(scale);
VISetFrameBufferScale(static_cast<float>(scale));
config::Save();
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Auto renders at the native window resolution.\n"
"Higher values scale the game's internal framebuffer.");
}
config::ImGuiSliderInt("Shadow Resolution", getSettings().game.shadowResolutionMultiplier, 1, 8, "x%d");
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Improves the shadow resolution, making them higher quality.");
}
ImGui::SeparatorText("Post-Processing");
constexpr const char* bloomModeNames[] = {"Off", "Classic", "Dusk"};
int bloomMode = static_cast<int>(getSettings().game.bloomMode.getValue());
if (ImGui::BeginCombo("Bloom", bloomModeNames[bloomMode])) {
for (int i = 0; i < IM_ARRAYSIZE(bloomModeNames); i++) {
const bool selected = bloomMode == i;
if (ImGui::Selectable(bloomModeNames[i], selected)) {
getSettings().game.bloomMode.setValue(static_cast<BloomMode>(i));
config::Save();
}
if (selected) {
ImGui::SetItemDefaultFocus();
}
}
ImGui::EndCombo();
}
bool bloomOff = bloomMode == static_cast<int>(BloomMode::Off);
if (bloomOff) ImGui::BeginDisabled();
float mult = getSettings().game.bloomMultiplier.getValue();
if (ImGui::SliderFloat("Bloom Brightness", &mult, 0.0f, 1.0f, "%.2f")) {
getSettings().game.bloomMultiplier.setValue(mult);
config::Save();
}
if (bloomOff) ImGui::EndDisabled();
ImGui::SeparatorText("Rendering");
config::ImGuiCheckbox("Unlock Framerate", getSettings().game.enableFrameInterpolation);
const bool frameInterpolationHovered = ImGui::IsItemHovered();
ImGui::SameLine();
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.72f, 0.2f, 1.0f));
ImGui::TextUnformatted("[EXPERIMENTAL]");
ImGui::PopStyleColor();
if (frameInterpolationHovered || ImGui::IsItemHovered()) {
ImGui::SetTooltip("Uses inter-frame interpolation to enable higher frame rates.\nVisual artifacts, animation glitches, or instability may occur.");
}
ImGui::Checkbox("Enable LOD Bias", &aurora::gx::enableLodBias);
config::ImGuiCheckbox("Enable Depth of Field", getSettings().game.enableDepthOfField);
config::ImGuiCheckbox("Enable Mini-Map Shadows", getSettings().game.enableMapBackground);
ImGui::EndMenu();
}
}
void ImGuiMenuGame::drawGameplayMenu() {
if (ImGui::BeginMenu("Gameplay")) {
ImGui::SeparatorText("General");
config::ImGuiCheckbox("Mirror Mode", getSettings().game.enableMirrorMode);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Mirrors the world horizontally, matching the Wii version of the game.");
}
config::ImGuiCheckbox("Disable Main HUD", getSettings().game.disableMainHUD);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Disables the main HUD of the game.\n"
"Useful for recording or a more immersive experience!");
}
config::ImGuiCheckbox("Restore Wii 1.0 Glitches", getSettings().game.restoreWiiGlitches);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Restores patched glitches from Wii USA 1.0,\n"
"the first released version.");
}
config::ImGuiCheckbox("Enable Rotating Link Doll", getSettings().game.enableLinkDollRotation);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Enables rotating Link in the collection menu with the C-Stick");
}
ImGui::SeparatorText("Difficulty");
ImGui::BeginDisabled(getSettings().game.speedrunMode);
config::ImGuiSliderInt("Damage Multiplier", getSettings().game.damageMultiplier, 1, 8, "x%d");
config::ImGuiCheckbox("Instant Death", getSettings().game.instantDeath);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Any hit will instantly kill you.");
}
config::ImGuiCheckbox("No Heart Drops", getSettings().game.noHeartDrops);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Hearts will never drop from enemies,\n"
"pots and various other places.");
}
ImGui::EndDisabled();
ImGui::SeparatorText("Quality of Life");
config::ImGuiCheckbox("Bigger Wallets", getSettings().game.biggerWallets);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Wallet sizes are like in the HD version. (500, 1000, 2000)");
}
config::ImGuiCheckbox("Disable Rupee Cutscenes", getSettings().game.disableRupeeCutscenes);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Rupees won't play cutscenes after you've collected them the first time.");
}
config::ImGuiCheckbox("Faster Climbing", getSettings().game.fastClimbing);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Quicker climbing on ladders and vines like the HD version.");
}
config::ImGuiCheckbox("Faster Tears of Light", getSettings().game.fastTears);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Tears of Light dropped by Shadow Insects pop out faster like the HD version.");
}
config::ImGuiCheckbox("Instant Saves", getSettings().game.instantSaves);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Skip the delay when writing to the Memory Card.");
}
config::ImGuiCheckbox("Hold B for Instant Text", getSettings().game.instantText);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Make text scroll immediately by holding B.");
}
config::ImGuiCheckbox("No Climbing Miss Animation", getSettings().game.noMissClimbing);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Prevents Link from playing a struggle animation\n"
"when grabbing ledges or climbing on vines.");
}
config::ImGuiCheckbox("No Rupee Returns", getSettings().game.noReturnRupees);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Always collect Rupees even if your Wallet is too full.");
}
config::ImGuiCheckbox("No Sword Recoil", getSettings().game.noSwordRecoil);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Link won't recoil when his sword hits walls.");
}
config::ImGuiCheckbox("No 2nd Fish for Cat", getSettings().game.no2ndFishForCat);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Only need to fish once for Sera's cat to return.");
}
config::ImGuiCheckbox("Skip TV Settings Screen", getSettings().game.hideTvSettingsScreen);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Skip the TV calibration screen shown when loading a save.");
}
config::ImGuiCheckbox("Skip Warning Screen", getSettings().game.skipWarningScreen);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Skip the warning screen shown when starting the game.");
}
config::ImGuiCheckbox("Sun's Song (R+X)", getSettings().game.sunsSong);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Allows Wolf Link to howl and change the time of day.");
}
config::ImGuiCheckbox("Quick Transform (R+Y)", getSettings().game.enableQuickTransform);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Transform instantly by pressing R and Y simultaneously.");
}
ImGui::SeparatorText("Speedrunning");
if (config::ImGuiCheckbox("Speedrun Mode", getSettings().game.speedrunMode)) {
resetForSpeedrunMode();
}
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Enables Speedrunning options, while restricting certain gameplay modifiers.");
}
ImGui::BeginDisabled(!getSettings().game.speedrunMode);
bool prevLiveSplit = getSettings().game.liveSplitEnabled;
config::ImGuiCheckbox("LiveSplit Connection", getSettings().game.liveSplitEnabled);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Connect to LiveSplit server on localhost:16834.");
}
ImGui::EndDisabled();
if ((bool)getSettings().game.liveSplitEnabled != prevLiveSplit) {
if (getSettings().game.liveSplitEnabled) {
dusk::speedrun::connectLiveSplit();
} else {
dusk::speedrun::disconnectLiveSplit();
DuskToast("LiveSplit disconnected", 3.f);
}
}
ImGui::EndMenu();
}
}
void ImGuiMenuGame::drawCheatsMenu() {
if (ImGui::BeginMenu("Cheats")) {
ImGui::BeginDisabled(getSettings().game.speedrunMode);
ImGui::SeparatorText("Resources");
config::ImGuiCheckbox("Infinite Hearts", getSettings().game.infiniteHearts);
config::ImGuiCheckbox("Infinite Arrows", getSettings().game.infiniteArrows);
config::ImGuiCheckbox("Infinite Bombs", getSettings().game.infiniteBombs);
config::ImGuiCheckbox("Infinite Oil", getSettings().game.infiniteOil);
config::ImGuiCheckbox("Infinite Oxygen", getSettings().game.infiniteOxygen);
config::ImGuiCheckbox("Infinite Rupees", getSettings().game.infiniteRupees);
config::ImGuiCheckbox("No Item Timer", getSettings().game.enableIndefiniteItemDrops);
ImGui::SetItemTooltip("Item drops such as Rupees, Hearts, etc. will never disappear after they drop.");
ImGui::SeparatorText("Abilities");
config::ImGuiCheckbox("Moon Jump (R+A)", getSettings().game.moonJump);
config::ImGuiCheckbox("Super Clawshot", getSettings().game.superClawshot);
config::ImGuiCheckbox("Always Greatspin", getSettings().game.alwaysGreatspin);
config::ImGuiCheckbox("Fast Iron Boots", getSettings().game.enableFastIronBoots);
config::ImGuiCheckbox("Can Transform Anywhere", getSettings().game.canTransformAnywhere);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Allows you to transform even if NPCs are looking.");
}
config::ImGuiCheckbox("Fast Spinner", getSettings().game.fastSpinner);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Speeds up Spinner movement when holding R.");
}
config::ImGuiCheckbox("Free Magic Armor", getSettings().game.freeMagicArmor);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Makes the magic armor work without rupees.");
}
ImGui::EndDisabled();
ImGui::EndMenu();
}
}
void ImGuiMenuGame::drawAudioMenu() {
if (ImGui::BeginMenu("Audio")) {
ImGui::SeparatorText("Volume");
ImGui::Text("Master Volume");
if (config::ImGuiSliderInt("##masterVolume", getSettings().audio.masterVolume, 0, 100)) {
dusk::audio::SetMasterVolume(getSettings().audio.masterVolume / 100.0f);
}
/*
// TODO: Implement additional settings
ImGui::Text("Main Music Volume");
ImGui::SliderFloat("##mainMusicVolume", &getSettings().audio.mainMusicVolume, 0, 100);
ImGui::Text("Sub Music Volume");
ImGui::SliderFloat("##subMusicVolume", &getSettings().audio.subMusicVolume, 0, 100);
ImGui::Text("Sound Effects Volume");
ImGui::SliderFloat("##soundEffectsVolume", &getSettings().audio.soundEffectsVolume, 0, 100);
ImGui::Text("Fanfare Volume");
ImGui::SliderFloat("##fanfareVolume", &getSettings().audio.fanfareVolume, 0, 100);
Z2AudioMgr* audioMgr = Z2AudioMgr::getInterface();
if (audioMgr != nullptr) {
}
*/
ImGui::SeparatorText("Effects");
if (config::ImGuiCheckbox("Enable Reverb", getSettings().audio.enableReverb)) {
dusk::audio::SetEnableReverb(getSettings().audio.enableReverb);
}
ImGui::SeparatorText("Tweaks");
config::ImGuiCheckbox("No Low HP Sound", getSettings().game.noLowHpSound);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Disable the beeping sound when having low health.");
}
config::ImGuiCheckbox("Non-Stop Midna's Lament", getSettings().game.midnasLamentNonStop);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Prevents enemy music while Midna's Lament is playing.");
}
ImGui::EndMenu();
}
}
void ImGuiMenuGame::drawInputMenu() {
if (ImGui::BeginMenu("Input")) {
ImGui::SeparatorText("Controller");
if (ImGui::Button("Configure Controller")){ if (ImGui::Button("Configure Controller")){
m_showControllerConfig = !m_showControllerConfig; m_showControllerConfig = !m_showControllerConfig;
} }
ImGui::SeparatorText("Camera");
config::ImGuiCheckbox("Free Camera", getSettings().game.freeCamera);
if (getSettings().game.freeCamera) {
config::ImGuiCheckbox("Invert Camera X Axis", getSettings().game.invertCameraXAxis);
config::ImGuiCheckbox("Invert Camera Y Axis", getSettings().game.invertCameraYAxis);
config::ImGuiSliderFloat("Free Camera Sensitivity", getSettings().game.freeCameraSensitivity, 0.5f, 2.0f, "%.1f");
} else {
config::ImGuiCheckbox("Invert Camera X Axis", getSettings().game.invertCameraXAxis);
}
ImGui::SeparatorText("Gyro");
config::ImGuiCheckbox("Gyro Aim", getSettings().game.enableGyroAim);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Enables the gyroscope on supported controllers\n"
"while in look mode (C-Up) and while aiming the\n"
"Slingshot, Gale Boomerang, Hero's Bow, Clawshot(s),\n"
"Ball and Chain, and Dominion Rod.");
}
config::ImGuiCheckbox("Gyro Rollgoal", getSettings().game.enableGyroRollgoal);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Enables the gyroscope on supported controllers to\n"
"tilt the Rollgoal table in Hena's Cabin.");
}
if (getSettings().game.enableGyroAim || getSettings().game.enableGyroRollgoal) {
config::ImGuiSliderFloat("Gyro Pitch Sensitivity", getSettings().game.gyroSensitivityY, 0.25f, 4.0f, "%.2f");
config::ImGuiSliderFloat("Gyro Yaw Sensitivity", getSettings().game.gyroSensitivityX, 0.25f, 4.0f, "%.2f");
if (getSettings().game.enableGyroRollgoal) {
config::ImGuiSliderFloat("Rollgoal Sensitivity", getSettings().game.gyroSensitivityRollgoal, 0.25f, 4.0f, "%.2f");
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Additional multiplier for scaling how strongly\n"
"the gyroscope affects the Rollgoal table.");
}
}
config::ImGuiSliderFloat("Gyro Deadband", getSettings().game.gyroDeadband, 0.0f, 0.5f, "%.3f");
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Angular rates below this magnitude are treated as zero,\n"
"reducing drift and jitter when the controller is still.");
}
config::ImGuiSliderFloat("Gyro Smoothing", getSettings().game.gyroSmoothing, 0.0f, 1.0f, "%.2f");
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Low values track raw gyro input more closely,\n"
"while higher values smooth out input over time.");
}
config::ImGuiCheckbox("Invert Gyro Pitch", getSettings().game.gyroInvertPitch);
config::ImGuiCheckbox("Invert Gyro Yaw", getSettings().game.gyroInvertYaw);
}
ImGui::SeparatorText("Tools");
ImGui::BeginDisabled(getSettings().game.speedrunMode);
config::ImGuiCheckbox("Turbo Key", getSettings().game.enableTurboKeybind);
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Hold TAB to increase game speed by up to 4x.");
}
ImGui::EndDisabled();
ImGui::Checkbox("Show Input Viewer", &m_showInputViewer); ImGui::Checkbox("Show Input Viewer", &m_showInputViewer);
ImGui::EndMenu(); ImGui::EndMenu();
} }
} }
void ImGuiMenuGame::drawInterfaceMenu() {
if (ImGui::BeginMenu("Interface")) {
config::ImGuiCheckbox("Achievement Notifications", getSettings().game.enableAchievementNotifications);
config::ImGuiCheckbox("Skip Pre-Launch UI", getSettings().backend.skipPreLaunchUI);
config::ImGuiCheckbox("Show Pipeline Compilation", getSettings().backend.showPipelineCompilation);
#if DUSK_ENABLE_SENTRY_NATIVE
config::ImGuiCheckbox("Enable Crash Reporting", getSettings().backend.enableCrashReporting);
#endif
if (!IsMobile) {
config::ImGuiCheckbox("Pause on Focus Lost", getSettings().game.pauseOnFocusLost);
}
ImGui::EndMenu();
}
}
static void drawVirtualStick(const char* id, const ImVec2& stick) { static void drawVirtualStick(const char* id, const ImVec2& stick) {
float scale = ImGuiScale(); float scale = ImGuiScale();
ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x + 45 * scale, ImGui::GetCursorPos().y + 10)); ImGui::SetCursorPos(ImVec2(ImGui::GetCursorPos().x + 45 * scale, ImGui::GetCursorPos().y + 10));
@@ -583,7 +1059,6 @@ namespace dusk {
getSettings().game.damageMultiplier.setValue(1); getSettings().game.damageMultiplier.setValue(1);
getSettings().game.instantDeath.setValue(false); getSettings().game.instantDeath.setValue(false);
getSettings().game.noHeartDrops.setValue(false); getSettings().game.noHeartDrops.setValue(false);
getSettings().game.hyperEnemies.setValue(false);
getSettings().game.infiniteHearts.setValue(false); getSettings().game.infiniteHearts.setValue(false);
getSettings().game.infiniteArrows.setValue(false); getSettings().game.infiniteArrows.setValue(false);
+7
View File
@@ -55,6 +55,13 @@ namespace dusk {
static void resetForSpeedrunMode(); static void resetForSpeedrunMode();
private: private:
void drawAudioMenu();
void drawInputMenu();
void drawGraphicsMenu();
void drawGameplayMenu();
void drawCheatsMenu();
void drawInterfaceMenu();
struct { struct {
int m_selectedPort = 0; int m_selectedPort = 0;
bool m_isReading = false; bool m_isReading = false;
+1 -5
View File
@@ -41,10 +41,6 @@ static void OpenDataFolder() {
#define DUSK_CAN_OPEN_DATA_FOLDER 0 #define DUSK_CAN_OPEN_DATA_FOLDER 0
#endif #endif
namespace aurora::gx {
extern bool enableLodBias;
}
namespace dusk { namespace dusk {
ImGuiMenuTools::ImGuiMenuTools() {} ImGuiMenuTools::ImGuiMenuTools() {}
@@ -95,7 +91,6 @@ namespace dusk {
getSettings().game.disableWaterRefraction.setValue(disableWaterRefraction); getSettings().game.disableWaterRefraction.setValue(disableWaterRefraction);
config::Save(); config::Save();
} }
ImGui::Checkbox("Enable LOD Bias", &aurora::gx::enableLodBias);
ImGui::EndMenu(); ImGui::EndMenu();
} }
@@ -124,6 +119,7 @@ namespace dusk {
ImGui::MenuItem("Audio Debug", hotkeys::SHOW_AUDIO_DEBUG, &m_showAudioDebug); ImGui::MenuItem("Audio Debug", hotkeys::SHOW_AUDIO_DEBUG, &m_showAudioDebug);
ImGui::MenuItem("Bloom", nullptr, &m_showBloomWindow); ImGui::MenuItem("Bloom", nullptr, &m_showBloomWindow);
ImGui::MenuItem("Stub Log", nullptr, &m_showStubLog); ImGui::MenuItem("Stub Log", nullptr, &m_showStubLog);
ImGui::MenuItem("Actor Spawner", nullptr, &m_showActorSpawner);
if (!dusk::IsGameLaunched) { if (!dusk::IsGameLaunched) {
ImGui::EndDisabled(); ImGui::EndDisabled();
+3
View File
@@ -29,6 +29,7 @@ namespace dusk {
void ShowStateShare(); void ShowStateShare();
void ShowAchievements(); void ShowAchievements();
void notifyAchievement(std::string name); void notifyAchievement(std::string name);
void ShowActorSpawner();
private: private:
bool m_showDebugOverlay = false; bool m_showDebugOverlay = false;
@@ -71,6 +72,8 @@ namespace dusk {
bool m_showAchievements = false; bool m_showAchievements = false;
ImGuiAchievements m_achievementsWindow; ImGuiAchievements m_achievementsWindow;
bool m_showActorSpawner = false;
}; };
} }
+64 -325
View File
@@ -13,7 +13,6 @@
#include "d/actor/d_a_player.h" #include "d/actor/d_a_player.h"
#include <map> #include <map>
#include <bit>
namespace dusk { namespace dusk {
enum ItemType { enum ItemType {
@@ -1297,32 +1296,7 @@ namespace dusk {
} }
} }
static void genCommonAreaFlags(dSv_memBit_c& membit) { void genMembitFlags(const char* id, dSv_memBit_c& membit) {
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f);
genDungeonItemCheckbox(membit, "Got Map", dSv_memBit_c::MAP);
ImGui::SameLine(230.0f);
genDungeonItemCheckbox(membit, "Got Compass", dSv_memBit_c::COMPASS);
genDungeonItemCheckbox(membit, "Got Boss Key", dSv_memBit_c::BOSS_KEY);
ImGui::SameLine(230.0f);
genDungeonItemCheckbox(membit, "Saw Boss Demo", dSv_memBit_c::STAGE_BOSS_DEMO);
genDungeonItemCheckbox(membit, "Got Heart Container", dSv_memBit_c::STAGE_LIFE);
ImGui::SameLine(230.0f);
genDungeonItemCheckbox(membit, "Defeated Boss", dSv_memBit_c::STAGE_BOSS_ENEMY);
genDungeonItemCheckbox(membit, "Defeated Miniboss", dSv_memBit_c::STAGE_BOSS_ENEMY_2);
ImGui::SameLine(230.0f);
genDungeonItemCheckbox(membit, "Got Ooccoo", dSv_memBit_c::OOCCOO_NOTE);
int keyTemp = membit.getKeyNum();
if (ImGui::SliderInt("Keys", &keyTemp, 0, 5)) {
membit.setKeyNum(keyTemp);
}
}
static void genMembitFlags(const char* id, dSv_memBit_c& membit) {
ImGuiBeginGroupPanel("Chest", { 100, 100 }); ImGuiBeginGroupPanel("Chest", { 100, 100 });
for (int j = 0; j < 2; j++) { for (int j = 0; j < 2; j++) {
drawFlagList(fmt::format("##_tbox{}", j).c_str(), membit.mTbox[j]); drawFlagList(fmt::format("##_tbox{}", j).c_str(), membit.mTbox[j]);
@@ -1348,10 +1322,29 @@ namespace dusk {
drawFlagList(fmt::format("##_item{}", j).c_str(), membit.mItem[j]); drawFlagList(fmt::format("##_item{}", j).c_str(), membit.mItem[j]);
} }
ImGuiEndGroupPanel(); ImGuiEndGroupPanel();
ImVec2 post_item_custor = ImGui::GetCursorPos();
ImGui::SetCursorPos({post_item_custor.x, post_switch_cursor.y}); ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f);
// genCommonAreaFlags(membit);
genDungeonItemCheckbox(membit, "Got Map", dSv_memBit_c::MAP);
ImGui::SameLine(230.0f);
genDungeonItemCheckbox(membit, "Got Compass", dSv_memBit_c::COMPASS);
genDungeonItemCheckbox(membit, "Got Boss Key", dSv_memBit_c::BOSS_KEY);
ImGui::SameLine(230.0f);
genDungeonItemCheckbox(membit, "Saw Boss Demo", dSv_memBit_c::STAGE_BOSS_DEMO);
genDungeonItemCheckbox(membit, "Got Heart Container", dSv_memBit_c::STAGE_LIFE);
ImGui::SameLine(230.0f);
genDungeonItemCheckbox(membit, "Defeated Boss", dSv_memBit_c::STAGE_BOSS_ENEMY);
genDungeonItemCheckbox(membit, "Defeated Miniboss", dSv_memBit_c::STAGE_BOSS_ENEMY_2);
ImGui::SameLine(230.0f);
genDungeonItemCheckbox(membit, "Got Ooccoo", dSv_memBit_c::OOCCOO_NOTE);
int keyTemp = membit.getKeyNum();
if (ImGui::SliderInt("Keys", &keyTemp, 0, 5)) {
membit.setKeyNum(keyTemp);
}
} }
template <typename T> template <typename T>
@@ -1399,254 +1392,10 @@ namespace dusk {
} }
} }
void ImGuiSaveEditor::drawFlagsTab() {
static void genAreaFlagTable(uint8_t areaIndex, dSv_memBit_c& membit) { if (ImGui::TreeNode("Current Region Flags")) {
constexpr auto makeMask = [](uint8_t size) -> uint16_t { return (1 << size) - 1; };
constexpr auto getByteIndexFromFlag = [](uint16_t f) -> uint8_t { return f >> 8; };
constexpr auto getBitMaskFromFlag = [](uint16_t f) -> uint8_t { return f & 0xff; };
constexpr auto getValueSize = [getBitMaskFromFlag](uint16_t f) -> uint8_t {
return std::popcount(getBitMaskFromFlag(f));
};
constexpr auto makeEventFlag = [](uint8_t byteIndex, uint8_t bitIndices) -> uint16_t {
return (byteIndex << 8) | bitIndices;
};
const auto eventFlagToAreaFlag = [&](uint16_t areaFlag) -> int {
auto byteInd = getByteIndexFromFlag(areaFlag);
constexpr size_t areaIndexSize = 5;
// if we're looking at 0x580, that would be byte 5, and check if 0x80 is set on that byte
// the event flags are structured differently than area flags
// B is byte index, b is the flag mask to check
// event flags are BBBBBBBB bbbbbbbb
// for area flags, they check bitIndex, not mask, i is index
// also area uses u32 index, not byte index
// area flags are BBBiiiii
// so we need to convert from bit mask to index
// also our byte index has to become a u32 index
// dividing byte index by sizeof(u32) gets us the u32 index
// but in big endian, the first byte is the highest order byte of the u32
// so we skip 24 bytes for the first byte, 16 for the second, etc
// essentially (3 - (x % 4)), reversing the modulus, 0=3, 1=2
auto bitsToSkip = 8 * ((sizeof(u32) - 1) - (byteInd % sizeof(u32)));
return ((byteInd / sizeof(u32)) << areaIndexSize) | ((std::countr_zero(areaFlag) + bitsToSkip) & makeMask(areaIndexSize));
};
constexpr uint8_t validTbox = sizeof(membit.mTbox);
constexpr uint8_t validSwitch = validTbox + sizeof(membit.mSwitch);
constexpr uint8_t validItem = validSwitch + sizeof(membit.mItem);
constexpr uint16_t tboxConvert = 0;
constexpr uint16_t switchConvert = sizeof(membit.mTbox) << 8;
constexpr uint16_t itemConvert = switchConvert + (sizeof(membit.mItem) << 8);
const auto LoadFlag = [&](uint16_t flag) -> bool {
const auto byteIndex = getByteIndexFromFlag(flag);
if (byteIndex < validTbox) {
return membit.isTbox(eventFlagToAreaFlag(flag - tboxConvert));
} else if (byteIndex < validSwitch) {
return membit.isSwitch(eventFlagToAreaFlag(flag - switchConvert));
} else if (byteIndex < validItem) {
return membit.isItem(eventFlagToAreaFlag(flag - itemConvert));
}
return false;
};
const auto SetFlag = [&](uint16_t flag, bool set) -> void {
const auto byteIndex = getByteIndexFromFlag(flag);
if (set) {
if (byteIndex < validTbox) {
membit.onTbox(eventFlagToAreaFlag(flag - tboxConvert));
} else if (byteIndex < validSwitch) {
membit.onSwitch(eventFlagToAreaFlag(flag - switchConvert));
} else if (byteIndex < validItem) {
membit.onItem(eventFlagToAreaFlag(flag - itemConvert));
}
} else {
if (byteIndex < validTbox) {
membit.offTbox(eventFlagToAreaFlag(flag - tboxConvert));
} else if (byteIndex < validSwitch) {
membit.offSwitch(eventFlagToAreaFlag(flag - switchConvert));
} else if (byteIndex < validItem) {
membit.offItem(eventFlagToAreaFlag(flag - itemConvert));
}
}
};
const auto LoadMultiByteFlag = [&](uint16_t flag) -> uint8_t {
const auto bitInds = getBitMaskFromFlag(flag);
const auto byteIndex = getByteIndexFromFlag(flag);
const uint16_t startingMask = std::bit_floor(bitInds);
uint8_t val = 0;
for (uint16_t bitIndexMask = startingMask; (bitInds & bitIndexMask) != 0;
bitIndexMask >>= 1)
{
val <<= 1;
if (LoadFlag(makeEventFlag(byteIndex, bitInds & bitIndexMask))) {
val |= 1;
}
}
return val;
};
const auto SetMultiByteFlag = [&](uint16_t flag, uint8_t val) -> void {
const auto bitInds = getBitMaskFromFlag(flag);
const auto byteIndex = getByteIndexFromFlag(flag);
const uint16_t startingMask = std::bit_floor(bitInds);
uint16_t valueMask = 1 << (getValueSize(flag) - 1);
for (uint16_t bitIndexMask = startingMask; (bitInds & bitIndexMask) != 0;
bitIndexMask >>= 1, valueMask >>= 1)
{
SetFlag(makeEventFlag(byteIndex, bitInds & bitIndexMask), (val & valueMask) != 0);
}
};
const auto LoadSpreadMultiByte = [&](uint16_t high, uint16_t low) -> uint8_t {
if (low == AREA_FLAG_NONE)
return LoadMultiByteFlag(high);
return (LoadMultiByteFlag(high) << getValueSize(low)) | LoadMultiByteFlag(low);
};
const auto SetSpreadMultiByte = [&](uint16_t high, uint16_t low, uint8_t value) -> void {
if (low == AREA_FLAG_NONE)
return SetMultiByteFlag(high, value);
const auto lowerSize = getValueSize(low);
SetMultiByteFlag(high, value >> lowerSize);
SetMultiByteFlag(low, value & makeMask(lowerSize));
};
auto iter = imguiAreaFlagLookup.find(areaIndex);
if (iter == imguiAreaFlagLookup.end()) return;
auto& areaFlags = iter->second;
static ImGuiTextFilter filter;
filter.Draw(); // Search bar
ImVec2 flagTableSize = {700, 400};
if (ImGui::BeginTable("Area Flags", 3,
ImGuiTableFlags_ScrollY | ImGuiTableFlags_ScrollX |
ImGuiTableFlags_Sortable,
flagTableSize))
{
ImGui::TableSetupScrollFreeze(0, 1);
constexpr int COLUMN_FLAG = 0, COLUMN_BIT = 1, COLUMN_DESC = 2;
ImGui::TableSetupColumn("Flag");
ImGui::TableSetupColumn("Byte:Bit");
ImGui::TableSetupColumn("Description");
ImGui::TableHeadersRow();
// if we're sorting by whether the flag is set or not,
// we want to re-sort whenever a flag updates, which means every frame cuz we don't
// know when it changes. otherwise only re-sort when the sort is dirty
if (auto* sort = ImGui::TableGetSortSpecs();
sort != nullptr && sort->SpecsCount > 0 &&
(sort->SpecsDirty || sort->Specs[0].ColumnIndex == COLUMN_FLAG))
{
const auto column = sort->Specs[0].ColumnIndex;
const auto direction = sort->Specs[0].SortDirection;
// if we're sorting by flags, do special sort, regular sort is bad for sorting
// bools it can swap values that are the same, and that causes constant
// reordering
if (column == COLUMN_FLAG) {
if (direction == ImGuiSortDirection_Ascending) {
sortByFlags(std::begin(areaFlags.bitFlags), std::end(areaFlags.bitFlags),
LoadFlag);
} else {
sortByFlags(std::rbegin(areaFlags.bitFlags), std::rend(areaFlags.bitFlags),
LoadFlag);
}
} else {
const auto cmp = [column](const EventAreaFlags& l,
const EventAreaFlags& r) -> bool {
switch (column) {
case COLUMN_DESC:
return l.description < r.description;
case COLUMN_BIT:
return l.flagID < r.flagID;
}
return false;
};
if (direction == ImGuiSortDirection_Ascending) {
std::sort(std::begin(areaFlags.bitFlags), std::end(areaFlags.bitFlags),
cmp);
} else {
std::sort(std::rbegin(areaFlags.bitFlags), std::rend(areaFlags.bitFlags),
cmp);
}
}
sort->SpecsDirty = false;
}
for (const auto& e : areaFlags.bitFlags) {
std::string formattedBitLocation =
fmt::format("{0:02X}:{1:02X}", e.byteIndex, e.bitIndex);
if (!filter.PassFilter(e.description.c_str()) &&
!filter.PassFilter(formattedBitLocation.c_str()))
{
continue;
}
ImGui::TableNextRow();
ImGui::TableNextColumn();
bool flag = LoadFlag(e.flagID);
if (ImGui::Checkbox(fmt::format("##_unused_area_flag_{}", e.flagID).c_str(), &flag)) {
SetFlag(e.flagID, flag);
}
ImGui::TableNextColumn();
ImGui::TextUnformatted(formattedBitLocation.c_str());
ImGui::TableNextColumn();
ImGui::TextUnformatted(e.description.c_str());
}
ImGui::EndTable();
}
for (const auto& multiByteFlag : areaFlags.multibyteFlags) {
auto flagValue = LoadSpreadMultiByte(multiByteFlag.highOrderflag, multiByteFlag.lowOrderflag);
const char* currentVal = "UNKNOWN";
auto enumValIter = multiByteFlag.enumValues.find(flagValue);
if (enumValIter != multiByteFlag.enumValues.end()) {
currentVal = enumValIter->second;
}
if (ImGui::BeginCombo(multiByteFlag.name, currentVal)) {
for (const auto& [val, name] : multiByteFlag.enumValues) {
if (ImGui::Selectable(name)) {
SetSpreadMultiByte(multiByteFlag.highOrderflag, multiByteFlag.lowOrderflag, val);
}
}
ImGui::EndCombo();
}
}
genCommonAreaFlags(membit);
}
static void drawCurrentRegionFlags()
{
dSv_memBit_c& membit = g_dComIfG_gameInfo.info.mMemory.mBit; dSv_memBit_c& membit = g_dComIfG_gameInfo.info.mMemory.mBit;
auto* stageData = dComIfGp_getStageStagInfo();
if (!stageData)
return;
uint8_t stageIndex = dStage_stagInfo_GetSaveTbl(stageData);
genAreaFlagTable(stageIndex, membit);
if (ImGui::TreeNode("Flag Matrix")) {
genMembitFlags("##TempSceneFlags", membit); genMembitFlags("##TempSceneFlags", membit);
ImGui::TreePop();
}
stage_stag_info_class* pstag = dComIfGp_getStageStagInfo(); stage_stag_info_class* pstag = dComIfGp_getStageStagInfo();
if (pstag != nullptr) { if (pstag != nullptr) {
@@ -1661,64 +1410,56 @@ namespace dusk {
dComIfGs_getSave(stageNo); dComIfGs_getSave(stageNo);
} }
} }
}
void ImGuiSaveEditor::drawFlagsTab() {
if (ImGui::TreeNode("Current Region Flags")) {
drawCurrentRegionFlags();
ImGui::TreePop(); ImGui::TreePop();
} }
if (ImGui::TreeNode("Region Saved Flags")) { if (ImGui::TreeNode("Region Saved Flags")) {
static const std::map<uint8_t, const char*> regionNames = { static std::array<const char*, 27> regionNames = {
{ 0x00, "Ordon" }, "Ordon",
{ 0x01, "Hyrule Sewers" }, "Hyrule Sewers",
{ 0x02, "Faron" }, "Faron",
{ 0x03, "Eldin" }, "Eldin",
{ 0x04, "Lanayru" }, "Lanayru",
{ 0x06, "Hyrule Field" }, "Reserved",
{ 0x07, "Sacred Grove" }, "Hyrule Field",
{ 0x08, "Snowpeak" }, "Sacred Grove",
{ 0x09, "Castle Town" }, "Snowpeak",
{ 0x0A, "Gerudo Desert" }, "Castle Town",
{ 0x0B, "Fishing Pond" }, "Gerudo Desert",
{ 0x10, "Forest Temple" }, "Fishing Pond",
{ 0x11, "Goron Mines" }, "Reserved",
{ 0x12, "Lakebed Temple" }, "Reserved",
{ 0x13, "Arbiter's Grounds" }, "Reserved",
{ 0x14, "Snowpeak Ruins" }, "Reserved",
{ 0x15, "Temple of Time" }, "Forest Temple",
{ 0x16, "City in the Sky" }, "Goron Mines",
{ 0x17, "Palace of Twilight" }, "Lakebed Temple",
{ 0x18, "Hyrule Castle" }, "Arbiter's Grounds",
{ 0x19, "Caves" }, "Snowpeak Ruins",
{ 0x1A, "Lake Hylia Long Cave"}, "Temple of Time",
{ 0x1B, "Grottos" } "City in the Sky",
"Palace of Twilight",
"Hyrule Castle",
"Caves",
"Grottos",
}; };
if (m_selectedRegion.name == nullptr) if (ImGui::BeginCombo("Region", regionNames[m_selectedRegion])) {
{ for (int i = 0; i < regionNames.size(); i++) {
const auto& firstRegion = *regionNames.find(0); if (strcmp(regionNames[i], "Reserved") == 0) continue;
m_selectedRegion = { firstRegion.first, firstRegion.second };
if (ImGui::Selectable(regionNames[i])) {
m_selectedRegion = i;
}
} }
if (ImGui::BeginCombo("Region", m_selectedRegion.name)) {
for (const auto& [id, name] : regionNames) {
if (ImGui::Selectable(name)) {
m_selectedRegion = {id, name};
}
}
ImGui::EndCombo(); ImGui::EndCombo();
} }
dSv_memBit_c& membit = dComIfGs_getSaveData()->mSave[m_selectedRegion.id].mBit; dSv_memBit_c* membit = &dComIfGs_getSaveData()->mSave[m_selectedRegion].mBit;
if (membit != nullptr) {
genAreaFlagTable(m_selectedRegion.id, membit); genMembitFlags("##SaveSceneFlags", *membit);
if (ImGui::TreeNode("Flag Matrix")) {
genMembitFlags("##SaveSceneFlags", membit);
ImGui::TreePop();
} }
ImGui::TreePop(); ImGui::TreePop();
@@ -1789,9 +1530,7 @@ namespace dusk {
} }
for (const auto& e : duskImguiEventFlags) { for (const auto& e : duskImguiEventFlags) {
if (!filter.PassFilter(e.location.c_str()) && if (!filter.PassFilter((e.location + "\n" + e.description + "\n" + e.flagName).c_str()))
!filter.PassFilter(e.description.c_str()) &&
!filter.PassFilter(e.flagName.c_str()))
{ {
continue; continue;
} }
+1 -4
View File
@@ -21,10 +21,7 @@ namespace dusk {
void drawConfigTab(); void drawConfigTab();
private: private:
struct { int m_selectedRegion = 0;
uint8_t id;
const char* name;
} m_selectedRegion = {0, nullptr};
}; };
} }
-4
View File
@@ -101,10 +101,6 @@ ValidationError validate(const char* path) {
NodHandleWrapper disc; NodHandleWrapper disc;
const auto sdlStream = SDL_IOFromFile(path, "rb"); const auto sdlStream = SDL_IOFromFile(path, "rb");
if (sdlStream == nullptr) {
return ValidationError::IOError;
}
const NodDiscStream nod_stream { const NodDiscStream nod_stream {
.user_data = sdlStream, .user_data = sdlStream,
.read_at = StreamReadAt, .read_at = StreamReadAt,
+21 -48
View File
@@ -1,6 +1,5 @@
#include "dusk/logging.h" #include "dusk/logging.h"
#include <array> #include <array>
#include <atomic>
#include <chrono> #include <chrono>
#include <cstdio> #include <cstdio>
#include <cstdlib> #include <cstdlib>
@@ -33,33 +32,9 @@ static constexpr std::string_view StubFragments[] = {
}; };
namespace { namespace {
// On macOS, std::mutex becomes poisoned when its dtor is run. std::mutex g_logMutex;
// We use this to check if the LogState is destroyed before attempting to acquire it. FILE* g_logFile = nullptr;
std::atomic g_logStateAlive(true); std::string g_logFilePath;
struct LogState {
std::mutex mutex;
FILE* file = nullptr;
std::string filePath;
~LogState() {
CloseFile();
g_logStateAlive.store(false, std::memory_order_release);
}
void CloseFile() {
if (!g_logStateAlive.load(std::memory_order_acquire)) {
return;
}
std::lock_guard lock(mutex);
if (file != nullptr) {
std::fflush(file);
std::fclose(file);
file = nullptr;
}
}
};
LogState g_logState;
const char* LogLevelString(AuroraLogLevel level) { const char* LogLevelString(AuroraLogLevel level) {
switch (level) { switch (level) {
@@ -177,10 +152,10 @@ void aurora_log_callback(AuroraLogLevel level, const char* module, const char* m
FILE* out = LogStreamForLevel(level); FILE* out = LogStreamForLevel(level);
WriteLogLine(out, levelStr, module, message, len); WriteLogLine(out, levelStr, module, message, len);
if (g_logStateAlive.load(std::memory_order_acquire)) { {
std::lock_guard lock(g_logState.mutex); std::lock_guard lock(g_logMutex);
if (g_logState.file != nullptr) { if (g_logFile != nullptr) {
WriteLogLine(g_logState.file, levelStr, module, message, len); WriteLogLine(g_logFile, levelStr, module, message, len);
} }
} }
@@ -194,11 +169,8 @@ void aurora_log_callback(AuroraLogLevel level, const char* module, const char* m
aurora::Module DuskLog("dusk"); aurora::Module DuskLog("dusk");
void dusk::InitializeFileLogging(const std::filesystem::path& configDir, AuroraLogLevel logLevel) { void dusk::InitializeFileLogging(const std::filesystem::path& configDir, AuroraLogLevel logLevel) {
if (!g_logStateAlive.load(std::memory_order_acquire)) { std::lock_guard lock(g_logMutex);
return; if (g_logFile != nullptr || configDir.empty()) {
}
std::lock_guard lock(g_logState.mutex);
if (g_logState.file != nullptr || configDir.empty()) {
return; return;
} }
@@ -212,30 +184,31 @@ void dusk::InitializeFileLogging(const std::filesystem::path& configDir, AuroraL
} }
const std::filesystem::path logPath = logsDir / MakeTimestampedLogName(); const std::filesystem::path logPath = logsDir / MakeTimestampedLogName();
g_logState.file = std::fopen(logPath.string().c_str(), "wb"); g_logFile = std::fopen(logPath.string().c_str(), "wb");
if (g_logState.file == nullptr) { if (g_logFile == nullptr) {
std::fprintf(stderr, "[WARNING | dusk] Failed to open log file '%s'\n", std::fprintf(stderr, "[WARNING | dusk] Failed to open log file '%s'\n",
logPath.string().c_str()); logPath.string().c_str());
return; return;
} }
g_logState.filePath = logPath.string(); g_logFilePath = logPath.string();
aurora::g_config.logCallback = &aurora_log_callback; aurora::g_config.logCallback = &aurora_log_callback;
aurora::g_config.logLevel = logLevel; aurora::g_config.logLevel = logLevel;
WriteLogLine(g_logState.file, "INFO", "dusk", "File logging initialized", 24); WriteLogLine(g_logFile, "INFO", "dusk", "File logging initialized", 24);
} }
void dusk::ShutdownFileLogging() { void dusk::ShutdownFileLogging() {
if (!g_logStateAlive.load(std::memory_order_acquire)) { std::lock_guard lock(g_logMutex);
if (g_logFile == nullptr) {
return; return;
} }
g_logState.CloseFile();
std::fflush(g_logFile);
std::fclose(g_logFile);
g_logFile = nullptr;
} }
const char* dusk::GetLogFilePath() { const char* dusk::GetLogFilePath() {
if (!g_logStateAlive.load(std::memory_order_acquire)) { std::lock_guard lock(g_logMutex);
return nullptr; return g_logFilePath.empty() ? nullptr : g_logFilePath.c_str();
}
std::lock_guard lock(g_logState.mutex);
return g_logState.filePath.empty() ? nullptr : g_logState.filePath.c_str();
} }
+2 -8
View File
@@ -17,7 +17,6 @@ UserSettings g_userSettings = {
.soundEffectsVolume {"audio.soundEffectsVolume", 100}, .soundEffectsVolume {"audio.soundEffectsVolume", 100},
.fanfareVolume {"audio.fanfareVolume", 100}, .fanfareVolume {"audio.fanfareVolume", 100},
.enableReverb {"audio.enableReverb", true}, .enableReverb {"audio.enableReverb", true},
.enableHrtf {"audio.enableHrtf", false},
}, },
.game = { .game = {
@@ -32,8 +31,7 @@ UserSettings g_userSettings = {
.disableRupeeCutscenes {"game.disableRupeeCutscenes", false}, .disableRupeeCutscenes {"game.disableRupeeCutscenes", false},
.noSwordRecoil {"game.noSwordRecoil", false}, .noSwordRecoil {"game.noSwordRecoil", false},
.damageMultiplier {"game.damageMultiplier", 1}, .damageMultiplier {"game.damageMultiplier", 1},
.hyperEnemies {"game.hyperEnemies", false}, .noHeartDrops{"game.noHeartDrops", false},
.noHeartDrops {"game.noHeartDrops", false},
.instantDeath {"game.instantDeath", false}, .instantDeath {"game.instantDeath", false},
.fastClimbing {"game.fastClimbing", false}, .fastClimbing {"game.fastClimbing", false},
.noMissClimbing {"game.noMissClimbing", false}, .noMissClimbing {"game.noMissClimbing", false},
@@ -42,7 +40,6 @@ UserSettings g_userSettings = {
.instantSaves {"game.instantSaves", false}, .instantSaves {"game.instantSaves", false},
.instantText {"game.instantText", false}, .instantText {"game.instantText", false},
.sunsSong {"game.sunsSong", false}, .sunsSong {"game.sunsSong", false},
.autoSave {"game.autoSave", false},
// Preferences // Preferences
.enableMirrorMode {"game.enableMirrorMode", false}, .enableMirrorMode {"game.enableMirrorMode", false},
@@ -55,7 +52,7 @@ UserSettings g_userSettings = {
.bloomMode {"game.bloomMode", BloomMode::Classic}, .bloomMode {"game.bloomMode", BloomMode::Classic},
.bloomMultiplier {"game.bloomMultiplier", 1.0f}, .bloomMultiplier {"game.bloomMultiplier", 1.0f},
.disableWaterRefraction {"game.disableWaterRefraction", false}, .disableWaterRefraction {"game.disableWaterRefraction", false},
.enableFrameInterpolation {"game.enableFrameInterpolation", false}, .enableFrameInterpolation = {"game.enableFrameInterpolation", false},
.internalResolutionScale {"game.internalResolutionScale", 0}, .internalResolutionScale {"game.internalResolutionScale", 0},
.shadowResolutionMultiplier {"game.shadowResolutionMultiplier", 1}, .shadowResolutionMultiplier {"game.shadowResolutionMultiplier", 1},
.enableDepthOfField {"game.enableDepthOfField", true}, .enableDepthOfField {"game.enableDepthOfField", true},
@@ -136,7 +133,6 @@ void registerSettings() {
Register(g_userSettings.audio.soundEffectsVolume); Register(g_userSettings.audio.soundEffectsVolume);
Register(g_userSettings.audio.fanfareVolume); Register(g_userSettings.audio.fanfareVolume);
Register(g_userSettings.audio.enableReverb); Register(g_userSettings.audio.enableReverb);
Register(g_userSettings.audio.enableHrtf);
// Game // Game
Register(g_userSettings.game.language); Register(g_userSettings.game.language);
@@ -148,7 +144,6 @@ void registerSettings() {
Register(g_userSettings.game.disableRupeeCutscenes); Register(g_userSettings.game.disableRupeeCutscenes);
Register(g_userSettings.game.noSwordRecoil); Register(g_userSettings.game.noSwordRecoil);
Register(g_userSettings.game.damageMultiplier); Register(g_userSettings.game.damageMultiplier);
Register(g_userSettings.game.hyperEnemies);
Register(g_userSettings.game.noHeartDrops); Register(g_userSettings.game.noHeartDrops);
Register(g_userSettings.game.instantDeath); Register(g_userSettings.game.instantDeath);
Register(g_userSettings.game.fastClimbing); Register(g_userSettings.game.fastClimbing);
@@ -157,7 +152,6 @@ void registerSettings() {
Register(g_userSettings.game.instantSaves); Register(g_userSettings.game.instantSaves);
Register(g_userSettings.game.instantText); Register(g_userSettings.game.instantText);
Register(g_userSettings.game.sunsSong); Register(g_userSettings.game.sunsSong);
Register(g_userSettings.game.autoSave);
Register(g_userSettings.game.enableMirrorMode); Register(g_userSettings.game.enableMirrorMode);
Register(g_userSettings.game.invertCameraXAxis); Register(g_userSettings.game.invertCameraXAxis);
Register(g_userSettings.game.invertCameraYAxis); Register(g_userSettings.game.invertCameraYAxis);
-29
View File
@@ -1,29 +0,0 @@
#include "bool_button.hpp"
namespace dusk::ui {
BoolButton::BoolButton(Rml::Element* parent, Props props)
: BaseControlledSelectButton(parent, {std::move(props.key)}),
mGetValue(std::move(props.getValue)), mSetValue(std::move(props.setValue)),
mIsDisabled(std::move(props.isDisabled)) {}
bool BoolButton::disabled() const {
if (mIsDisabled) {
return mIsDisabled();
}
return BaseControlledSelectButton::disabled();
}
Rml::String BoolButton::format_value() {
return mGetValue() ? "On" : "Off";
}
bool BoolButton::handle_nav_command(NavCommand cmd) {
if (cmd == NavCommand::Confirm || cmd == NavCommand::Left || cmd == NavCommand::Right) {
mSetValue(!mGetValue());
return true;
}
return false;
}
} // namespace dusk::ui
-29
View File
@@ -1,29 +0,0 @@
#pragma once
#include "select_button.hpp"
namespace dusk::ui {
class BoolButton : public BaseControlledSelectButton {
public:
struct Props {
Rml::String key;
std::function<bool()> getValue;
std::function<void(bool)> setValue;
std::function<bool()> isDisabled;
};
BoolButton(Rml::Element* parent, Props props);
bool disabled() const override;
protected:
Rml::String format_value() override;
bool handle_nav_command(NavCommand cmd) override;
private:
std::function<int()> mGetValue;
std::function<void(int)> mSetValue;
std::function<bool()> mIsDisabled;
};
} // namespace dusk::ui
-64
View File
@@ -1,64 +0,0 @@
#include "button.hpp"
#include "ui.hpp"
#include <utility>
namespace dusk::ui {
namespace {
Rml::Element* createRoot(Rml::Element* parent, const Rml::String& tagName) {
auto* doc = parent->GetOwnerDocument();
auto elem = doc->CreateElement(tagName);
return parent->AppendChild(std::move(elem));
}
} // namespace
Button::Button(Rml::Element* parent, Props props, const Rml::String& tagName)
: FluentComponent(createRoot(parent, tagName)) {
update_props(std::move(props));
}
void Button::set_text(const Rml::String& text) {
if (mProps.text != text) {
mRoot->SetInnerRML(escape(text));
mProps.text = text;
}
}
Button& Button::on_pressed(ButtonCallback callback) {
if (!callback) {
return *this;
}
// TODO: convert this to a FluentComponent method?
on_nav_command([callback = std::move(callback)](Rml::Event&, NavCommand cmd) {
if (cmd == NavCommand::Confirm) {
callback();
return true;
}
return false;
});
return *this;
}
void Button::update_props(Props props) {
set_text(props.text);
mProps = std::move(props);
}
void ControlledButton::update() {
if (mIsSelected) {
set_selected(mIsSelected());
}
Button::update();
}
bool ControlledButton::selected() const {
if (mIsSelected) {
return mIsSelected();
}
return Button::selected();
}
} // namespace dusk::ui
-48
View File
@@ -1,48 +0,0 @@
#pragma once
#include "component.hpp"
namespace dusk::ui {
using ButtonCallback = std::function<void()>;
class Button : public FluentComponent<Button> {
public:
struct Props {
Rml::String text;
};
Button(Rml::Element* parent, Props props, const Rml::String& tagName = "button");
Button(Rml::Element* parent, Rml::String text, const Rml::String& tagName = "button")
: Button(parent, Props{std::move(text)}, tagName) {}
void set_text(const Rml::String& text);
Button& on_pressed(ButtonCallback callback);
const Rml::String& get_text() const { return mProps.text; }
private:
void update_props(Props props);
Props mProps;
};
class ControlledButton : public Button {
public:
struct Props {
Rml::String text;
std::function<bool()> isSelected;
};
ControlledButton(Rml::Element* parent, Props props, const Rml::String& tagName = "button")
: Button(parent, {std::move(props.text)}, tagName),
mIsSelected(std::move(props.isSelected)) {}
void update() override;
bool selected() const override;
private:
std::function<bool()> mIsSelected;
};
} // namespace dusk::ui
-97
View File
@@ -1,97 +0,0 @@
#include "component.hpp"
namespace dusk::ui {
Component::Component(Rml::Element* root) : mRoot(root) {}
Component::~Component() = default;
void Component::update() {
for (const auto& child : mChildren) {
child->update();
}
}
bool Component::focus() {
if (disabled()) {
return false;
}
// Can we focus self?
if (mRoot->Focus(true)) {
mRoot->ScrollIntoView(Rml::ScrollIntoViewOptions{
Rml::ScrollAlignment::Center,
Rml::ScrollAlignment::Center,
Rml::ScrollBehavior::Smooth,
Rml::ScrollParentage::Closest,
});
return true;
}
// Otherwise, try to focus a child
for (const auto& child : mChildren) {
if (child->focus()) {
return true;
}
}
return false;
}
void Component::set_selected(bool value) {
// Subclasses may override selected() to return a dynamic value, but
// we're only interested in if the pseudoclass is set or not, so we
// use Component::selected() directly rather than selected().
if (Component::selected() == value) {
return;
}
mRoot->SetPseudoClass("selected", value);
}
void Component::set_disabled(bool value) {
if (Component::disabled() == value) {
return;
}
if (value) {
mRoot->SetAttribute("disabled", "");
mRoot->SetPseudoClass("disabled", true);
mRoot->Blur();
} else {
mRoot->RemoveAttribute("disabled");
mRoot->SetPseudoClass("disabled", false);
}
}
Rml::Element* Component::append(Rml::Element* parent, const Rml::String& tag) {
if (parent == nullptr) {
return nullptr;
}
auto* doc = parent->GetOwnerDocument();
if (doc == nullptr) {
return nullptr;
}
return parent->AppendChild(doc->CreateElement(tag));
}
void Component::listen(Rml::Element* element, Rml::EventId event,
ScopedEventListener::Callback callback, bool capture) {
if (element == nullptr) {
element = mRoot;
}
mListeners.emplace_back(
std::make_unique<ScopedEventListener>(element, event, std::move(callback), capture));
}
bool Component::contains(Rml::Element* element) const {
for (const auto* node = element; node != nullptr; node = node->GetParentNode()) {
if (node == mRoot) {
return true;
}
}
return false;
}
void Component::clear_children() {
mChildren.clear();
while (mRoot->GetNumChildren() > 0) {
mRoot->RemoveChild(mRoot->GetFirstChild());
}
}
} // namespace dusk::ui
-97
View File
@@ -1,97 +0,0 @@
#pragma once
#include "event.hpp"
#include "ui.hpp"
#include <RmlUi/Core.h>
#include <memory>
#include <utility>
#include <vector>
namespace Rml {
class Element;
}
namespace dusk::ui {
class Component {
public:
Component() = default;
explicit Component(Rml::Element* root);
virtual ~Component();
Component(const Component&) = delete;
Component& operator=(const Component&) = delete;
virtual void update();
virtual bool focus();
virtual bool selected() const { return mRoot->IsPseudoClassSet("selected"); }
virtual void set_selected(bool selected);
virtual bool disabled() const { return mRoot->IsPseudoClassSet("disabled"); }
virtual void set_disabled(bool disabled);
void listen(Rml::Element* element, Rml::EventId event, ScopedEventListener::Callback callback,
bool capture = false);
bool contains(Rml::Element* element) const;
template <typename T, typename... Args>
requires std::is_base_of_v<Component, T> T& add_child(Args&&... args) {
auto child = std::make_unique<T>(mRoot, std::forward<Args>(args)...);
T& ref = *child;
mChildren.emplace_back(std::move(child));
return ref;
}
Rml::Element* root() const { return mRoot; }
protected:
static Rml::Element* append(Rml::Element* parent, const Rml::String& tag);
void clear_children();
Rml::Element* mRoot = nullptr;
std::vector<std::unique_ptr<Component> > mChildren;
std::vector<std::unique_ptr<ScopedEventListener> > mListeners;
};
template <class Derived>
class FluentComponent : public Component {
public:
using Component::Component;
Derived& listen(
Rml::EventId event, ScopedEventListener::Callback callback, bool capture = false) {
Component::listen(mRoot, event, std::move(callback), capture);
return static_cast<Derived&>(*this);
}
Derived& on_focus(ScopedEventListener::Callback callback) {
return listen(
Rml::EventId::Focus, [this, callback = std::move(callback)](Rml::Event& event) {
if (!disabled()) {
callback(event);
}
});
}
Derived& on_nav_command(std::function<bool(Rml::Event&, NavCommand)> callback) {
listen(Rml::EventId::Click, [this, callback](Rml::Event& event) {
if (!disabled() && callback(event, NavCommand::Confirm)) {
event.StopPropagation();
}
});
listen(Rml::EventId::Keydown, [this, callback = std::move(callback)](Rml::Event& event) {
if (disabled()) {
return;
}
const auto cmd = map_nav_event(event);
if (cmd != NavCommand::None && callback(event, cmd)) {
event.StopPropagation();
}
});
return static_cast<Derived&>(*this);
}
};
} // namespace dusk::ui
-109
View File
@@ -1,109 +0,0 @@
#include "document.hpp"
#include "aurora/rmlui.hpp"
#include "ui.hpp"
namespace dusk::ui {
namespace {
Rml::ElementDocument* load_document(const Rml::String& source) {
auto* context = aurora::rmlui::get_context();
if (context == nullptr) {
return nullptr;
}
return context->LoadDocumentFromMemory(source);
}
} // namespace
Document::Document(const Rml::String& source) : mDocument(load_document(source)) {
// Block events while hidden (except for Menu command)
listen(
Rml::EventId::Keydown,
[this](Rml::Event& event) {
const auto cmd = map_nav_event(event);
if (cmd != NavCommand::Menu && !visible()) {
event.StopImmediatePropagation();
}
},
true);
const auto blockUnlessVisible = [this](Rml::Event& event) {
if (!visible()) {
event.StopImmediatePropagation();
}
};
listen(Rml::EventId::Mouseover, blockUnlessVisible, true);
listen(Rml::EventId::Click, blockUnlessVisible, true);
listen(Rml::EventId::Scroll, blockUnlessVisible, true);
listen(Rml::EventId::Keydown, [this](Rml::Event& event) {
const auto cmd = map_nav_event(event);
if (cmd != NavCommand::None && handle_nav_command(event, cmd)) {
event.StopPropagation();
}
});
}
Document::~Document() {
mListeners.clear();
if (mDocument != nullptr) {
mDocument->Close();
mDocument = nullptr;
}
}
void Document::show() {
if (mDocument != nullptr) {
// Attempt to preserve the previously focused element
mDocument->Show(Rml::ModalFlag::None, Rml::FocusFlag::Keep, Rml::ScrollFlag::None);
// If nothing is focused, let the document decide the initial focus
auto* leaf = mDocument->GetFocusLeafNode();
if (leaf == nullptr || leaf == mDocument) {
focus();
}
}
}
void Document::hide(bool close) {
if (mDocument != nullptr) {
mDocument->Hide();
}
if (close) {
mClosed = true;
}
}
void Document::update() {}
bool Document::focus() {
return false;
}
void Document::listen(Rml::Element* element, Rml::EventId event,
ScopedEventListener::Callback callback, bool capture) {
if (element == nullptr) {
element = mDocument;
}
if (element == nullptr || !callback) {
return;
}
mListeners.emplace_back(
std::make_unique<ScopedEventListener>(element, event, std::move(callback), capture));
}
bool Document::visible() const {
if (mDocument == nullptr) {
return false;
}
return *mDocument->GetProperty(Rml::PropertyId::Visibility) == Rml::Style::Visibility::Visible;
}
bool Document::handle_nav_command(Rml::Event& event, NavCommand cmd) {
if (cmd == NavCommand::Menu) {
toggle();
return true;
}
return false;
}
} // namespace dusk::ui

Some files were not shown because too many files have changed in this diff Show More