mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-07-05 03:29:45 -04:00
Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 1520205403 | |||
| d2d7459d05 | |||
| c71272af05 |
+1
-1
@@ -2,7 +2,7 @@
|
||||
Language: Cpp
|
||||
Standard: C++03
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: DontAlign
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignOperands: true
|
||||
|
||||
@@ -100,7 +100,6 @@ if (CMAKE_SYSTEM_NAME STREQUAL Linux)
|
||||
endif ()
|
||||
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_RMLUI ON CACHE BOOL "Enable RmlUi UI support" FORCE)
|
||||
add_subdirectory(extern/aurora EXCLUDE_FROM_ALL)
|
||||
|
||||
add_subdirectory(libs/freeverb)
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||

|
||||

|
||||
|
||||
- ### **[Official Website](https://twilitrealm.dev)**
|
||||
- ### **[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
|
||||
**⚠️ 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
|
||||
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
|
||||
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).
|
||||
|
||||
Vendored
+1
-1
Submodule extern/aurora updated: 41d5c9c5a2...7784b6fc95
+3
-42
@@ -1,7 +1,7 @@
|
||||
|
||||
set(DOLZEL_FILES
|
||||
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_controller_pad.cpp
|
||||
#src/m_Do/m_Re_controller_pad.cpp
|
||||
@@ -1429,7 +1429,6 @@ set(DUSK_FILES
|
||||
src/dusk/globals.cpp
|
||||
src/dusk/gyro.cpp
|
||||
src/dusk/gamepad_color.cpp
|
||||
src/dusk/autosave.cpp
|
||||
src/dusk/io.cpp
|
||||
src/dusk/layout.cpp
|
||||
src/dusk/logging.cpp
|
||||
@@ -1454,6 +1453,7 @@ set(DUSK_FILES
|
||||
src/dusk/imgui/ImGuiProcessOverlay.cpp
|
||||
src/dusk/imgui/ImGuiCameraOverlay.cpp
|
||||
src/dusk/imgui/ImGuiHeapOverlay.cpp
|
||||
src/dusk/imgui/ImGuiActorSpawner.cpp
|
||||
src/dusk/imgui/ImGuiDebugPad.cpp
|
||||
src/dusk/imgui/ImGuiControllerOverlay.cpp
|
||||
src/dusk/imgui/ImGuiStubLog.cpp
|
||||
@@ -1463,51 +1463,12 @@ set(DUSK_FILES
|
||||
src/dusk/imgui/ImGuiStateShare.cpp
|
||||
src/dusk/imgui/ImGuiAchievements.hpp
|
||||
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/iso_validate.cpp
|
||||
src/dusk/livesplit.cpp
|
||||
src/dusk/offset_ptr.cpp
|
||||
src/dusk/vmem.cpp
|
||||
src/dusk/OSContext.cpp
|
||||
src/dusk/OSReport.cpp
|
||||
src/dusk/OSThread.cpp
|
||||
src/dusk/OSMutex.cpp
|
||||
src/dusk/discord_presence.cpp
|
||||
|
||||
@@ -27,7 +27,6 @@ public:
|
||||
/* 0x17C */ cXyz mViewScale;
|
||||
#if TARGET_PC
|
||||
bool mbReset = false;
|
||||
bool mbHadEntry = false;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -91,10 +91,6 @@ public:
|
||||
void calcCursor();
|
||||
void drawCursor();
|
||||
|
||||
#if TARGET_PC
|
||||
void dMapBgWide();
|
||||
#endif
|
||||
|
||||
void setDPDFloorSelCurPos(s8 i_pos) { field_0xdd6 = i_pos; }
|
||||
|
||||
f32 getMapWidth() { return mMapWidth; }
|
||||
|
||||
@@ -81,10 +81,6 @@ public:
|
||||
void calcDrawPriority();
|
||||
void setArrowPosAxis(f32, f32);
|
||||
|
||||
#if TARGET_PC
|
||||
void fMapBackWide();
|
||||
#endif
|
||||
|
||||
virtual void draw();
|
||||
virtual ~dMenu_Fmap2DBack_c();
|
||||
|
||||
@@ -334,10 +330,6 @@ public:
|
||||
void setHIO(bool);
|
||||
bool isWarpAccept();
|
||||
|
||||
#if TARGET_PC
|
||||
void fMapTopWide();
|
||||
#endif
|
||||
|
||||
virtual void draw();
|
||||
virtual ~dMenu_Fmap2DTop_c();
|
||||
|
||||
|
||||
@@ -67,9 +67,6 @@ public:
|
||||
bool isStaffMessage();
|
||||
bool isSaveMessage();
|
||||
bool isTalkMessage();
|
||||
#if TARGET_PC
|
||||
bool isShopItemMessage();
|
||||
#endif
|
||||
const char* getSmellName();
|
||||
const char* getPortalName();
|
||||
const char* getBombName();
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
#include <functional>
|
||||
#include <queue>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_set>
|
||||
#include <vector>
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
@@ -16,7 +14,6 @@ enum class AchievementCategory : uint8_t {
|
||||
Collection,
|
||||
Challenge,
|
||||
Minigame,
|
||||
Misc,
|
||||
Glitched
|
||||
};
|
||||
|
||||
@@ -43,11 +40,6 @@ public:
|
||||
void save();
|
||||
void tick();
|
||||
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;
|
||||
bool hasPendingUnlock() const { return !m_pendingUnlocks.empty(); }
|
||||
@@ -65,7 +57,6 @@ private:
|
||||
void processEntry(Entry& e);
|
||||
|
||||
std::vector<Entry> m_entries;
|
||||
std::unordered_set<std::string_view> m_signals;
|
||||
bool m_loaded = false;
|
||||
bool m_dirty = false;
|
||||
std::queue<std::string> m_pendingUnlocks;
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -55,7 +55,6 @@ struct UserSettings {
|
||||
ConfigVar<int> soundEffectsVolume;
|
||||
ConfigVar<int> fanfareVolume;
|
||||
ConfigVar<bool> enableReverb;
|
||||
ConfigVar<bool> enableHrtf;
|
||||
} audio;
|
||||
|
||||
// Game settings
|
||||
@@ -72,7 +71,6 @@ struct UserSettings {
|
||||
ConfigVar<bool> disableRupeeCutscenes;
|
||||
ConfigVar<bool> noSwordRecoil;
|
||||
ConfigVar<int> damageMultiplier;
|
||||
ConfigVar<bool> hyperEnemies;
|
||||
ConfigVar<bool> noHeartDrops;
|
||||
ConfigVar<bool> instantDeath;
|
||||
ConfigVar<bool> fastClimbing;
|
||||
@@ -82,7 +80,6 @@ struct UserSettings {
|
||||
ConfigVar<bool> instantSaves;
|
||||
ConfigVar<bool> instantText;
|
||||
ConfigVar<bool> sunsSong;
|
||||
ConfigVar<bool> autoSave;
|
||||
|
||||
// Preferences
|
||||
ConfigVar<bool> enableMirrorMode;
|
||||
|
||||
@@ -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; }
|
||||
int getNumActiveSeqs() const { return mSeqList.getNumLinks(); }
|
||||
void pause(bool paused) { mActivity.field_0x0.flags.flag2 = paused; }
|
||||
#if TARGET_PC
|
||||
JSUList<JAISeq>* getSeqList() { return &mSeqList; }
|
||||
#endif
|
||||
|
||||
private:
|
||||
/* 0x08 */ JAIAudience* mAudience;
|
||||
|
||||
@@ -127,6 +127,13 @@ public:
|
||||
[[nodiscard]] const CMemBlock* getFreeHead() const { return mHeadFreeList; }
|
||||
[[nodiscard]] CMemBlock* getUsedHead() { 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
|
||||
};
|
||||
|
||||
|
||||
@@ -61,6 +61,15 @@ public:
|
||||
static JKRSolidHeap* create(u32, JKRHeap*, bool);
|
||||
|
||||
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) {
|
||||
|
||||
@@ -207,11 +207,4 @@ void JPARegistAlphaEnv(JPAEmitterWorkData*, JPABaseParticle*);
|
||||
void JPARegistPrmAlpha(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 */
|
||||
|
||||
@@ -24,9 +24,6 @@ public:
|
||||
void init_c(JPAEmitterWorkData*, JPABaseParticle*);
|
||||
bool calc_p(JPAEmitterWorkData*);
|
||||
bool calc_c(JPAEmitterWorkData*);
|
||||
#if TARGET_PC
|
||||
void interp(JPAEmitterWorkData*, void const* drawFunc);
|
||||
#endif
|
||||
bool canCreateChild(JPAEmitterWorkData*);
|
||||
f32 getWidth(JPABaseEmitter const*) const;
|
||||
f32 getHeight(JPABaseEmitter const*) const;
|
||||
|
||||
@@ -40,9 +40,6 @@ public:
|
||||
JUTTransparency getTransparency() const { return JUTTransparency(mTransparency); }
|
||||
u16 getNumColors() const { return mNumColors; }
|
||||
ResTLUT* getColorTable() const { return mColorTable; }
|
||||
#if TARGET_PC
|
||||
void dataUploaded();
|
||||
#endif
|
||||
|
||||
private:
|
||||
/* 0x00 */ GXTlutObj mTlutObj;
|
||||
|
||||
@@ -75,7 +75,6 @@ public:
|
||||
s32 getTransparency() const { return mTexInfo->alphaEnabled; }
|
||||
s32 getWidth() const { return mTexInfo->width; }
|
||||
s32 getHeight() const { return mTexInfo->height; }
|
||||
JUTPalette* getPalette() const { return mPalette; }
|
||||
void setCaptureFlag(bool flag) { mFlags &= 2 | flag; }
|
||||
bool getCaptureFlag() const { return mFlags & 1; }
|
||||
bool getEmbPaletteDelFlag() const { return mFlags & 2; }
|
||||
@@ -83,7 +82,7 @@ public:
|
||||
int getTlutName() const { return mTlutName; }
|
||||
bool operator==(const JUTTexture& other) {
|
||||
return mTexInfo == other.mTexInfo
|
||||
&& mPalette == other.mPalette
|
||||
&& field_0x2c == other.field_0x2c
|
||||
&& mWrapS == other.mWrapS
|
||||
&& mWrapT == other.mWrapT
|
||||
&& mMinFilter == other.mMinFilter
|
||||
@@ -101,7 +100,7 @@ private:
|
||||
/* 0x20 */ const ResTIMG* mTexInfo;
|
||||
/* 0x24 */ void* mTexData;
|
||||
/* 0x28 */ JUTPalette* mEmbPalette;
|
||||
/* 0x2C */ JUTPalette* mPalette;
|
||||
/* 0x2C */ JUTPalette* field_0x2c;
|
||||
/* 0x30 */ u8 mWrapS;
|
||||
/* 0x31 */ u8 mWrapT;
|
||||
/* 0x32 */ u8 mMinFilter;
|
||||
|
||||
@@ -1,9 +1,6 @@
|
||||
#include "JSystem/JSystem.h" // IWYU pragma: keep
|
||||
|
||||
#include "JSystem/JAudio2/JASChannel.h"
|
||||
#if TARGET_PC
|
||||
#include "dusk/audio/DuskDsp.hpp"
|
||||
#endif
|
||||
#include "JSystem/JAudio2/JASAiCtrl.h"
|
||||
#include "JSystem/JAudio2/JASCalc.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 dolby = 0.0f;
|
||||
#if TARGET_PC
|
||||
u32 effectiveOutputMode = dusk::audio::EnableHrtf ? JAS_OUTPUT_SURROUND : JASDriver::getOutputMode();
|
||||
#else
|
||||
u32 effectiveOutputMode = JASDriver::getOutputMode();
|
||||
#endif
|
||||
switch (effectiveOutputMode) {
|
||||
switch (JASDriver::getOutputMode()) {
|
||||
case JAS_OUTPUT_MONO:
|
||||
break;
|
||||
case JAS_OUTPUT_STEREO:
|
||||
|
||||
@@ -302,6 +302,7 @@ void JASKernel::setupRootHeap(JKRSolidHeap* heap, u32 size) {
|
||||
JKRHEAP_NAME(sSystemHeap, "JASKernel::sSystemHeap");
|
||||
JUT_ASSERT(787, sSystemHeap);
|
||||
sCommandHeap = JKR_NEW_ARGS (heap, 0) JASMemChunkPool<1024, JASThreadingModel::ObjectLevelLockable>;
|
||||
JKRHEAP_NAME(sSystemHeap, "JASKernel::sCommandHeap");
|
||||
JUT_ASSERT(790, sCommandHeap);
|
||||
JASDram = heap;
|
||||
}
|
||||
|
||||
@@ -442,7 +442,6 @@ static JAUSectionHeap* JAUNewSectionHeap(JKRSolidHeap* heap, bool param_1) {
|
||||
JAUSectionHeap* JAUNewSectionHeap(bool param_0) {
|
||||
s32 freeSize = JASDram->getFreeSize();
|
||||
JKRSolidHeap* sectionHeap = JKRCreateSolidHeap(freeSize, JASDram, true);
|
||||
JKRHEAP_NAME(sectionHeap, "sectionHeap");
|
||||
JUT_ASSERT(821, sectionHeap);
|
||||
return JAUNewSectionHeap(sectionHeap, param_0);
|
||||
}
|
||||
|
||||
@@ -10,6 +10,11 @@
|
||||
#include "JSystem/JUtility/JUTConsole.h"
|
||||
#include "JSystem/JUtility/JUTException.h"
|
||||
#include <cstdlib>
|
||||
#if TARGET_PC
|
||||
#include "dusk/vmem.h"
|
||||
#include <algorithm>
|
||||
#include "dusk/logging.h"
|
||||
#endif
|
||||
|
||||
JKRExpHeap* JKRExpHeap::createRoot(int maxHeaps, bool errorFlag) {
|
||||
JKRExpHeap* heap = NULL;
|
||||
@@ -71,21 +76,49 @@ JKRExpHeap* JKRExpHeap::create(u32 size, JKRHeap* parent, bool errorFlag) {
|
||||
|
||||
u32 alignedSize = ALIGN_PREV(size, 0x10);
|
||||
|
||||
if (alignedSize < expHeapSize + blockSize)
|
||||
if (alignedSize < expHeapSize + blockSize) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
u8* memory = (u8*)JKRAllocFromHeap(parent, alignedSize, 0x10);
|
||||
u8* dataPtr = (memory + expHeapSize);
|
||||
#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* dataPtr = memory + expHeapSize;
|
||||
if (!memory) {
|
||||
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) {
|
||||
JKRFree(memory);
|
||||
return NULL;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
if (newHeap) {
|
||||
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) {
|
||||
JKRHeap* parent2;
|
||||
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);
|
||||
if (!parent2)
|
||||
#endif
|
||||
if (!parent2) {
|
||||
return NULL;
|
||||
}
|
||||
} else {
|
||||
parent2 = parent;
|
||||
}
|
||||
@@ -136,6 +176,15 @@ JKRExpHeap* JKRExpHeap::create(void* ptr, u32 size, JKRHeap* parent, bool errorF
|
||||
}
|
||||
|
||||
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) {
|
||||
JKRHeap* heap = getParent();
|
||||
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);
|
||||
mHeadUsedList = NULL;
|
||||
mTailUsedList = NULL;
|
||||
#if TARGET_PC
|
||||
mVmemBase = nullptr;
|
||||
mVmemCapacity = 0;
|
||||
mVmemCommitted = 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
JKRExpHeap::~JKRExpHeap() {
|
||||
@@ -214,6 +268,24 @@ void* JKRExpHeap::do_alloc(u32 size, int alignment) {
|
||||
#endif
|
||||
|
||||
#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) {
|
||||
// Allocation failed.
|
||||
OSReport_Error(
|
||||
@@ -222,11 +294,16 @@ void* JKRExpHeap::do_alloc(u32 size, int alignment) {
|
||||
OSReport_Error("Free block list as follows:\n");
|
||||
OSReport_Error("Start | End | Size \n");
|
||||
|
||||
int i = 0;
|
||||
for (const CMemBlock* block = mHeadFreeList; block; block = block->mNext) {
|
||||
if (block->mMagic) {
|
||||
// Allocated, ignore.
|
||||
continue;
|
||||
}
|
||||
if (i++ > 10) {
|
||||
OSReport_Error("<more>\n");
|
||||
break;
|
||||
}
|
||||
|
||||
auto blockStart = (uintptr_t)block - (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("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!");
|
||||
}
|
||||
#else
|
||||
@@ -494,6 +563,49 @@ static void dummy() {
|
||||
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() {
|
||||
lock();
|
||||
JKRHeap::callAllDisposer();
|
||||
|
||||
@@ -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/JGadget/binary.h"
|
||||
@@ -7,6 +7,11 @@
|
||||
#include "global.h"
|
||||
#include <stdint.h>
|
||||
#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) {
|
||||
if (!heap) {
|
||||
@@ -19,18 +24,56 @@ JKRSolidHeap* JKRSolidHeap::create(u32 size, JKRHeap* heap, bool useErrorHandler
|
||||
}
|
||||
|
||||
u32 alignedSize = ALIGN_PREV(size, 0x10);
|
||||
if (alignedSize < solidHeapSize)
|
||||
if (alignedSize < solidHeapSize) {
|
||||
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);
|
||||
void* dataPtr = mem + solidHeapSize;
|
||||
if (!mem)
|
||||
if (!mem) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return JKR_NEW_ARGS (mem) JKRSolidHeap(dataPtr, alignedSize - solidHeapSize, heap, useErrorHandler);
|
||||
#endif
|
||||
}
|
||||
|
||||
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();
|
||||
if (parent) {
|
||||
this->~JKRSolidHeap();
|
||||
@@ -44,6 +87,11 @@ JKRSolidHeap::JKRSolidHeap(void* start, u32 size, JKRHeap* parent, bool useError
|
||||
mSolidHead = (u8*)mStart;
|
||||
mSolidTail = (u8*)mEnd;
|
||||
field_0x78 = NULL;
|
||||
#if TARGET_PC
|
||||
mVmemBase = nullptr;
|
||||
mVmemCapacity = 0;
|
||||
mVmemCommitted = 0;
|
||||
#endif
|
||||
#if DEBUG
|
||||
if (mDebugFill) {
|
||||
JKRFillMemory(mStart, mSize, JKRValue_DEBUGFILL_NOTUSE);
|
||||
@@ -59,6 +107,15 @@ s32 JKRSolidHeap::adjustSize(void) {
|
||||
int r25 = 0;
|
||||
JKRHeap* parent = getParent();
|
||||
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();
|
||||
u32 thisSize = (uintptr_t)mStart - (uintptr_t)this;
|
||||
u32 newSize = ALIGN_NEXT(mSolidHead - mStart, 0x20);
|
||||
@@ -110,6 +167,11 @@ void* JKRSolidHeap::allocFromHead(u32 size, int alignment) {
|
||||
void* ptr = NULL;
|
||||
uintptr_t alignedStart = (alignment - 1 + (uintptr_t)mSolidHead) & ~(alignment - 1);
|
||||
u32 totalSize = size + (alignedStart - (uintptr_t)mSolidHead);
|
||||
#if TARGET_PC
|
||||
if (totalSize > mFreeSize && mVmemBase) {
|
||||
growHeap(totalSize);
|
||||
}
|
||||
#endif
|
||||
if (totalSize <= mFreeSize) {
|
||||
#if DEBUG
|
||||
if (mCheckMemoryFilled) {
|
||||
@@ -137,6 +199,15 @@ void* JKRSolidHeap::allocFromTail(u32 size, int alignment) {
|
||||
void* ptr = NULL;
|
||||
uintptr_t alignedStart = ALIGN_PREV((uintptr_t)mSolidTail - size, alignment);
|
||||
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) {
|
||||
ptr = (void*)alignedStart;
|
||||
mSolidTail -= totalSize;
|
||||
@@ -158,6 +229,47 @@ void* JKRSolidHeap::allocFromTail(u32 size, int alignment) {
|
||||
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) {
|
||||
JUTWarningConsole_f("free: cannot free memory block (%08x)\n", ptr);
|
||||
}
|
||||
|
||||
@@ -9,9 +9,6 @@
|
||||
#include <mtx.h>
|
||||
#include <gx.h>
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/frame_interpolation.h"
|
||||
#endif
|
||||
#include "tracy/Tracy.hpp"
|
||||
|
||||
void JPASetPointSize(JPAEmitterWorkData* work) {
|
||||
@@ -421,95 +418,50 @@ static projectionFunc p_prj[3] = {
|
||||
loadPrjAnm,
|
||||
};
|
||||
|
||||
#if TARGET_PC
|
||||
void JPAInterpBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
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)) {
|
||||
void JPADrawBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
|
||||
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
|
||||
return;
|
||||
}
|
||||
|
||||
JGeometry::TVec3<f32> pos;
|
||||
#if TARGET_PC
|
||||
Mtx ptclPosMtx;
|
||||
if (dusk::frame_interp::lookup_replacement(ptcl, ptclPosMtx)) {
|
||||
pos.set(ptclPosMtx[0][3], ptclPosMtx[1][3], ptclPosMtx[2][3]);
|
||||
MTXMultVec(work->mPosCamMtx, &pos, &pos);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
MTXMultVec(work->mPosCamMtx, &ptcl->mPosition, &pos);
|
||||
}
|
||||
Mtx posMtx;
|
||||
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);
|
||||
JGeometry::TVec3<f32> local_48;
|
||||
MTXMultVec(work->mPosCamMtx, ¶m_1->mPosition, &local_48);
|
||||
Mtx local_38;
|
||||
local_38[0][0] = work->mGlobalPtclScl.x * param_1->mParticleScaleX;
|
||||
local_38[0][3] = local_48.x;
|
||||
local_38[1][1] = work->mGlobalPtclScl.y * param_1->mParticleScaleY;
|
||||
local_38[1][3] = local_48.y;
|
||||
local_38[2][2] = 1.0f;
|
||||
local_38[2][3] = local_48.z;
|
||||
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);
|
||||
p_prj[work->mPrjType](work, local_38);
|
||||
GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
|
||||
}
|
||||
|
||||
void JPADrawRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
|
||||
void JPADrawRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
|
||||
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (work->mpRes->getUsrIdx() == 0x89d7) {
|
||||
int a = 0;
|
||||
}
|
||||
JGeometry::TVec3<f32> local_48;
|
||||
MTXMultVec(work->mPosCamMtx, ¶m_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;
|
||||
f32 sinRot, cosRot;
|
||||
#if TARGET_PC
|
||||
Mtx ptclPosMtx;
|
||||
MTXTrans(ptclPosMtx, ptcl->mPosition.x, ptcl->mPosition.y, ptcl->mPosition.z);
|
||||
if (dusk::frame_interp::lookup_replacement(ptcl, ptclPosMtx)) {
|
||||
pos.set(ptclPosMtx[0][3], ptclPosMtx[1][3], ptclPosMtx[2][3]);
|
||||
sinRot = ptclPosMtx[1][0];
|
||||
cosRot = ptclPosMtx[0][0];
|
||||
MTXMultVec(work->mPosCamMtx, &pos, &pos);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
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);
|
||||
Mtx local_38;
|
||||
local_38[0][0] = cosRot * particleX;
|
||||
local_38[0][1] = -sinRot * particleY;
|
||||
local_38[0][3] = local_48.x;
|
||||
local_38[1][0] = sinRot * particleX;
|
||||
local_38[1][1] = cosRot * particleY;
|
||||
local_38[1][3] = local_48.y;
|
||||
local_38[2][2] = 1.0f;
|
||||
local_38[2][3] = local_48.z;
|
||||
local_38[0][2] = local_38[1][2] = local_38[2][0] = local_38[2][1] = 0.0f;
|
||||
GXLoadPosMtxImm(local_38, 0);
|
||||
p_prj[work->mPrjType](work, local_38);
|
||||
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][3] = local_48.z;
|
||||
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);
|
||||
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][2] = local_90;
|
||||
local_38[2][3] = local_48.z;
|
||||
GXLoadPosMtxImm(local_38, GX_PNMTX0);
|
||||
GXLoadPosMtxImm(local_38, 0);
|
||||
p_prj[work->mPrjType](work, local_38);
|
||||
GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
|
||||
}
|
||||
@@ -729,197 +681,103 @@ static u8* p_dl[2] = {
|
||||
jpa_dl_x,
|
||||
};
|
||||
|
||||
#if TARGET_PC
|
||||
void JPAInterpDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
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)) {
|
||||
void JPADrawDirection(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
|
||||
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ZoneScoped;
|
||||
|
||||
Mtx posMtx;
|
||||
#if TARGET_PC
|
||||
if (!dusk::frame_interp::lookup_replacement(ptcl, posMtx))
|
||||
#endif
|
||||
{
|
||||
JGeometry::TVec3<f32> axisY;
|
||||
JGeometry::TVec3<f32> axisZ;
|
||||
p_direction[work->mDirType](work, ptcl, &axisY);
|
||||
JGeometry::TVec3<f32> local_6c;
|
||||
JGeometry::TVec3<f32> local_78;
|
||||
p_direction[param_0->mDirType](param_0, param_1, &local_6c);
|
||||
|
||||
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;
|
||||
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);
|
||||
if (local_6c.isZero()) {
|
||||
return;
|
||||
}
|
||||
|
||||
MTXConcat(work->mPosCamMtx, posMtx, posMtx);
|
||||
GXLoadPosMtxImm(posMtx, GX_PNMTX0);
|
||||
p_prj[work->mPrjType](work, posMtx);
|
||||
GXCallDisplayList(p_dl[work->mDLType], sizeof(jpa_dl));
|
||||
local_6c.normalize();
|
||||
local_78.cross(param_1->mBaseAxis, local_6c);
|
||||
|
||||
if (local_78.isZero()) {
|
||||
return;
|
||||
}
|
||||
|
||||
local_78.normalize();
|
||||
param_1->mBaseAxis.cross(local_6c, local_78);
|
||||
param_1->mBaseAxis.normalize();
|
||||
Mtx local_60;
|
||||
f32 fVar1 = param_0->mGlobalPtclScl.x * param_1->mParticleScaleX;
|
||||
f32 fVar2 = param_0->mGlobalPtclScl.y * param_1->mParticleScaleY;
|
||||
local_60[0][0] = param_1->mBaseAxis.x;
|
||||
local_60[0][1] = local_6c.x;
|
||||
local_60[0][2] = local_78.x;
|
||||
local_60[0][3] = param_1->mPosition.x;
|
||||
local_60[1][0] = param_1->mBaseAxis.y;
|
||||
local_60[1][1] = local_6c.y;
|
||||
local_60[1][2] = local_78.y;
|
||||
local_60[1][3] = param_1->mPosition.y;
|
||||
local_60[2][0] = param_1->mBaseAxis.z;
|
||||
local_60[2][1] = local_6c.z;
|
||||
local_60[2][2] = local_78.z;
|
||||
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);
|
||||
GXLoadPosMtxImm(local_60, 0);
|
||||
p_prj[param_0->mPrjType](param_0, local_60);
|
||||
GXCallDisplayList(p_dl[param_0->mDLType], sizeof(jpa_dl));
|
||||
}
|
||||
|
||||
void JPADrawRotDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
|
||||
if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
|
||||
void JPADrawRotDirection(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
|
||||
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
|
||||
return;
|
||||
}
|
||||
|
||||
ZoneScoped;
|
||||
|
||||
Mtx mtx1;
|
||||
Mtx mtx2;
|
||||
#if TARGET_PC
|
||||
if (!dusk::frame_interp::lookup_replacement(ptcl, mtx1))
|
||||
#endif
|
||||
{
|
||||
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);
|
||||
f32 sinRot = JMASSin(param_1->mRotateAngle);
|
||||
f32 cosRot = JMASCos(param_1->mRotateAngle);
|
||||
JGeometry::TVec3<f32> local_6c;
|
||||
JGeometry::TVec3<f32> local_78;
|
||||
p_direction[param_0->mDirType](param_0, param_1, &local_6c);
|
||||
|
||||
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;
|
||||
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);
|
||||
if (local_6c.isZero()) {
|
||||
return;
|
||||
}
|
||||
MTXConcat(work->mPosCamMtx, mtx1, mtx2);
|
||||
GXLoadPosMtxImm(mtx2, GX_PNMTX0);
|
||||
p_prj[work->mPrjType](work, mtx2);
|
||||
GXCallDisplayList(p_dl[work->mDLType], sizeof(jpa_dl));
|
||||
|
||||
local_6c.normalize();
|
||||
local_78.cross(param_1->mBaseAxis, local_6c);
|
||||
|
||||
if (local_78.isZero()) {
|
||||
return;
|
||||
}
|
||||
|
||||
local_78.normalize();
|
||||
param_1->mBaseAxis.cross(local_6c, local_78);
|
||||
param_1->mBaseAxis.normalize();
|
||||
f32 particleX = param_0->mGlobalPtclScl.x * param_1->mParticleScaleX;
|
||||
f32 particleY = param_0->mGlobalPtclScl.y * param_1->mParticleScaleY;
|
||||
Mtx auStack_80;
|
||||
Mtx local_60;
|
||||
p_rot[param_0->mRotType](sinRot, cosRot, auStack_80);
|
||||
p_plane[param_0->mPlaneType](auStack_80, particleX, particleY);
|
||||
local_60[0][0] = param_1->mBaseAxis.x;
|
||||
local_60[0][1] = local_6c.x;
|
||||
local_60[0][2] = local_78.x;
|
||||
local_60[0][3] = param_1->mPosition.x;
|
||||
local_60[1][0] = param_1->mBaseAxis.y;
|
||||
local_60[1][1] = local_6c.y;
|
||||
local_60[1][2] = local_78.y;
|
||||
local_60[1][3] = param_1->mPosition.y;
|
||||
local_60[2][0] = param_1->mBaseAxis.z;
|
||||
local_60[2][1] = local_6c.z;
|
||||
local_60[2][2] = local_78.z;
|
||||
local_60[2][3] = param_1->mPosition.z;
|
||||
MTXConcat(local_60, auStack_80, auStack_80);
|
||||
MTXConcat(param_0->mPosCamMtx, auStack_80, local_60);
|
||||
GXLoadPosMtxImm(local_60, 0);
|
||||
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) {
|
||||
|
||||
@@ -204,28 +204,6 @@ void JPABaseParticle::init_c(JPAEmitterWorkData* work, JPABaseParticle* parent)
|
||||
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) {
|
||||
if (++mAge >= mLifeTime) {
|
||||
return true;
|
||||
@@ -269,17 +247,6 @@ bool JPABaseParticle::calc_p(JPAEmitterWorkData* work) {
|
||||
mOffsetPosition.y + mLocalPosition.y * work->mPublicScale.y,
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -322,23 +289,6 @@ bool JPABaseParticle::calc_c(JPAEmitterWorkData* work) {
|
||||
mOffsetPosition.y + mLocalPosition.y * work->mPublicScale.y,
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -38,9 +38,3 @@ bool JUTPalette::load() {
|
||||
|
||||
return check;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
void JUTPalette::dataUploaded() {
|
||||
GXInitTlutObjData(&mTlutObj, (void*)mColorTable);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -27,7 +27,7 @@ void JUTTexture::storeTIMG(ResTIMG const* param_0, u8 param_1) {
|
||||
mTexData = (void*)((intptr_t)mTexInfo + 0x20);
|
||||
}
|
||||
|
||||
mPalette = NULL;
|
||||
field_0x2c = NULL;
|
||||
mTlutName = 0;
|
||||
mWrapS = mTexInfo->wrapS;
|
||||
mWrapT = mTexInfo->wrapT;
|
||||
@@ -95,7 +95,7 @@ void JUTTexture::storeTIMG(ResTIMG const* param_0, JUTPalette* param_1, GXTlut p
|
||||
}
|
||||
mEmbPalette = param_1;
|
||||
setEmbPaletteDelFlag(false);
|
||||
mPalette = NULL;
|
||||
field_0x2c = NULL;
|
||||
if (param_1 != NULL) {
|
||||
mTlutName = param_2;
|
||||
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) {
|
||||
if (mTexInfo->indexTexture) {
|
||||
if (param_0 == NULL && mEmbPalette != NULL) {
|
||||
mPalette = mEmbPalette;
|
||||
field_0x2c = mEmbPalette;
|
||||
} else {
|
||||
mPalette = param_0;
|
||||
field_0x2c = param_0;
|
||||
}
|
||||
initTexObj(mPalette->getTlutName());
|
||||
initTexObj(field_0x2c->getTlutName());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -133,9 +133,9 @@ void JUTTexture::init() {
|
||||
initTexObj();
|
||||
} else {
|
||||
if (mEmbPalette != NULL) {
|
||||
mPalette = mEmbPalette;
|
||||
field_0x2c = mEmbPalette;
|
||||
|
||||
initTexObj(mPalette->getTlutName());
|
||||
initTexObj(field_0x2c->getTlutName());
|
||||
} else {
|
||||
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) {
|
||||
if (mPalette) {
|
||||
mPalette->load();
|
||||
if (field_0x2c) {
|
||||
field_0x2c->load();
|
||||
}
|
||||
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 |
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
@@ -1,9 +1,5 @@
|
||||
#include "Z2AudioLib/Z2Audience.h"
|
||||
#include "Z2AudioLib/Z2SoundInfo.h"
|
||||
#if TARGET_PC
|
||||
#include "dusk/audio/DuskDsp.hpp"
|
||||
#include <cmath>
|
||||
#endif
|
||||
#include "Z2AudioLib/Z2Calc.h"
|
||||
#include "Z2AudioLib/Z2Param.h"
|
||||
#include "JSystem/JAudio2/JAISound.h"
|
||||
@@ -738,22 +734,9 @@ f32 Z2Audience::calcRelPosPan(const Vec& param_0, int camID) {
|
||||
|
||||
f32 Z2Audience::calcRelPosDolby(const Vec& param_0, int camID) {
|
||||
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) {
|
||||
return 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
if (fVar1 < mSetting.field_0x44) {
|
||||
return 0.0f;
|
||||
|
||||
@@ -4962,16 +4962,13 @@ int daAlink_c::create() {
|
||||
|
||||
setArcName(checkWolf());
|
||||
setOriginalHeap(&mpArcHeap, 0xA2800);
|
||||
JKRHEAP_NAME(mpArcHeap, "Alink ArcHeap");
|
||||
if (dComIfG_resLoad(&mPhaseReq, mArcName, mpArcHeap) != cPhs_COMPLEATE_e) {
|
||||
return cPhs_INIT_e;
|
||||
}
|
||||
|
||||
setShieldArcName();
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -8,10 +8,6 @@
|
||||
#include "d/actor/d_a_horse.h"
|
||||
#include "d/actor/d_a_crod.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
|
||||
#include "d/d_s_menu.h"
|
||||
@@ -681,15 +677,6 @@ BOOL daAlink_c::checkDamageAction() {
|
||||
}
|
||||
|
||||
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) {
|
||||
setGuardSe(var_r29);
|
||||
|
||||
@@ -18,10 +18,6 @@ enum {
|
||||
};
|
||||
|
||||
void daAlink_c::hsChainShape_c::draw() {
|
||||
if (dusk::getSettings().game.superClawshot) {
|
||||
return;
|
||||
}
|
||||
|
||||
static const int dummy = 0;
|
||||
|
||||
daAlink_c* alink = (daAlink_c*)getUserArea();
|
||||
|
||||
@@ -46,6 +46,7 @@ void daAlink_c::setOriginalHeap(JKRExpHeap** i_ppheap, u32 i_size) {
|
||||
JKRHeap* parent = mDoExt_getGameHeap();
|
||||
|
||||
JKRExpHeap* heap = JKRExpHeap::create(size + (var_r29 + var_r28), parent, true);
|
||||
JKRHEAP_NAME(heap, "Alink original");
|
||||
*i_ppheap = heap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,8 +14,6 @@
|
||||
#include "JSystem/J2DGraph/J2DAnmLoader.h"
|
||||
#include <cstring>
|
||||
|
||||
#include "dusk/memory.h"
|
||||
|
||||
class daCoach2D_HIO_c : public mDoHIO_entry_c {
|
||||
public:
|
||||
struct Param {
|
||||
@@ -155,7 +153,7 @@ int daCoach2D_c::createHeap() {
|
||||
int daCoach2D_c::create() {
|
||||
int phase_state = dComIfG_resLoad(this, l_arcName);
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
@@ -17,11 +17,6 @@
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#if TARGET_PC
|
||||
#include <f_ap/f_ap_game.h>
|
||||
#include <dusk/autosave.h>
|
||||
#endif
|
||||
|
||||
char* daDoor20_c::getStopBmdName() {
|
||||
switch (door_param2_c::getKind(this)) {
|
||||
case 3:
|
||||
@@ -201,7 +196,6 @@ void daDoor20_c::setEventPrm() {
|
||||
} else {
|
||||
roomNo = FRoomNo;
|
||||
}
|
||||
|
||||
if (dComIfGp_roomControl_checkStatusFlag(roomNo, 1)) {
|
||||
if (door_param2_c::getKind(this) == 9) {
|
||||
if (daPy_py_c::checkNowWolf()) {
|
||||
@@ -570,11 +564,6 @@ int daDoor20_c::openEnd(int param_1) {
|
||||
openEnd_1();
|
||||
break;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
triggerAutoSave();
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
@@ -282,11 +282,6 @@ static void e_th_spin_B(e_th_class* i_this) {
|
||||
i_this->current.pos += spC;
|
||||
|
||||
f32 speed_target;
|
||||
|
||||
#if AVOID_UB
|
||||
speed_target = 0;
|
||||
#endif
|
||||
|
||||
f32 anm_frame = i_this->mpModelMorf->getFrame();
|
||||
|
||||
switch (i_this->mMode) {
|
||||
|
||||
@@ -463,23 +463,6 @@ int daMidna_c::createHeap() {
|
||||
JKRReadIdxResource(mBckHeap[0].getBuffer(), mBckHeap[0].getBufferSize(), 0x1DC, dComIfGp_getAnmArchive());
|
||||
J3DAnmTransform* md_anm = (J3DAnmTransform*)J3DAnmLoaderDataBase::load(mBckHeap[0].getBuffer());
|
||||
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);
|
||||
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) {
|
||||
|
||||
@@ -40,7 +40,6 @@ dMirror_packet_c::dMirror_packet_c() {
|
||||
void dMirror_packet_c::reset() {
|
||||
#if TARGET_PC
|
||||
mbReset = true;
|
||||
mbHadEntry = false;
|
||||
#else
|
||||
mModelCount = 0;
|
||||
#endif
|
||||
@@ -85,21 +84,11 @@ void dMirror_packet_c::calcMinMax() {
|
||||
}
|
||||
|
||||
int dMirror_packet_c::entryModel(J3DModel* i_model) {
|
||||
#if TARGET_PC
|
||||
if (mbReset) {
|
||||
mModelCount = 0;
|
||||
mbReset = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mModelCount >= 0x40) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
mModels[mModelCount++] = i_model;
|
||||
#if TARGET_PC
|
||||
mbHadEntry = true;
|
||||
#endif
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -603,6 +592,13 @@ int daMirror_c::execute() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
if (mPacket.mbReset) {
|
||||
mPacket.mModelCount = 0;
|
||||
mPacket.mbReset = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
daPy_py_c* player = daPy_getLinkPlayerActorClass();
|
||||
JUT_ASSERT(0, player != NULL);
|
||||
|
||||
@@ -628,12 +624,6 @@ int daMirror_c::draw() {
|
||||
mDoExt_modelUpdateDL(mpModel);
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
if (mPacket.mbReset && !mPacket.mbHadEntry) {
|
||||
mPacket.mModelCount = 0;
|
||||
}
|
||||
mPacket.mbHadEntry = true;
|
||||
#endif
|
||||
dComIfGd_getOpaListBG()->entryImm(&mPacket, 0);
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -62,16 +62,6 @@ void daObj_Balloon_c::saveBestScore() {
|
||||
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 daObj_Balloon_HIO_c l_HIO;
|
||||
@@ -215,6 +205,13 @@ int daObj_Balloon_c::_delete() {
|
||||
Z2GetAudioMgr()->seStop(Z2SE_OBJ_WATERMILL_ROUND, 0);
|
||||
if (mHIOInit) {
|
||||
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;
|
||||
}
|
||||
@@ -256,7 +253,6 @@ int daObj_Balloon_c::create() {
|
||||
}
|
||||
|
||||
if (!hio_set) {
|
||||
IF_DUSK(minigameReset());
|
||||
mHIOInit = true;
|
||||
hio_set = true;
|
||||
l_HIO.field_0x04 = -1;
|
||||
|
||||
+43
-55
@@ -1175,12 +1175,6 @@ bool dCamera_c::Run() {
|
||||
clrFlag(0x200000);
|
||||
}
|
||||
} else {
|
||||
#if TARGET_PC
|
||||
if (mCamParam.Algorythmn(mCamStyle) != 1) {
|
||||
mCamParam.mManualMode = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
sp0F = (this->*engine_tbl[mCamParam.Algorythmn(mCamStyle)])(mCamStyle);
|
||||
|
||||
field_0x170++;
|
||||
@@ -1487,7 +1481,7 @@ void dCamera_c::CalcTrimSize() {
|
||||
mTrimHeight += -mTrimHeight * 0.25f;
|
||||
break;
|
||||
case 2:
|
||||
#if !TARGET_PC && WIDESCREEN_SUPPORT
|
||||
#if WIDESCREEN_SUPPORT
|
||||
if (mDoGph_gInf_c::isWide() && mDoGph_gInf_c::isWideZoom()) {
|
||||
mTrimHeight += (16.0f - mTrimHeight) * 0.25f;
|
||||
break;
|
||||
@@ -3095,6 +3089,10 @@ bool dCamera_c::bumpCheck(u32 i_flags) {
|
||||
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);
|
||||
center += vec3.norm() * (tmp * globe.V().Sin());
|
||||
cSGlobe globe2(vec2 - center);
|
||||
@@ -3108,6 +3106,10 @@ bool dCamera_c::bumpCheck(u32 i_flags) {
|
||||
vec = lin_chk1.GetCross();
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
if (mCamSetup.CheckFlag(0x8000)) {
|
||||
dDbVw_Report(20, 235, " U");
|
||||
@@ -3518,6 +3520,12 @@ void dCamera_c::checkGroundInfo() {
|
||||
}
|
||||
|
||||
bool dCamera_c::chaseCamera(s32 param_0) {
|
||||
#if TARGET_PC
|
||||
if (freeCamera()) {
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
static f32 JumpCushion = 0.9f;
|
||||
f32 charge_latitude = mCamSetup.ChargeLatitude();
|
||||
int charge_timer = mCamSetup.ChargeTimer();
|
||||
@@ -4199,11 +4207,6 @@ bool dCamera_c::chaseCamera(s32 param_0) {
|
||||
chase->field_0x8 -= chase->field_0xc;
|
||||
chase->field_0x8c = 0;
|
||||
chase->field_0x90 = false;
|
||||
|
||||
#if TARGET_PC
|
||||
freeCamera();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -4641,11 +4644,6 @@ bool dCamera_c::chaseCamera(s32 param_0) {
|
||||
if (chase->field_0x1c != 0) {
|
||||
chase->field_0x1c--;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
freeCamera();
|
||||
#endif
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -7093,12 +7091,10 @@ bool dCamera_c::subjectCamera(s32 param_0) {
|
||||
cXyz sp1E0(val0, val2, val1);
|
||||
|
||||
#if TARGET_PC
|
||||
if (sp13) {
|
||||
f32 aspect = mDoGph_gInf_c::getAspect();
|
||||
f32 baseAspect = FB_WIDTH / FB_HEIGHT;
|
||||
if (aspect > baseAspect) {
|
||||
sp1E0.z += (aspect - baseAspect) * 4;
|
||||
}
|
||||
f32 aspect = mDoGph_gInf_c::getAspect();
|
||||
f32 baseAspect = FB_WIDTH / FB_HEIGHT;
|
||||
if (aspect > baseAspect) {
|
||||
sp1E0.z += (aspect - baseAspect) * 4;
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -7476,47 +7472,52 @@ bool dCamera_c::test2Camera(s32 param_0) {
|
||||
|
||||
#if TARGET_PC
|
||||
bool dCamera_c::freeCamera() {
|
||||
if (dusk::getSettings().game.freeCamera && mGear == 1) {
|
||||
mGear = 0;
|
||||
}
|
||||
|
||||
if (!dusk::getSettings().game.freeCamera || mCamStyle == 70)
|
||||
{
|
||||
if (!dusk::getSettings().game.freeCamera) {
|
||||
mCamParam.mManualMode = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!mCamParam.mManualMode) {
|
||||
mCamParam.freeXAngle = mViewCache.mDirection.mAzimuth.Degree();
|
||||
mCamParam.freeYAngle = mViewCache.mDirection.mInclination.Degree();
|
||||
}
|
||||
mCamParam.freeXAngle = mViewCache.mDirection.mAzimuth.Degree();
|
||||
mCamParam.freeYAngle = mViewCache.mDirection.mInclination.Degree();
|
||||
|
||||
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);
|
||||
|
||||
if (mPadInfo.mCStick.mLastPosX != 0 || mPadInfo.mCStick.mLastPosY != 0) {
|
||||
mCamParam.mManualMode = 1;
|
||||
if (!mCamParam.mManualMode) {
|
||||
mCamParam.mManualMode = 1;
|
||||
mCamParam.freeXAngle = mViewCache.mDirection.mAzimuth.Degree();
|
||||
mCamParam.freeYAngle = mViewCache.mDirection.mInclination.Degree();
|
||||
}
|
||||
|
||||
camMovement = camMovement.normalize();
|
||||
camMovement.y *= dusk::getSettings().game.invertCameraYAxis ? 1.0f : -1.0f;
|
||||
mCamParam.freeXAngle += camMovement.x * magnitude * dusk::getSettings().game.freeCameraSensitivity * 5.0f;
|
||||
mCamParam.freeYAngle += camMovement.y * magnitude * dusk::getSettings().game.freeCameraSensitivity * 5.0f;
|
||||
mCamParam.freeXAngle += camMovement.x * magnitude * dusk::getSettings().game.freeCameraSensitivity * 4.0f;
|
||||
mCamParam.freeYAngle += camMovement.y * magnitude * dusk::getSettings().game.freeCameraSensitivity * 4.0f;
|
||||
}
|
||||
|
||||
fopAc_ac_c* player = dComIfGp_getPlayer(0);
|
||||
if (!mCamParam.mManualMode || player == nullptr) {
|
||||
if (!mCamParam.mManualMode) {
|
||||
return false;
|
||||
}
|
||||
|
||||
f32 minYAngle = -30.0f;
|
||||
f32 minYAngle = -10.0f;
|
||||
f32 maxAngle = 50.0f;
|
||||
|
||||
mCamParam.freeYAngle = std::clamp(mCamParam.freeYAngle, minYAngle, maxAngle);
|
||||
mViewCache.mDirection.mAzimuth = cSAngle(mCamParam.freeXAngle);
|
||||
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.mFovy = 60.0f;
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
@@ -11160,25 +11161,12 @@ static int camera_draw(camera_process_class* i_this) {
|
||||
}
|
||||
#endif
|
||||
|
||||
int trim_height = body->TrimHeight();
|
||||
|
||||
#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;
|
||||
window->setScissor(0.0f, trim_height, viewport->width, viewport->height - trim_height * 2.0f);
|
||||
#else
|
||||
int trim_height = body->TrimHeight();
|
||||
|
||||
window->setScissor(0.0f, trim_height, FB_WIDTH, FB_HEIGHT - trim_height * 2.0f);
|
||||
#endif
|
||||
|
||||
|
||||
+9
-45
@@ -22,10 +22,6 @@
|
||||
#include "dusk/frame_interpolation.h"
|
||||
#include "dusk/gx_helper.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
|
||||
|
||||
class dDlst_2Dm_c {
|
||||
@@ -1066,15 +1062,7 @@ void dDlst_shadowReal_c::reset() {
|
||||
}
|
||||
|
||||
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);
|
||||
J3DModelData* model_data;
|
||||
J3DModel** models = mpModels;
|
||||
@@ -1087,15 +1075,7 @@ void dDlst_shadowReal_c::imageDraw(Mtx param_0) {
|
||||
for (u16 j = 0; j < model_data->getShapeNum(); j++) {
|
||||
if (!model_data->getShapeNodePointer(j)->checkFlag(1)) {
|
||||
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->setBaseMtxPtr((Mtx*)param_0);
|
||||
}
|
||||
@@ -1116,18 +1096,7 @@ void dDlst_shadowReal_c::draw() {
|
||||
GXSetVtxDesc(GX_VA_POS, GX_DIRECT);
|
||||
GXSetVtxAttrFmt(GX_VTXFMT0, GX_VA_POS, GX_POS_XYZ, GX_F32, 0);
|
||||
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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
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);
|
||||
|
||||
#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);
|
||||
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);
|
||||
|
||||
if (!field_0x1) {
|
||||
@@ -1412,6 +1370,12 @@ void dDlst_shadowSimple_c::draw() {
|
||||
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,
|
||||
s16 param_4, f32 param_5, TGXTexObj* param_6) {
|
||||
if (param_5 < 0.0f) {
|
||||
|
||||
@@ -78,7 +78,14 @@ void dEyeHL_mng_c::remove(dEyeHL_c* i_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;
|
||||
}
|
||||
#else
|
||||
i_obj->m_timg->LODBias = i_obj->m_lodBias;
|
||||
#endif
|
||||
i_obj->m_timg = NULL;
|
||||
i_obj->m_pre = NULL;
|
||||
i_obj->m_next = NULL;
|
||||
|
||||
+1
-2
@@ -6,7 +6,6 @@
|
||||
#include "d/dolzel.h" // IWYU pragma: keep
|
||||
|
||||
#include "d/d_k_wmark.h"
|
||||
#include "dusk/memory.h"
|
||||
#include "JSystem/J3DGraphBase/J3DMaterial.h"
|
||||
#include "SSystem/SComponent/c_math.h"
|
||||
#include "d/actor/d_a_player.h"
|
||||
@@ -34,7 +33,7 @@ int dkWmark_c::create() {
|
||||
mColorType = this->parameters;
|
||||
}
|
||||
|
||||
mpHeap = mDoExt_createSolidHeapFromGameToCurrent(HEAP_SIZE(0x880, 0x1100), 0x20);
|
||||
mpHeap = mDoExt_createSolidHeapFromGameToCurrent(0x880, 0x20);
|
||||
if (mpHeap != NULL) {
|
||||
JKRHEAP_NAME(mpHeap, "dkWmark_c::mpHeap");
|
||||
J3DModelData* modelData = (J3DModelData*)dComIfG_getObjectRes("Alink", 0x23);
|
||||
|
||||
+1
-2
@@ -1,7 +1,6 @@
|
||||
#include "d/dolzel.h" // IWYU pragma: keep
|
||||
|
||||
#include "d/d_kankyo.h"
|
||||
#include "dusk/memory.h"
|
||||
#ifdef __REVOLUTION_SDK__
|
||||
#include <revolution.h>
|
||||
#else
|
||||
@@ -1186,7 +1185,7 @@ static void undwater_init() {
|
||||
J3DModelData* modelData2 = (J3DModelData*)dComIfG_getObjectRes("Always", 0x1D);
|
||||
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");
|
||||
|
||||
if (g_env_light.undwater_ef_heap != NULL) {
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
#ifdef TARGET_PC
|
||||
constexpr u16 kMapResolutionMultiplier = 4;
|
||||
constexpr u16 kMapCircleSize = 16 * kMapResolutionMultiplier;
|
||||
#endif
|
||||
|
||||
void dMpath_n::dTexObjAggregate_c::create() {
|
||||
@@ -33,48 +32,6 @@ void dMpath_n::dTexObjAggregate_c::create() {
|
||||
JUT_ASSERT(74, image->magFilter == GX_NEAR);
|
||||
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() {
|
||||
|
||||
@@ -856,46 +856,7 @@ void dMenu_DmapBg_c::decGoldFrameAlphaRate() {
|
||||
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() {
|
||||
#if TARGET_PC
|
||||
dMapBgWide();
|
||||
#endif
|
||||
|
||||
u32 scissor_left;
|
||||
u32 scissor_top;
|
||||
u32 scissor_width;
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "d/d_msg_object.h"
|
||||
#include "d/d_msg_scrn_explain.h"
|
||||
#include "d/d_stage.h"
|
||||
#include "dusk/memory.h"
|
||||
#include "f_op/f_op_msg_mng.h"
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
mpTalkHeap = JKRCreateExpHeap(HEAP_SIZE(0x32000, 0x40000), mpHeap, false);
|
||||
mpTalkHeap = JKRCreateExpHeap(0x32000, mpHeap, false);
|
||||
JUT_ASSERT(359, mpTalkHeap != NULL);
|
||||
JKRHEAP_NAME(mpTalkHeap, "dMenu_Fmap_c::mpTalkHeap");
|
||||
field_0x200 = 0;
|
||||
|
||||
+1
-34
@@ -20,15 +20,6 @@
|
||||
#include "dusk/frame_interpolation.h"
|
||||
#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() {
|
||||
dMeter2Info_setMapDrugFlag(0);
|
||||
|
||||
@@ -276,10 +267,6 @@ dMenu_Fmap2DBack_c::~dMenu_Fmap2DBack_c() {
|
||||
}
|
||||
|
||||
void dMenu_Fmap2DBack_c::draw() {
|
||||
#if TARGET_PC
|
||||
fMapBackWide();
|
||||
#endif
|
||||
|
||||
calcBlink();
|
||||
|
||||
J2DGrafContext* grafPort = dComIfGp_getCurrentGrafPort();
|
||||
@@ -1212,7 +1199,7 @@ f32 dMenu_Fmap2DBack_c::getMapScissorAreaSizeX() {
|
||||
}
|
||||
|
||||
f32 dMenu_Fmap2DBack_c::getMapScissorAreaSizeRealX() {
|
||||
#if PLATFORM_GCN
|
||||
#if PLATFORM_GCN && !TARGET_PC
|
||||
return getMapScissorAreaSizeX();
|
||||
#else
|
||||
return getMapScissorAreaSizeX() * mDoGph_gInf_c::getScale();
|
||||
@@ -1420,11 +1407,6 @@ void dMenu_Fmap2DBack_c::stageTextureDraw() {
|
||||
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(),
|
||||
getMapScissorAreaSizeRealX(), getMapScissorAreaSizeRealY(), false, false,
|
||||
false);
|
||||
@@ -2197,17 +2179,6 @@ void dMenu_Fmap2DBack_c::setArrowPosAxis(f32 i_posX, f32 i_posZ) {
|
||||
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) {
|
||||
mpHeap = i_heap;
|
||||
mTransX = 0.0f;
|
||||
@@ -2601,10 +2572,6 @@ void dMenu_Fmap2DTop_c::setAllAlphaRate(f32 i_rate, bool i_init) {
|
||||
}
|
||||
|
||||
void dMenu_Fmap2DTop_c::draw() {
|
||||
#if TARGET_PC
|
||||
fMapTopWide();
|
||||
#endif
|
||||
|
||||
u32 scissor_left, scissor_top, scissor_width, scissor_height;
|
||||
J2DOrthoGraph* ctx = static_cast<J2DOrthoGraph*>(dComIfGp_getCurrentGrafPort());
|
||||
ctx->setup2D();
|
||||
|
||||
@@ -17,10 +17,6 @@
|
||||
#include "d/d_msg_scrn_arrow.h"
|
||||
#include "d/d_lib.h"
|
||||
|
||||
#ifdef TARGET_PC
|
||||
#include "dusk/achievements.h"
|
||||
#endif
|
||||
|
||||
#if VERSION == VERSION_GCN_JPN
|
||||
#define D_MENU_LETTER_LINE_MAX 9
|
||||
#else
|
||||
@@ -518,10 +514,6 @@ void dMenu_Letter_c::read_open_init() {
|
||||
setAButtonString(0);
|
||||
setBButtonString(0);
|
||||
mpBlackTex->setAlpha(0);
|
||||
|
||||
#ifdef TARGET_PC
|
||||
dusk::AchievementSystem::get().signal("open_letter");
|
||||
#endif
|
||||
}
|
||||
|
||||
void dMenu_Letter_c::read_open_move() {
|
||||
|
||||
+3
-7
@@ -24,16 +24,12 @@
|
||||
#include "d/actor/d_a_horse.h"
|
||||
#include <cstring>
|
||||
|
||||
#include "dusk/memory.h"
|
||||
|
||||
#include "dusk/memory.h"
|
||||
|
||||
int dMeter2_c::_create() {
|
||||
stage_stag_info_class* stag_info = dComIfGp_getStageStagInfo();
|
||||
if (dStage_stagInfo_GetUpButton(stag_info) == 1) {
|
||||
mpHeap = fopMsgM_createExpHeap(HEAP_SIZE(0x5A400, 0xA0000), NULL);
|
||||
mpHeap = fopMsgM_createExpHeap(0x5A400, NULL);
|
||||
} else {
|
||||
mpHeap = fopMsgM_createExpHeap(HEAP_SIZE(0x60800, 0xC1000), NULL);
|
||||
mpHeap = fopMsgM_createExpHeap(0x60800, NULL);
|
||||
}
|
||||
JKRHEAP_NAME(mpHeap, "dMeter2_c");
|
||||
|
||||
@@ -236,7 +232,7 @@ int dMeter2_c::_create() {
|
||||
dMeter2Info_setMeterMapClass(mpMap);
|
||||
|
||||
mpHeap->getTotalFreeSize();
|
||||
mpSubHeap = fopMsgM_createExpHeap(HEAP_SIZE(0x5000, 0x6500), mpHeap);
|
||||
mpSubHeap = fopMsgM_createExpHeap(0x5000, mpHeap);
|
||||
JKRHEAP_NAME(mpSubHeap, "dMeter2_c mpSubHeap");
|
||||
field_0x108 = NULL;
|
||||
mpSubContents = NULL;
|
||||
|
||||
@@ -2306,10 +2306,6 @@ void dMeter_drawHIO_c::updateOnWide() {
|
||||
// River Canoe Minigame
|
||||
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]);
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
|
||||
@@ -1987,6 +1987,13 @@ bool jmessage_tSequenceProcessor::do_isReady() {
|
||||
}
|
||||
#endif
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.instantText && mDoCPd_c::getHoldB(0)) {
|
||||
field_0xb2 = 1;
|
||||
pReference->setSendTimer(0);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dComIfGp_checkMesgBgm()) {
|
||||
bool isItemMusicPlaying = true;
|
||||
if (mDoAud_checkPlayingSubBgmFlag() != Z2BGM_ITEM_GET &&
|
||||
@@ -2059,7 +2066,7 @@ bool jmessage_tSequenceProcessor::do_isReady() {
|
||||
case 0:
|
||||
case 5:
|
||||
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;
|
||||
pReference->onBatchFlag();
|
||||
pReference->setCharCnt(D_MSG_CLASS_CHAR_CNT_MAX);
|
||||
|
||||
+1
-38
@@ -32,9 +32,6 @@
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/settings.h"
|
||||
#include <vector>
|
||||
#include <array>
|
||||
#include <algorithm>
|
||||
#endif
|
||||
|
||||
static void dMsgObject_addFundRaising(s16 param_0);
|
||||
@@ -1597,7 +1594,7 @@ u8 dMsgObject_c::isSend() {
|
||||
return 2;
|
||||
}
|
||||
} 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) {
|
||||
return 2;
|
||||
}
|
||||
@@ -1869,40 +1866,6 @@ bool dMsgObject_c::isTalkMessage() {
|
||||
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() {
|
||||
JMSMesgInfo_c* info_header_p = (JMSMesgInfo_c*)((char*)mpMsgRes + 0x20);
|
||||
char* data_ptr = (char*)info_header_p + info_header_p->header.size;
|
||||
|
||||
+18
-6
@@ -36,15 +36,27 @@ dRes_info_c::dRes_info_c() {
|
||||
|
||||
dRes_info_c::~dRes_info_c() {
|
||||
if (mDMCommand != NULL) {
|
||||
mDMCommand->destroy();
|
||||
#if TARGET_PC
|
||||
if (JKRHeap::findFromRoot(mDMCommand) != nullptr) {
|
||||
#endif
|
||||
mDMCommand->destroy();
|
||||
#if TARGET_PC
|
||||
}
|
||||
#endif
|
||||
mDMCommand = NULL;
|
||||
} else if (mArchive != NULL) {
|
||||
deleteArchiveRes();
|
||||
if (mDataHeap != NULL) {
|
||||
mDoExt_destroySolidHeap(mDataHeap);
|
||||
mDataHeap = NULL;
|
||||
mArchive->unmount();
|
||||
#if TARGET_PC
|
||||
if (JKRHeap::findFromRoot(mArchive) != nullptr) {
|
||||
#endif
|
||||
deleteArchiveRes();
|
||||
if (mDataHeap != NULL) {
|
||||
mDoExt_destroySolidHeap(mDataHeap);
|
||||
mDataHeap = NULL;
|
||||
mArchive->unmount();
|
||||
}
|
||||
#if TARGET_PC
|
||||
}
|
||||
#endif
|
||||
mRes = NULL;
|
||||
mArchive = NULL;
|
||||
}
|
||||
|
||||
+1
-2
@@ -10,7 +10,6 @@
|
||||
#include "d/d_meter2_info.h"
|
||||
#include "d/d_s_name.h"
|
||||
#include "dusk/imgui/ImGuiConsole.hpp"
|
||||
#include "dusk/memory.h"
|
||||
#include "dusk/settings.h"
|
||||
#include "f_op/f_op_overlap_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() {
|
||||
int phase_state = resLoad(&phase, "fileSel");
|
||||
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);
|
||||
JKRHEAP_NAME(mHeap, "File select");
|
||||
|
||||
|
||||
+2
-25
@@ -39,11 +39,6 @@
|
||||
#include "JSystem/JKernel/JKRAram.h"
|
||||
#include "JSystem/JKernel/JKRAramArchive.h"
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/memory.h"
|
||||
#include <dusk/autosave.h>
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
#include "d/d_s_menu.h"
|
||||
#include "d/d_debug_pad.h"
|
||||
@@ -701,10 +696,6 @@ static u8 lbl_8074CAE4;
|
||||
static u32 l_sceneChangeStartTick;
|
||||
#endif
|
||||
|
||||
#if TARGET_PC
|
||||
static BOOL autoSaved;
|
||||
#endif
|
||||
|
||||
static int dScnPly_Execute(dScnPly_c* i_this) {
|
||||
#if DEBUG
|
||||
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();
|
||||
|
||||
#if DEBUG
|
||||
@@ -1438,7 +1420,7 @@ static int phase_4(dScnPly_c* i_this) {
|
||||
dComIfGd_setViewport(NULL);
|
||||
dComIfGd_setView(NULL);
|
||||
|
||||
JKRExpHeap* heap = fopMsgM_createExpHeap(HEAP_SIZE(0xBB800, 0x177000), NULL);
|
||||
JKRExpHeap* heap = fopMsgM_createExpHeap(0xBB800, NULL);
|
||||
#if TARGET_PC
|
||||
heap->setName("Scene2DHeap");
|
||||
#endif
|
||||
@@ -1446,7 +1428,7 @@ static int phase_4(dScnPly_c* i_this) {
|
||||
JUT_ASSERT(2704, heap != NULL);
|
||||
dComIfGp_setExpHeap2D(heap);
|
||||
|
||||
JKRExpHeap* heap2 = fopMsgM_createExpHeap(HEAP_SIZE(0xA800, 0x15000), NULL);
|
||||
JKRExpHeap* heap2 = fopMsgM_createExpHeap(0xA800, NULL);
|
||||
#if TARGET_PC
|
||||
heap2->setName("SceneMsgHeap");
|
||||
#endif
|
||||
@@ -1607,11 +1589,6 @@ static int dScnPly_Create(scene_class* i_this) {
|
||||
|
||||
dScnPly_c* a_this = (dScnPly_c*)i_this;
|
||||
int phase_state = dComLbG_PhaseHandler(&a_this->field_0x1c4, l_method, a_this);
|
||||
|
||||
#if TARGET_PC
|
||||
autoSaved = FALSE;
|
||||
#endif
|
||||
|
||||
return phase_state;
|
||||
}
|
||||
|
||||
|
||||
@@ -27,11 +27,7 @@
|
||||
#include "lingcod/lingcod.h"
|
||||
#endif
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/settings.h"
|
||||
#include <f_ap/f_ap_game.h>
|
||||
#include <dusk/autosave.h>
|
||||
#endif
|
||||
|
||||
static u8 dSv_item_rename(u8 i_itemNo) {
|
||||
switch (i_itemNo) {
|
||||
@@ -349,10 +345,6 @@ void dSv_player_item_c::setItem(int i_slotNo, u8 i_itemNo) {
|
||||
dComIfGp_setSelectItem(i);
|
||||
}
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
triggerAutoSave();
|
||||
#endif
|
||||
}
|
||||
|
||||
u8 dSv_player_item_c::getItem(int i_slotNo, bool i_checkCombo) const {
|
||||
|
||||
@@ -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
@@ -8,7 +8,6 @@
|
||||
#include "d/actor/d_a_player.h"
|
||||
#include "d/d_demo.h"
|
||||
#include "f_pc/f_pc_name.h"
|
||||
#include "f_op/f_op_actor_mng.h"
|
||||
|
||||
#include <filesystem>
|
||||
#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",
|
||||
@@ -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",
|
||||
@@ -335,13 +267,18 @@ std::vector<AchievementSystem::Entry> AchievementSystem::makeEntries() {
|
||||
false, 0, 0, false
|
||||
},
|
||||
[](Achievement& a, json&) {
|
||||
static int titleNoDemoFrames = 0;
|
||||
if (fopAcM_SearchByName(fpcNm_TITLE_e) == nullptr) {
|
||||
titleNoDemoFrames = 0;
|
||||
return;
|
||||
}
|
||||
const auto* player = static_cast<const daPy_py_c*>(daPy_getPlayerActorClass());
|
||||
|
||||
if (player != nullptr && player->mDemo.getDemoMode() == 1) {
|
||||
const auto* link = static_cast<const daAlink_c*>(daPy_getPlayerActorClass());
|
||||
if (link != nullptr && dDemo_c::getMode() == 0) {
|
||||
if (++titleNoDemoFrames >= 60) {
|
||||
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();
|
||||
}
|
||||
|
||||
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) {
|
||||
if (e.achievement.unlocked) {
|
||||
return;
|
||||
@@ -576,7 +458,6 @@ void AchievementSystem::tick() {
|
||||
for (auto& e : m_entries) {
|
||||
processEntry(e);
|
||||
}
|
||||
m_signals.clear();
|
||||
if (m_dirty) {
|
||||
save();
|
||||
m_dirty = false;
|
||||
|
||||
@@ -48,20 +48,6 @@ f32 dusk::audio::MasterVolume = 1.0f;
|
||||
f32 dusk::audio::PrevMasterVolume = 1.0f;
|
||||
bool dusk::audio::EnableReverb = true;
|
||||
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.
|
||||
@@ -297,9 +283,6 @@ void dusk::audio::DspRender(OutputSubframe& subframe) {
|
||||
DspSubframe reverbInputR = {};
|
||||
bool anyReverbInput = false;
|
||||
|
||||
DspSubframe surroundBus = {};
|
||||
bool anySurroundInput = false;
|
||||
|
||||
for (int i = 0; i < channels.size(); i++) {
|
||||
auto& channel = channels[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]) {
|
||||
f32 interleaved[DSP_SUBFRAME_SIZE * 2];
|
||||
for (int j = 0; j < DSP_SUBFRAME_SIZE; j++) {
|
||||
@@ -381,28 +349,6 @@ void dusk::audio::DspRender(OutputSubframe& subframe) {
|
||||
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) {
|
||||
ApplyVolume(channel, channel, PrevMasterVolume, MasterVolume);
|
||||
}
|
||||
|
||||
@@ -133,6 +133,4 @@ namespace dusk::audio {
|
||||
extern f32 PrevMasterVolume;
|
||||
extern bool EnableReverb;
|
||||
extern bool DumpAudio;
|
||||
extern bool EnableHrtf;
|
||||
extern f32 HrtfGain;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
@@ -76,8 +76,8 @@ void ImGuiAchievements::draw(bool& open) {
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(800, 200), ImVec2(1280, 900));
|
||||
ImGui::SetNextWindowSize(ImVec2(800, 480), ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(640, 200), ImVec2(800, 900));
|
||||
ImGui::SetNextWindowSize(ImVec2(640, 480), ImGuiCond_FirstUseEver);
|
||||
|
||||
if (!ImGui::Begin(
|
||||
"Achievements", &open,
|
||||
@@ -111,7 +111,6 @@ void ImGuiAchievements::draw(bool& open) {
|
||||
{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::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)},
|
||||
};
|
||||
|
||||
@@ -132,7 +131,7 @@ void ImGuiAchievements::draw(bool& open) {
|
||||
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);
|
||||
const bool tabOpen = ImGui::BeginTabItem(tabLabel.c_str());
|
||||
@@ -153,7 +152,6 @@ void ImGuiAchievements::draw(bool& open) {
|
||||
continue;
|
||||
}
|
||||
ImGui::PushID(a.key);
|
||||
ImGui::BeginGroup();
|
||||
|
||||
ImGui::PushStyleColor(
|
||||
ImGuiCol_Text,
|
||||
@@ -192,21 +190,6 @@ void ImGuiAchievements::draw(bool& open) {
|
||||
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::PopID();
|
||||
}
|
||||
|
||||
@@ -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,7 +1,5 @@
|
||||
#include "ImGuiConsole.hpp"
|
||||
#include "ImGuiMenuTools.hpp"
|
||||
#include <cmath>
|
||||
#include "JSystem/JAudio2/JAISeq.h"
|
||||
#include "JSystem/JAudio2/JAISeMgr.h"
|
||||
#include "JSystem/JAudio2/JAISeqMgr.h"
|
||||
#include "JSystem/JAudio2/JAIStreamMgr.h"
|
||||
@@ -17,24 +15,6 @@ static std::array<u32, DSP_CHANNELS> lastResetCounts = {};
|
||||
|
||||
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) {
|
||||
using namespace dusk::audio;
|
||||
|
||||
@@ -72,10 +52,8 @@ static void DisplayDspChannel(int i) {
|
||||
auto fxMix = (channel.mAutoMixerFxMix >> 8) / 127.5f;
|
||||
auto volume = VolumeFromU16(channel.mAutoMixerVolume);
|
||||
auto pitch = channel.mPitch / 4096.0f;
|
||||
DrawDirectionGauge(pan, dolby);
|
||||
ImGui::SameLine();
|
||||
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);
|
||||
} else {
|
||||
ImGui::Text(
|
||||
@@ -205,10 +183,6 @@ static void ShowAllJAISes() {
|
||||
if (ImGui::Button("Pause All")) {
|
||||
category->pause(true);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Resume All")) {
|
||||
category->pause(false);
|
||||
}
|
||||
|
||||
for (auto seLink = category->getSeList()->getFirst(); seLink != nullptr; seLink = seLink->getNext()) {
|
||||
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() {
|
||||
auto& mgr = *JAISeqMgr::getInstance();
|
||||
|
||||
@@ -259,26 +206,6 @@ static void ShowAllJAISeqs() {
|
||||
if (ImGui::Button("Unpause")) {
|
||||
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() {
|
||||
|
||||
@@ -324,18 +324,18 @@ namespace dusk {
|
||||
ImGuiMenuGame::ToggleFullscreen();
|
||||
}
|
||||
|
||||
// if (!dusk::IsGameLaunched) {
|
||||
// m_preLaunchWindow.draw();
|
||||
// }
|
||||
if (!dusk::IsGameLaunched) {
|
||||
m_preLaunchWindow.draw();
|
||||
}
|
||||
|
||||
m_isHidden = !getSettings().backend.duskMenuOpen;
|
||||
if (ImGui::GetIO().KeyShift && ImGui::IsKeyPressed(ImGuiKey_F1)) {
|
||||
m_isHidden = !m_isHidden;
|
||||
}
|
||||
bool showMenu = !m_isHidden;
|
||||
if (getSettings().backend.duskMenuOpen != showMenu) {
|
||||
getSettings().backend.duskMenuOpen.setValue(showMenu);
|
||||
Save();
|
||||
bool showMenu = !dusk::IsGameLaunched || !CheckMenuViewToggle(ImGuiKey_F1, m_isHidden);
|
||||
if (dusk::IsGameLaunched) {
|
||||
const bool menuOpen = !m_isHidden;
|
||||
if (getSettings().backend.duskMenuOpen != menuOpen) {
|
||||
getSettings().backend.duskMenuOpen.setValue(menuOpen);
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
// The menu bar renders with ImGuiCol_WindowBg behind it. We just want ImGuiCol_MenuBarBg,
|
||||
@@ -365,10 +365,10 @@ namespace dusk {
|
||||
}
|
||||
|
||||
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 :
|
||||
"Press F1 to toggle menu"s,
|
||||
4.f);
|
||||
2.5f);
|
||||
m_isLaunchInitialized = true;
|
||||
if (getSettings().game.liveSplitEnabled) {
|
||||
dusk::speedrun::connectLiveSplit();
|
||||
@@ -401,6 +401,7 @@ namespace dusk {
|
||||
m_menuTools.ShowAudioDebug();
|
||||
m_menuTools.ShowSaveEditor();
|
||||
m_menuTools.ShowStateShare();
|
||||
m_menuTools.ShowActorSpawner();
|
||||
}
|
||||
m_menuTools.ShowAchievements();
|
||||
DuskDebugPad(); // temporary, remove later
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -44,7 +44,6 @@ static void ApplyPresetDusk() {
|
||||
s.game.enableFrameInterpolation.setValue(true);
|
||||
s.game.sunsSong.setValue(true);
|
||||
s.game.bloomMode.setValue(BloomMode::Dusk);
|
||||
s.game.autoSave.setValue(true);
|
||||
}
|
||||
|
||||
// =========================================================================
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "JSystem/JFramework/JFWSystem.h"
|
||||
#include "JSystem/JKernel/JKRExpHeap.h"
|
||||
#include "JSystem/JKernel/JKRHeap.h"
|
||||
#include "JSystem/JKernel/JKRSolidHeap.h"
|
||||
#include "absl/container/flat_hash_map.h"
|
||||
#include "imgui.h"
|
||||
|
||||
@@ -178,9 +179,9 @@ namespace dusk {
|
||||
}
|
||||
|
||||
void ShowHeapDetailed(JKRHeap* heap, OpenHeapData& data, bool& open) {
|
||||
const char* heapName = data.Safe ? heap->getName() : "INVALID";
|
||||
char title[128];
|
||||
const char* name = data.Safe ? heap->getName() : "INVALID";
|
||||
snprintf(title, sizeof(title), "Heap %s##%p", name, static_cast<const void*>(heap));
|
||||
snprintf(title, sizeof(title), "Heap %s##%p", heapName, static_cast<const void*>(heap));
|
||||
|
||||
if (!ImGui::Begin(title, &open)) {
|
||||
ImGui::End();
|
||||
@@ -195,11 +196,35 @@ namespace dusk {
|
||||
|
||||
heap->lock();
|
||||
|
||||
ImGui::Text("Name: %s", name);
|
||||
ImGui::Text("Name: %s", heap->getName());
|
||||
const auto size = BytesToString(heap->getSize());
|
||||
const auto freeSize = BytesToString(heap->getFreeSize());
|
||||
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")) {
|
||||
data.HeapCheckFailed = !heap->check();
|
||||
data.HeapCheckRan = true;
|
||||
|
||||
@@ -3,13 +3,31 @@
|
||||
|
||||
#include "ImGuiEngine.hpp"
|
||||
#include "ImGuiConsole.hpp"
|
||||
#include "ImGuiMenuGame.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/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 <SDL3/SDL_gamepad.h>
|
||||
namespace {
|
||||
constexpr int kInternalResolutionScaleMax = 12;
|
||||
} // namespace
|
||||
|
||||
namespace aurora::gx {
|
||||
extern bool enableLodBias;
|
||||
}
|
||||
|
||||
namespace dusk {
|
||||
void ImGuiMenuGame::ToggleFullscreen() {
|
||||
@@ -22,17 +40,475 @@ namespace dusk {
|
||||
|
||||
void ImGuiMenuGame::draw() {
|
||||
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")){
|
||||
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::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) {
|
||||
float scale = ImGuiScale();
|
||||
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.instantDeath.setValue(false);
|
||||
getSettings().game.noHeartDrops.setValue(false);
|
||||
getSettings().game.hyperEnemies.setValue(false);
|
||||
|
||||
getSettings().game.infiniteHearts.setValue(false);
|
||||
getSettings().game.infiniteArrows.setValue(false);
|
||||
|
||||
@@ -55,6 +55,13 @@ namespace dusk {
|
||||
static void resetForSpeedrunMode();
|
||||
|
||||
private:
|
||||
void drawAudioMenu();
|
||||
void drawInputMenu();
|
||||
void drawGraphicsMenu();
|
||||
void drawGameplayMenu();
|
||||
void drawCheatsMenu();
|
||||
void drawInterfaceMenu();
|
||||
|
||||
struct {
|
||||
int m_selectedPort = 0;
|
||||
bool m_isReading = false;
|
||||
|
||||
@@ -41,10 +41,6 @@ static void OpenDataFolder() {
|
||||
#define DUSK_CAN_OPEN_DATA_FOLDER 0
|
||||
#endif
|
||||
|
||||
namespace aurora::gx {
|
||||
extern bool enableLodBias;
|
||||
}
|
||||
|
||||
namespace dusk {
|
||||
ImGuiMenuTools::ImGuiMenuTools() {}
|
||||
|
||||
@@ -95,7 +91,6 @@ namespace dusk {
|
||||
getSettings().game.disableWaterRefraction.setValue(disableWaterRefraction);
|
||||
config::Save();
|
||||
}
|
||||
ImGui::Checkbox("Enable LOD Bias", &aurora::gx::enableLodBias);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
|
||||
@@ -124,6 +119,7 @@ namespace dusk {
|
||||
ImGui::MenuItem("Audio Debug", hotkeys::SHOW_AUDIO_DEBUG, &m_showAudioDebug);
|
||||
ImGui::MenuItem("Bloom", nullptr, &m_showBloomWindow);
|
||||
ImGui::MenuItem("Stub Log", nullptr, &m_showStubLog);
|
||||
ImGui::MenuItem("Actor Spawner", nullptr, &m_showActorSpawner);
|
||||
|
||||
if (!dusk::IsGameLaunched) {
|
||||
ImGui::EndDisabled();
|
||||
|
||||
@@ -29,6 +29,7 @@ namespace dusk {
|
||||
void ShowStateShare();
|
||||
void ShowAchievements();
|
||||
void notifyAchievement(std::string name);
|
||||
void ShowActorSpawner();
|
||||
|
||||
private:
|
||||
bool m_showDebugOverlay = false;
|
||||
@@ -71,6 +72,8 @@ namespace dusk {
|
||||
|
||||
bool m_showAchievements = false;
|
||||
ImGuiAchievements m_achievementsWindow;
|
||||
|
||||
bool m_showActorSpawner = false;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include "d/actor/d_a_player.h"
|
||||
|
||||
#include <map>
|
||||
#include <bit>
|
||||
|
||||
namespace dusk {
|
||||
enum ItemType {
|
||||
@@ -1296,33 +1295,8 @@ namespace dusk {
|
||||
membit.offDungeonItem(flag);
|
||||
}
|
||||
}
|
||||
|
||||
static void genCommonAreaFlags(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) {
|
||||
void genMembitFlags(const char* id, dSv_memBit_c& membit) {
|
||||
ImGuiBeginGroupPanel("Chest", { 100, 100 });
|
||||
for (int j = 0; j < 2; 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]);
|
||||
}
|
||||
ImGuiEndGroupPanel();
|
||||
ImVec2 post_item_custor = ImGui::GetCursorPos();
|
||||
|
||||
ImGui::SetCursorPos({post_item_custor.x, post_switch_cursor.y});
|
||||
// genCommonAreaFlags(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);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -1399,326 +1392,74 @@ namespace dusk {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void genAreaFlagTable(uint8_t areaIndex, dSv_memBit_c& membit) {
|
||||
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;
|
||||
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);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
stage_stag_info_class* pstag = dComIfGp_getStageStagInfo();
|
||||
if (pstag != nullptr) {
|
||||
int stageNo = dStage_stagInfo_GetSaveTbl(pstag);
|
||||
if (ImGui::Button("Save##SaveTempFlags")) {
|
||||
dComIfGs_putSave(stageNo);
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Load##LoadSaveFlags")) {
|
||||
dComIfGs_getSave(stageNo);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ImGuiSaveEditor::drawFlagsTab() {
|
||||
if (ImGui::TreeNode("Current Region Flags")) {
|
||||
drawCurrentRegionFlags();
|
||||
dSv_memBit_c& membit = g_dComIfG_gameInfo.info.mMemory.mBit;
|
||||
genMembitFlags("##TempSceneFlags", membit);
|
||||
|
||||
stage_stag_info_class* pstag = dComIfGp_getStageStagInfo();
|
||||
if (pstag != nullptr) {
|
||||
int stageNo = dStage_stagInfo_GetSaveTbl(pstag);
|
||||
if (ImGui::Button("Save##SaveTempFlags")) {
|
||||
dComIfGs_putSave(stageNo);
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Load##LoadSaveFlags")) {
|
||||
dComIfGs_getSave(stageNo);
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode("Region Saved Flags")) {
|
||||
static const std::map<uint8_t, const char*> regionNames = {
|
||||
{ 0x00, "Ordon" },
|
||||
{ 0x01, "Hyrule Sewers" },
|
||||
{ 0x02, "Faron" },
|
||||
{ 0x03, "Eldin" },
|
||||
{ 0x04, "Lanayru" },
|
||||
{ 0x06, "Hyrule Field" },
|
||||
{ 0x07, "Sacred Grove" },
|
||||
{ 0x08, "Snowpeak" },
|
||||
{ 0x09, "Castle Town" },
|
||||
{ 0x0A, "Gerudo Desert" },
|
||||
{ 0x0B, "Fishing Pond" },
|
||||
{ 0x10, "Forest Temple" },
|
||||
{ 0x11, "Goron Mines" },
|
||||
{ 0x12, "Lakebed Temple" },
|
||||
{ 0x13, "Arbiter's Grounds" },
|
||||
{ 0x14, "Snowpeak Ruins" },
|
||||
{ 0x15, "Temple of Time" },
|
||||
{ 0x16, "City in the Sky" },
|
||||
{ 0x17, "Palace of Twilight" },
|
||||
{ 0x18, "Hyrule Castle" },
|
||||
{ 0x19, "Caves" },
|
||||
{ 0x1A, "Lake Hylia Long Cave"},
|
||||
{ 0x1B, "Grottos" }
|
||||
static std::array<const char*, 27> regionNames = {
|
||||
"Ordon",
|
||||
"Hyrule Sewers",
|
||||
"Faron",
|
||||
"Eldin",
|
||||
"Lanayru",
|
||||
"Reserved",
|
||||
"Hyrule Field",
|
||||
"Sacred Grove",
|
||||
"Snowpeak",
|
||||
"Castle Town",
|
||||
"Gerudo Desert",
|
||||
"Fishing Pond",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Reserved",
|
||||
"Forest Temple",
|
||||
"Goron Mines",
|
||||
"Lakebed Temple",
|
||||
"Arbiter's Grounds",
|
||||
"Snowpeak Ruins",
|
||||
"Temple of Time",
|
||||
"City in the Sky",
|
||||
"Palace of Twilight",
|
||||
"Hyrule Castle",
|
||||
"Caves",
|
||||
"Grottos",
|
||||
};
|
||||
|
||||
if (m_selectedRegion.name == nullptr)
|
||||
{
|
||||
const auto& firstRegion = *regionNames.find(0);
|
||||
m_selectedRegion = { firstRegion.first, firstRegion.second };
|
||||
}
|
||||
if (ImGui::BeginCombo("Region", regionNames[m_selectedRegion])) {
|
||||
for (int i = 0; i < regionNames.size(); i++) {
|
||||
if (strcmp(regionNames[i], "Reserved") == 0) continue;
|
||||
|
||||
if (ImGui::BeginCombo("Region", m_selectedRegion.name)) {
|
||||
for (const auto& [id, name] : regionNames) {
|
||||
if (ImGui::Selectable(name)) {
|
||||
m_selectedRegion = {id, name};
|
||||
if (ImGui::Selectable(regionNames[i])) {
|
||||
m_selectedRegion = i;
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
dSv_memBit_c& membit = dComIfGs_getSaveData()->mSave[m_selectedRegion.id].mBit;
|
||||
|
||||
genAreaFlagTable(m_selectedRegion.id, membit);
|
||||
|
||||
if (ImGui::TreeNode("Flag Matrix")) {
|
||||
genMembitFlags("##SaveSceneFlags", membit);
|
||||
|
||||
ImGui::TreePop();
|
||||
dSv_memBit_c* membit = &dComIfGs_getSaveData()->mSave[m_selectedRegion].mBit;
|
||||
if (membit != nullptr) {
|
||||
genMembitFlags("##SaveSceneFlags", *membit);
|
||||
}
|
||||
|
||||
ImGui::TreePop();
|
||||
@@ -1789,9 +1530,7 @@ namespace dusk {
|
||||
}
|
||||
|
||||
for (const auto& e : duskImguiEventFlags) {
|
||||
if (!filter.PassFilter(e.location.c_str()) &&
|
||||
!filter.PassFilter(e.description.c_str()) &&
|
||||
!filter.PassFilter(e.flagName.c_str()))
|
||||
if (!filter.PassFilter((e.location + "\n" + e.description + "\n" + e.flagName).c_str()))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -21,10 +21,7 @@ namespace dusk {
|
||||
void drawConfigTab();
|
||||
|
||||
private:
|
||||
struct {
|
||||
uint8_t id;
|
||||
const char* name;
|
||||
} m_selectedRegion = {0, nullptr};
|
||||
int m_selectedRegion = 0;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -101,10 +101,6 @@ ValidationError validate(const char* path) {
|
||||
NodHandleWrapper disc;
|
||||
|
||||
const auto sdlStream = SDL_IOFromFile(path, "rb");
|
||||
if (sdlStream == nullptr) {
|
||||
return ValidationError::IOError;
|
||||
}
|
||||
|
||||
const NodDiscStream nod_stream {
|
||||
.user_data = sdlStream,
|
||||
.read_at = StreamReadAt,
|
||||
|
||||
+21
-48
@@ -1,6 +1,5 @@
|
||||
#include "dusk/logging.h"
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstdio>
|
||||
#include <cstdlib>
|
||||
@@ -33,33 +32,9 @@ static constexpr std::string_view StubFragments[] = {
|
||||
};
|
||||
|
||||
namespace {
|
||||
// On macOS, std::mutex becomes poisoned when its dtor is run.
|
||||
// We use this to check if the LogState is destroyed before attempting to acquire it.
|
||||
std::atomic g_logStateAlive(true);
|
||||
|
||||
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;
|
||||
std::mutex g_logMutex;
|
||||
FILE* g_logFile = nullptr;
|
||||
std::string g_logFilePath;
|
||||
|
||||
const char* LogLevelString(AuroraLogLevel level) {
|
||||
switch (level) {
|
||||
@@ -177,10 +152,10 @@ void aurora_log_callback(AuroraLogLevel level, const char* module, const char* m
|
||||
FILE* out = LogStreamForLevel(level);
|
||||
WriteLogLine(out, levelStr, module, message, len);
|
||||
|
||||
if (g_logStateAlive.load(std::memory_order_acquire)) {
|
||||
std::lock_guard lock(g_logState.mutex);
|
||||
if (g_logState.file != nullptr) {
|
||||
WriteLogLine(g_logState.file, levelStr, module, message, len);
|
||||
{
|
||||
std::lock_guard lock(g_logMutex);
|
||||
if (g_logFile != nullptr) {
|
||||
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");
|
||||
|
||||
void dusk::InitializeFileLogging(const std::filesystem::path& configDir, AuroraLogLevel logLevel) {
|
||||
if (!g_logStateAlive.load(std::memory_order_acquire)) {
|
||||
return;
|
||||
}
|
||||
std::lock_guard lock(g_logState.mutex);
|
||||
if (g_logState.file != nullptr || configDir.empty()) {
|
||||
std::lock_guard lock(g_logMutex);
|
||||
if (g_logFile != nullptr || configDir.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -212,30 +184,31 @@ void dusk::InitializeFileLogging(const std::filesystem::path& configDir, AuroraL
|
||||
}
|
||||
|
||||
const std::filesystem::path logPath = logsDir / MakeTimestampedLogName();
|
||||
g_logState.file = std::fopen(logPath.string().c_str(), "wb");
|
||||
if (g_logState.file == nullptr) {
|
||||
g_logFile = std::fopen(logPath.string().c_str(), "wb");
|
||||
if (g_logFile == nullptr) {
|
||||
std::fprintf(stderr, "[WARNING | dusk] Failed to open log file '%s'\n",
|
||||
logPath.string().c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
g_logState.filePath = logPath.string();
|
||||
g_logFilePath = logPath.string();
|
||||
aurora::g_config.logCallback = &aurora_log_callback;
|
||||
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() {
|
||||
if (!g_logStateAlive.load(std::memory_order_acquire)) {
|
||||
std::lock_guard lock(g_logMutex);
|
||||
if (g_logFile == nullptr) {
|
||||
return;
|
||||
}
|
||||
g_logState.CloseFile();
|
||||
|
||||
std::fflush(g_logFile);
|
||||
std::fclose(g_logFile);
|
||||
g_logFile = nullptr;
|
||||
}
|
||||
|
||||
const char* dusk::GetLogFilePath() {
|
||||
if (!g_logStateAlive.load(std::memory_order_acquire)) {
|
||||
return nullptr;
|
||||
}
|
||||
std::lock_guard lock(g_logState.mutex);
|
||||
return g_logState.filePath.empty() ? nullptr : g_logState.filePath.c_str();
|
||||
std::lock_guard lock(g_logMutex);
|
||||
return g_logFilePath.empty() ? nullptr : g_logFilePath.c_str();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@ UserSettings g_userSettings = {
|
||||
.soundEffectsVolume {"audio.soundEffectsVolume", 100},
|
||||
.fanfareVolume {"audio.fanfareVolume", 100},
|
||||
.enableReverb {"audio.enableReverb", true},
|
||||
.enableHrtf {"audio.enableHrtf", false},
|
||||
},
|
||||
|
||||
.game = {
|
||||
@@ -32,8 +31,7 @@ UserSettings g_userSettings = {
|
||||
.disableRupeeCutscenes {"game.disableRupeeCutscenes", false},
|
||||
.noSwordRecoil {"game.noSwordRecoil", false},
|
||||
.damageMultiplier {"game.damageMultiplier", 1},
|
||||
.hyperEnemies {"game.hyperEnemies", false},
|
||||
.noHeartDrops {"game.noHeartDrops", false},
|
||||
.noHeartDrops{"game.noHeartDrops", false},
|
||||
.instantDeath {"game.instantDeath", false},
|
||||
.fastClimbing {"game.fastClimbing", false},
|
||||
.noMissClimbing {"game.noMissClimbing", false},
|
||||
@@ -42,7 +40,6 @@ UserSettings g_userSettings = {
|
||||
.instantSaves {"game.instantSaves", false},
|
||||
.instantText {"game.instantText", false},
|
||||
.sunsSong {"game.sunsSong", false},
|
||||
.autoSave {"game.autoSave", false},
|
||||
|
||||
// Preferences
|
||||
.enableMirrorMode {"game.enableMirrorMode", false},
|
||||
@@ -55,7 +52,7 @@ UserSettings g_userSettings = {
|
||||
.bloomMode {"game.bloomMode", BloomMode::Classic},
|
||||
.bloomMultiplier {"game.bloomMultiplier", 1.0f},
|
||||
.disableWaterRefraction {"game.disableWaterRefraction", false},
|
||||
.enableFrameInterpolation {"game.enableFrameInterpolation", false},
|
||||
.enableFrameInterpolation = {"game.enableFrameInterpolation", false},
|
||||
.internalResolutionScale {"game.internalResolutionScale", 0},
|
||||
.shadowResolutionMultiplier {"game.shadowResolutionMultiplier", 1},
|
||||
.enableDepthOfField {"game.enableDepthOfField", true},
|
||||
@@ -136,7 +133,6 @@ void registerSettings() {
|
||||
Register(g_userSettings.audio.soundEffectsVolume);
|
||||
Register(g_userSettings.audio.fanfareVolume);
|
||||
Register(g_userSettings.audio.enableReverb);
|
||||
Register(g_userSettings.audio.enableHrtf);
|
||||
|
||||
// Game
|
||||
Register(g_userSettings.game.language);
|
||||
@@ -148,7 +144,6 @@ void registerSettings() {
|
||||
Register(g_userSettings.game.disableRupeeCutscenes);
|
||||
Register(g_userSettings.game.noSwordRecoil);
|
||||
Register(g_userSettings.game.damageMultiplier);
|
||||
Register(g_userSettings.game.hyperEnemies);
|
||||
Register(g_userSettings.game.noHeartDrops);
|
||||
Register(g_userSettings.game.instantDeath);
|
||||
Register(g_userSettings.game.fastClimbing);
|
||||
@@ -157,7 +152,6 @@ void registerSettings() {
|
||||
Register(g_userSettings.game.instantSaves);
|
||||
Register(g_userSettings.game.instantText);
|
||||
Register(g_userSettings.game.sunsSong);
|
||||
Register(g_userSettings.game.autoSave);
|
||||
Register(g_userSettings.game.enableMirrorMode);
|
||||
Register(g_userSettings.game.invertCameraXAxis);
|
||||
Register(g_userSettings.game.invertCameraYAxis);
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
Reference in New Issue
Block a user