Ongoing gameplay dev (#49)

* launch.json cwd

* bodge to load gci for testing

* stub card stat

* gameplay bodges

* viewport, ub fixes

* add release with debug info cmake variant

* be fixes, sound stub

* viewport h

* d_msg_flow BE

* be fopAcM_createItemFromEnemyID

* update launch configuration to use iso

* more audio stubs

* Attempt to set viewport and get messages for brightness check

* skip opening scene again, fixed JMessage::TResourceContainer::TCResource::Do_destroy

* add guards for viewport changes

* moar endian swapping to get Link sitting in PROC_OPENING_SCENE and for dialogues

* BE d_msg_class i_data

* stub bgm start

* fix div by 0 error (for now)

* TEMP_BROKEN in d_menu_ring

* REQUIRES_GX_LINES

* properly stub renderingAmap::draw with REQUIRES_GX_LINES

* better stubbing outside of stubs

* fix event data getting swapped multiple times

* evil draw vp fix

* Stub log imgui

This redirects all spammy logs to an imgui window that is cleared per frame.

This fixes the serious performance dip of the logging, and makes the regular log readable.

* Oops move those optimization changes I accidentally committed behind a flag

DUSK_SELECTED_OPT

* gx_line macro in map

* fix audio stubbing

* switch to CARD API aurora impl

* remove kabufuda from link libs

* refactor imgui stuff and add input viewer

* merge stub log with refactor

* accidentally committed a metaforce header shh

* basic map loader

* ImGuiConsole: Add missing <thread> include

* you may now play as luigi (you may now load stages with bridges)

* bloom fix

* bloom leak fix

* cloud shadow fix

* add soft reset button to imgui menu

* if it broke dont not fix it

* i swear i committed this

* BE swap indMtx in JPAResource::setPTev

* wnark ct fix

* frsqrte implementation from kinoko

* Fix Clang compile error in JAISeq::prepare_getSeqData_

* Add endian conversions to dMsgFlow_c::getInitNodeIndex

This fixes a freeze when Fado tries to stop you from leaving the
starting area.

* Add RAII GXTexObj wrapper; fix almost all leaks

* Update aurora for indirect texturing

* Update aurora for CARD fix

* Fix Clang build

* More d_msg_flow endian fixes

Fixes softlock when trying to talk to Fado and possibly other NPCs.

* no frame limiter

* get pause menu working

* proper frame limiting

* particle pointer size fix

* improve map loader a bit

---------

Co-authored-by: Jasper St. Pierre <jstpierre@mecheye.net>
Co-authored-by: TakaRikka <takarikka@outlook.com>
Co-authored-by: CraftyBoss <talibabdulmaalik@gmail.com>
Co-authored-by: Luke Street <luke@street.dev>
Co-authored-by: Lurs <2795933+Lurs@users.noreply.github.com>
Co-authored-by: PJB3005 <pieterjan.briers+git@gmail.com>
Co-authored-by: tgsm <doodrabbit@hotmail.com>
Co-authored-by: Max Roncace <me@caseif.net>
Co-authored-by: Phillip Stephens <antidote.crk@gmail.com>
This commit is contained in:
qwertyquerty
2026-03-12 04:01:03 -07:00
committed by GitHub
parent 15732e241c
commit 767ba3bb14
129 changed files with 2270 additions and 1541 deletions
+2 -2
View File
@@ -15,10 +15,10 @@ public:
virtual void draw();
virtual ~dMirror_packet_c();
cXyz& getViewScale() { return mViewScale; }
GXTexObj& getTexObj() { return mTexObj; }
TGXTexObj& getTexObj() { return mTexObj; }
cXyz* getQuad() { return mQuad; }
/* 0x010 */ GXTexObj mTexObj;
/* 0x010 */ TGXTexObj mTexObj;
/* 0x030 */ u8 mModelCount;
/* 0x034 */ J3DModel* mModels[0x40];
/* 0x134 */ cXyz mQuad[4];
+2 -2
View File
@@ -35,11 +35,11 @@ public:
void setDecayRate(f32 rate) { mDecayRate = rate; }
void setGravity(f32 rate) { mGravity = rate; }
void setTornado(f32 tornado) { mTornado = tornado; }
GXTexObj* getImageTexObj() { return &mTexObj; }
TGXTexObj* getImageTexObj() { return &mTexObj; }
void setTexCoord_p(void* texCoordP) { mpTexCoord = texCoordP; }
/* 0x010 */ dKy_tevstr_c mTevStr;
/* 0x398 */ GXTexObj mTexObj;
/* 0x398 */ TGXTexObj mTexObj;
/* 0x3B8 */ dCcD_Stts mStts;
/* 0x3F4 */ dCcD_Sph mSph;
/* 0x52C */ u8 field_0x52c[0x540 - 0x52c];
+2 -2
View File
@@ -34,7 +34,7 @@ public:
cXyz* getVec() { return mVecs; }
cXyz* getNormal() { return mNormals; }
cXyz* getNormalBack() { return mNormalBacks; }
GXTexObj* getImageTexObj() { return &mTexObj; }
TGXTexObj* getImageTexObj() { return &mTexObj; }
void setSpringRate(f32 rate) { mSpringRate = rate; }
void setWindRate(f32 rate) { mWindRate = rate; }
void setDecayRate(f32 rate) { mDecayRate = rate; }
@@ -52,7 +52,7 @@ public:
void calcFlagFactorSub(cXyz* param_1, cXyz* param_2, cXyz* param_3, f32 param_4);
/* 0x010 */ GXTexObj mTexObj;
/* 0x010 */ TGXTexObj mTexObj;
/* 0x030 */ dKy_tevstr_c mTevStr;
/* 0x3B8 */ dCcD_Stts mStts;
/* 0x3F4 */ dCcD_Sph mSph;
+1 -1
View File
@@ -47,7 +47,7 @@ public:
mpBrkAnm->entry(model->getModelData());
mpMorfSO->entryDL();
if (field_0x9c0 == 0) {
GXTexObj* texObj = dDlst_shadowControl_c::getSimpleTex();
TGXTexObj* texObj = dDlst_shadowControl_c::getSimpleTex();
dComIfGd_setSimpleShadow(&current.pos, mObjAcch.GetGroundH(), 15.0f, mObjAcch.m_gnd, 0, -0.6f, texObj);
}
}
+1 -1
View File
@@ -25,7 +25,7 @@ public:
private:
/* 0x0568 */ request_of_phase_process_class mpPhase;
/* 0x0570 */ GXTexObj mTexObj;
/* 0x0570 */ TGXTexObj mTexObj;
/* 0x0590 */ dBgS_ObjAcch mObjAcch;
/* 0x0768 */ dBgS_AcchCir mAcchCir;
/* 0x07A8 */ dCcD_Stts mStts;
+3 -3
View File
@@ -1251,10 +1251,10 @@ int dComLbG_PhaseHandler(request_of_phase_process_class*, request_of_phase_proce
BOOL dComIfG_isSceneResetButton();
int dComIfGd_setSimpleShadow(cXyz* i_pos, f32 param_1, f32 param_2, cBgS_PolyInfo& param_3, s16 i_angle,
f32 param_5, GXTexObj* i_tex);
f32 param_5, TGXTexObj* i_tex);
int dComIfGd_setShadow(u32 param_0, s8 param_1, J3DModel* param_2, cXyz* param_3, f32 param_4,
f32 param_5, f32 param_6, f32 param_7, cBgS_PolyInfo& param_8,
dKy_tevstr_c* param_9, s16 param_10, f32 param_11, GXTexObj* param_12);
dKy_tevstr_c* param_9, s16 param_10, f32 param_11, TGXTexObj* param_12);
inline dSv_info_c* dComIfGs_getSaveInfo() {
return &g_dComIfG_gameInfo.info;
@@ -4489,7 +4489,7 @@ inline int dComIfGd_setRealShadow(u32 param_0, s8 param_1, J3DModel* param_2, cX
}
inline int dComIfGd_setSimpleShadow(cXyz* pos, f32 param_1, f32 param_2, cXyz* param_3, s16 angle,
f32 param_5, GXTexObj* tex) {
f32 param_5, TGXTexObj* tex) {
return g_dComIfG_gameInfo.drawlist.setSimpleShadow(pos, param_1, param_2, param_3, angle,
param_5, tex);
}
+10 -9
View File
@@ -5,9 +5,10 @@
#include "JSystem/J2DGraph/J2DScreen.h"
#include "JSystem/J3DGraphBase/J3DSys.h"
#include "SSystem/SComponent/c_m3d_g_pla.h"
#include "dusk/gx_helper.h"
#include "f_op/f_op_view.h"
#include "m_Do/m_Do_ext.h"
#include "global.h"
#include "m_Do/m_Do_ext.h"
class J3DDrawBuffer;
class J3DModel;
@@ -168,7 +169,7 @@ public:
void setScaleX(f32 scale) { mScaleX = scale; }
void setScaleY(f32 scale) { mScaleY = scale; }
/* 0x04 */ GXTexObj mTexObj;
/* 0x04 */ TGXTexObj mTexObj;
/* 0x24 */ f32 field_0x24;
/* 0x28 */ f32 field_0x28;
/* 0x2C */ f32 field_0x2c;
@@ -201,11 +202,11 @@ public:
class dDlst_shadowSimple_c {
public:
void draw();
void set(cXyz*, f32, f32, cXyz*, s16, f32, GXTexObj*);
void set(cXyz*, f32, f32, cXyz*, s16, f32, TGXTexObj*);
dDlst_shadowSimple_c();
/* 0x00 */ u8 mAlpha;
/* 0x04 */ GXTexObj* mpTexObj;
/* 0x04 */ TGXTexObj* mpTexObj;
/* 0x08 */ Mtx mVolumeMtx;
/* 0x38 */ Mtx mMtx;
}; // Size: 0x68
@@ -291,12 +292,12 @@ public:
void draw(f32 (*)[4]);
int setReal(u32, s8, J3DModel*, cXyz*, f32, f32, dKy_tevstr_c*);
bool addReal(u32, J3DModel*);
int setSimple(cXyz*, f32, f32, cXyz*, s16, f32, GXTexObj*);
int setSimple(cXyz*, f32, f32, cXyz*, s16, f32, TGXTexObj*);
static void setSimpleTex(ResTIMG const*);
static GXTexObj* getSimpleTex() { return &mSimpleTexObj; }
static TGXTexObj* getSimpleTex() { return &mSimpleTexObj; }
static GXTexObj mSimpleTexObj;
static TGXTexObj mSimpleTexObj;
private:
/* 0x00000 */ u8 field_0x0;
@@ -307,7 +308,7 @@ private:
/* 0x0000C */ dDlst_shadowSimple_c mSimple[128];
/* 0x0340C */ int mNextID;
/* 0x03410 */ dDlst_shadowReal_c mReal[8];
/* 0x15EB0 */ GXTexObj field_0x15eb0[2];
/* 0x15EB0 */ TGXTexObj field_0x15eb0[2];
/* 0x15EF0 */ void* field_0x15ef0[2];
};
@@ -444,7 +445,7 @@ public:
}
int setSimpleShadow(cXyz* param_0, f32 param_1, f32 param_2, cXyz* param_3, s16 param_4,
f32 param_5, GXTexObj* param_6) {
f32 param_5, TGXTexObj* param_6) {
return mShadowControl.setSimple(param_0, param_1, param_2, param_3, param_4, param_5,
param_6);
}
+2 -2
View File
@@ -246,7 +246,7 @@ struct dMpath_n {
void remove();
~dTexObjAggregate_c() { remove(); };
GXTexObj* getTexObjPointer(int i_no) {
TGXTexObj* getTexObjPointer(int i_no) {
JUT_ASSERT(44, i_no >= 0 && i_no < TEX_OBJ_NUMBER);
return mp_texObj[i_no];
}
@@ -257,7 +257,7 @@ struct dMpath_n {
}
}
/* 0x0 */ GXTexObj* mp_texObj[TEX_OBJ_NUMBER];
/* 0x0 */ TGXTexObj* mp_texObj[TEX_OBJ_NUMBER];
};
static dTexObjAggregate_c m_texObjAgg;
+4 -4
View File
@@ -18,11 +18,11 @@
class JMSMesgEntry_c {
public:
/* 0x0 */ u32 string_offset;
/* 0x0 */ BE(u32) string_offset;
// Attributes
/* 0x04 */ u16 message_id;
/* 0x06 */ u16 event_label_id;
/* 0x04 */ BE(u16) message_id;
/* 0x06 */ BE(u16) event_label_id;
/* 0x08 */ u8 se_speaker;
/* 0x09 */ u8 fuki_kind;
/* 0x0A */ u8 output_type;
@@ -33,7 +33,7 @@ public:
/* 0x0F */ u8 camera_id;
/* 0x10 */ u8 base_anm_id;
/* 0x11 */ u8 face_anm_id;
/* 0x12 */ u16 unk_0x12;
/* 0x12 */ BE(u16) unk_0x12;
};
class JMSMesgInfo_c {
+10 -9
View File
@@ -2,6 +2,7 @@
#define D_MSG_D_MSG_FLOW_H
#include <types.h>
#include "dusk/endian.h"
enum {
NODETYPE_MESSAGE_e = 1,
@@ -22,23 +23,23 @@ struct msg_class;
struct mesg_flow_node {
/* 0x00 */ u8 type;
/* 0x01 */ u8 field_0x1;
/* 0x02 */ u16 msg_index;
/* 0x04 */ u16 next_node_idx;
/* 0x06 */ u16 unk_0x6;
/* 0x02 */ BE(u16) msg_index;
/* 0x04 */ BE(u16) next_node_idx;
/* 0x06 */ BE(u16) unk_0x6;
}; // Size: 0x8
struct mesg_flow_node_branch {
/* 0x00 */ u8 type;
/* 0x01 */ u8 field_0x1;
/* 0x02 */ u16 query_idx;
/* 0x04 */ u16 param;
/* 0x06 */ u16 next_node_idx;
/* 0x02 */ BE(u16) query_idx;
/* 0x04 */ BE(u16) param;
/* 0x06 */ BE(u16) next_node_idx;
};
struct mesg_flow_node_event {
/* 0x00 */ u8 type;
/* 0x01 */ u8 event_idx;
/* 0x02 */ u16 next_node_idx;
/* 0x02 */ BE(u16) next_node_idx;
/* 0x04 */ u8 params[4];
}; // Size: 0x8
@@ -197,8 +198,8 @@ private:
}* mFlowNodeTBL;
/* 0x10 */ u16 mNodeIdx;
/* 0x12 */ u16 field_0x12;
/* 0x14 */ u16* mFlowIdxTBL;
/* 0x18 */ u16* field_0x18;
/* 0x14 */ BE(u16)* mFlowIdxTBL;
/* 0x18 */ BE(u16)* field_0x18;
/* 0x1C */ u16 mFlow;
/* 0x20 */ u32 mMsg;
/* 0x24 */ u8 mSelectMessage;
-1
View File
@@ -237,7 +237,6 @@ void be_swap(T (& val)[N]) {
for (u32 i = 0; i < N; i++) {
be_swap(val[i]);
}
val = BE<T>::swap(val);
}
template<typename T>
+32
View File
@@ -1,7 +1,10 @@
#ifndef DUSK_GX_HELPER_H
#define DUSK_GX_HELPER_H
#include <cstring>
#include <dolphin/gx/GXAurora.h>
#include <dolphin/gx/GXExtra.h>
#define GX_DEBUG_GROUP(name, ...) \
do { \
@@ -10,4 +13,33 @@
GXPopDebugGroup(); \
} while (0)
#ifdef TARGET_PC
class GXTexObjRAII : public GXTexObj {
public:
GXTexObjRAII() : GXTexObj() {}
~GXTexObjRAII() { GXDestroyTexObj(this); }
void reset() { GXDestroyTexObj(this); }
GXTexObjRAII(const GXTexObjRAII&) = delete;
GXTexObjRAII& operator=(const GXTexObjRAII&) = delete;
GXTexObjRAII(GXTexObjRAII&& o) = delete;/*noexcept : GXTexObj(o) {
std::memset(static_cast<GXTexObj*>(&o), 0, sizeof(GXTexObj));
}*/
GXTexObjRAII& operator=(GXTexObjRAII&& o) = delete;/*noexcept {
if (this != &o) {
GXDestroyTexObj(this);
std::memcpy(static_cast<GXTexObj*>(this), &o, sizeof(GXTexObj));
std::memset(static_cast<GXTexObj*>(&o), 0, sizeof(GXTexObj));
}
return *this;
}*/
};
static_assert(sizeof(GXTexObjRAII) == sizeof(GXTexObj),
"GXTexObjRAII should have the same size as GXTexObj");
typedef GXTexObjRAII TGXTexObj;
#else
typedef GXTexObj TGXTexObj;
#endif
#endif // DUSK_GX_HELPER_H
+15
View File
@@ -6,8 +6,23 @@
void aurora_log_callback(AuroraLogLevel level, const char* module, const char* message, unsigned int len);
namespace dusk {
void SendToStubLog(AuroraLogLevel level, const char* module, const char* message);
}
extern bool StubLogEnabled;
extern aurora::Module DuskLog;
#define STUB_LOG() DuskLog.debug("{} is a stub", __FUNCTION__)
#if TARGET_PC
#define STUB_RET(...) \
STUB_LOG(); \
return __VA_ARGS__;
#else
#define STUB_RET() (void)0
#endif
#endif
+179
View File
@@ -0,0 +1,179 @@
#pragma once
struct MapEntry {
static constexpr int MAX_ROOMS = 50;
const char* mapName;
const char* mapFile;
u8 mapRooms[MAX_ROOMS] = {};
int numRooms;
constexpr MapEntry() : mapName(nullptr), mapFile(nullptr), numRooms(0) {}
constexpr MapEntry(const MapEntry& other) = default;
template <int N>
constexpr MapEntry(const char* mapName, const char* mapFile, const int (&rooms)[N], const char*) : mapName(mapName),
mapFile(mapFile), numRooms(N) {
static_assert(N <= MAX_ROOMS);
for (int i = 0; i < N; i++) {
mapRooms[i] = rooms[i];
}
}
template <int N>
constexpr MapEntry(const char* mapName, const char* mapFile, const int (&rooms)[N]) :
mapName(mapName), mapFile(mapFile), numRooms(N) {
static_assert(N <= MAX_ROOMS);
for (int i = 0; i < N; i++) {
mapRooms[i] = rooms[i];
}
}
constexpr MapEntry(const char* mapName, const char* mapFile) : mapName(mapName),
mapFile(mapFile), numRooms(0) {}
};
struct RegionEntry {
static constexpr int MAX_MAPS = 22;
const char* regionName = nullptr;
int numMaps = 0;
MapEntry maps[MAX_MAPS] = {};
template <int N>
constexpr RegionEntry(const char* regionName, const MapEntry (&maps)[N]) : regionName(regionName), numMaps(N) {
static_assert(N <= MAX_MAPS);
for (int i = 0; i < N; i++) {
this->maps[i] = maps[i];
}
}
};
constexpr auto gameRegions = std::to_array({
RegionEntry("Hyrule Field", {
MapEntry("Hyrule Field", "F_SP121", {0, 1, 2, 3, 4, 5, 6, 7, 9, 10, 11, 12, 13, 14, 15}),
}), RegionEntry("Ordon", {
MapEntry("Ordon Village", "F_SP103"),
MapEntry("Outside Link's House", "F_SP103", {1}, "F_SP103_1"),
MapEntry("Ordon Ranch", "F_SP00"),
MapEntry("Ordon Spring", "F_SP104", {1}),
MapEntry("Bo's House", "R_SP01", {0}),
MapEntry("Sera's Sundries", "R_SP01", {1}, "R_SP01_1"),
MapEntry("Jaggle's House", "R_SP01", {2}, "R_SP01_2"),
MapEntry("Link's House", "R_SP01", {4, 7}, "R_SP01_4"),
MapEntry("Rusl's House", "R_SP01", {5}, "R_SP01_5"),
}), RegionEntry("Faron", {
MapEntry("South Faron Woods", "F_SP108", {0, 1, 2, 3, 4, 5, 8, 11, 14}),
MapEntry("North Faron Woods", "F_SP108", {6}, "F_SP108"),
MapEntry("Lost Woods", "F_SP117", {3}),
MapEntry("Sacred Grove", "F_SP117", {1}, "F_SP117_1"),
MapEntry("Temple of Time (Past)", "F_SP117", {2}, "F_SP117_2"),
MapEntry("Faron Woods Cave", "D_SB10"),
MapEntry("Coro's House", "R_SP108"),
}), RegionEntry("Eldin", {
MapEntry("Kakariko Village", "F_SP109"),
MapEntry("Death Mountain Trail", "F_SP110", {0, 1, 2, 3}),
MapEntry("Kakariko Graveyard", "F_SP111"),
MapEntry("Hidden Village", "F_SP128"),
MapEntry("Renado's Sanctuary", "R_SP109", {0}),
MapEntry("Sanctuary Basement", "R_SP209", {7}),
MapEntry("Barnes' Bombs", "R_SP109", {1}, "R_SP109_1"),
MapEntry("Elde Inn", "R_SP109", {2}, "R_SP109_2"),
MapEntry("Malo Mart", "R_SP109", {3}, "R_SP109_3"),
MapEntry("Lookout Tower", "R_SP109", {4}, "R_SP109_4"),
MapEntry("Bomb Warehouse", "R_SP109", {5}, "R_SP109_5"),
MapEntry("Abandoned House", "R_SP109", {6}, "R_SP109_6"),
MapEntry("Goron Elder's Hall", "R_SP110"),
}), RegionEntry("Lanayru", {
MapEntry("Outside Castle Town - West", "F_SP122", {8}),
MapEntry("Outside Castle Town - South", "F_SP122", {16}, "F_SP122_16"),
MapEntry("Outside Castle Town - East", "F_SP122", {17}, "F_SP122_17"),
MapEntry("Castle Town", "F_SP116", {0, 1, 2, 3, 4}),
MapEntry("Zora's River", "F_SP112", {1}),
MapEntry("Zora's Domain", "F_SP113", {0, 1}),
MapEntry("Lake Hylia", "F_SP115"),
MapEntry("Lanayru Spring", "F_SP115", {1}, "F_SP115_1"),
MapEntry("Upper Zora's River", "F_SP126", {0}),
MapEntry("Fishing Pond", "F_SP127", {0}),
MapEntry("Castle Town Sewers", "R_SP107", {0, 1, 2, 3}),
MapEntry("Telma's Bar / Secret Passage", "R_SP116", {5, 6}),
MapEntry("Hena's Cabin", "R_SP127", {0}),
MapEntry("Impaz's House", "R_SP128", {0}),
MapEntry("Malo Mart", "R_SP160", {0}),
MapEntry("Fanadi's Palace", "R_SP160", {1}, "R_SP160_1"),
MapEntry("Medical Clinic", "R_SP160", {2}, "R_SP160_2"),
MapEntry("Agitha's Castle", "R_SP160", {3}, "R_SP160_3"),
MapEntry("Goron Shop", "R_SP160", {4}, "R_SP160_4"),
MapEntry("Jovani's House", "R_SP160", {5}, "R_SP160_5"),
MapEntry("STAR Tent", "R_SP161", {7}),
}), RegionEntry("Gerudo Desert", {
MapEntry("Bulblin Camp", "F_SP118", {0, 1, 3}),
MapEntry("Bulblin Camp Beta Room", "F_SP118", {2}, "F_SP118_2"),
MapEntry("Gerudo Desert", "F_SP124", {0}),
MapEntry("Mirror Chamber", "F_SP125", {4}),
}), RegionEntry("Snowpeak", {
MapEntry("Snowpeak Mountain", "F_SP114", {0, 1, 2}),
}), RegionEntry("Forest Temple", {
MapEntry("Forest Temple", "D_MN05", {0, 1, 2, 3, 4, 5, 7, 9, 10, 11, 12, 19, 22}),
MapEntry("Diababa Arena", "D_MN05A", {50}),
MapEntry("Ook Arena", "D_MN05B", {51}),
}), RegionEntry("Goron Mines", {
MapEntry("Goron Mines", "D_MN04", {1, 3, 4, 5, 6, 7, 9, 11, 12, 13, 14, 16, 17}),
MapEntry("Fyrus Arena", "D_MN04A", {50}),
MapEntry("Dangoro Arena", "D_MN04B", {51}),
}), RegionEntry("Lakebed Temple", {
MapEntry("Lakebed Temple", "D_MN01", {0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13}),
MapEntry("Morpheel Arena", "D_MN01A", {50}),
MapEntry("Deku Toad Arena", "D_MN01B", {51}),
}), RegionEntry("Arbiter's Grounds", {
MapEntry("Arbiter's Grounds", "D_MN10", {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16}),
MapEntry("Stallord Arena", "D_MN10A", {50}),
MapEntry("Death Sword Arena", "D_MN10B", {51}),
}), RegionEntry("Snowpeak Ruins", {
MapEntry("Snowpeak Ruins", "D_MN11", {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 11, 13}),
MapEntry("Blizzeta Arena", "D_MN11A", {50}),
MapEntry("Darkhammer Arena", "D_MN11B", {51}),
MapEntry("Darkhammer Beta Arena", "D_MN11B", {49}),
}), RegionEntry("Temple of Time", {
MapEntry("Temple of Time", "D_MN06", {0, 1, 2, 3, 4, 5, 6, 7, 8}),
MapEntry("Armogohma Arena", "D_MN06A", {50}),
MapEntry("Darknut Arena", "D_MN06B", {51}),
}), RegionEntry("City in the Sky", {
MapEntry("City in the Sky", "D_MN07", {0, 1, 2, 3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 15, 16}),
MapEntry("Argorok Arena", "D_MN07A", {50}),
MapEntry("Aeralfos Arena", "D_MN07B", {51}),
}), RegionEntry("Palace of Twilight", {
MapEntry("Palace of Twilight", "D_MN08", {0, 1, 2, 4, 5, 7, 8, 9, 10, 11}),
MapEntry("Palace of Twilight Throne Room", "D_MN08A", {10}),
MapEntry("Phantom Zant Arena 1", "D_MN08B", {51}),
MapEntry("Phantom Zant Arena 2", "D_MN08C", {52}),
MapEntry("Zant Arenas", "D_MN08D", {50, 53, 54, 55, 56, 57, 60}),
}), RegionEntry("Hyrule Castle", {
MapEntry("Hyrule Castle", "D_MN09", {1, 2, 3, 4, 5, 6, 8, 9, 11, 12, 13, 14, 15}),
MapEntry("Hyrule Castle Throne Room", "D_MN09A", {50, 51}),
MapEntry("Horseback Ganondorf Arena", "D_MN09B", {0}),
MapEntry("Dark Lord Ganondorf Arena", "D_MN09C", {0}),
}), RegionEntry("Mini-Dungeons and Grottos", {
MapEntry("Ice Cavern", "D_SB00", {0}),
MapEntry("Cave Of Ordeals", "D_SB01",
{0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
20, 21, 22, 23, 24, 25, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39,
40, 41, 42, 43, 44, 45, 46, 47, 48, 49}
),
MapEntry("Kakariko Gorge Cavern", "D_SB02", {0}),
MapEntry("Lake Hylia Cavern", "D_SB03", {0}),
MapEntry("Goron Stockcave", "D_SB04", {10}),
MapEntry("Grotto 1", "D_SB05"),
MapEntry("Grotto 2", "D_SB06", {1}),
MapEntry("Grotto 3", "D_SB07", {2}),
MapEntry("Grotto 4", "D_SB08", {3}),
MapEntry("Grotto 5", "D_SB09", {4}),
}), RegionEntry("Misc", {
MapEntry("Title Screen / King Bulblin 1", "F_SP102"),
MapEntry("King Bulblin 2", "F_SP123", {13}),
MapEntry("Wolf Howling Cutscene Map", "F_SP200"),
// MapEntry("Cutscene: Light Arrow Area", "R_SP300"),
MapEntry("Cutscene: Hyrule Castle Throne Room", "R_SP301"),
})
});
+138
View File
@@ -2,6 +2,9 @@
#define _SRC_DUSK_MATH_H_
#include <cmath>
#include <array>
#include <limits>
#include <bit>
#ifndef M_PI
#define M_PI 3.14159265358979323846f
@@ -16,4 +19,139 @@ inline float i_cosf(float x) { return cos(x); }
inline float i_tanf(float x) { return tan(x); }
inline float i_acosf(float x) { return acos(x); }
// frsqrte matching courtesy of Geotale, with reference to https://achurch.org/cpu-tests/ppc750cl.s
struct BaseAndDec32 {
uint32_t base;
int32_t dec;
};
struct BaseAndDec64 {
uint64_t base;
int64_t dec;
};
union c32 {
constexpr c32(const float p) {
f = p;
}
constexpr c32(const uint32_t p) {
u = p;
}
uint32_t u;
float f;
};
union c64 {
constexpr c64(const double p) {
f = p;
}
constexpr c64(const uint64_t p) {
u = p;
}
uint64_t u;
double f;
};
static constexpr uint64_t EXPONENT_SHIFT_F64 = 52;
static constexpr uint64_t MANTISSA_MASK_F64 = 0x000fffffffffffffULL;
static constexpr uint64_t EXPONENT_MASK_F64 = 0x7ff0000000000000ULL;
static constexpr uint64_t SIGN_MASK_F64 = 0x8000000000000000ULL;
static constexpr std::array<BaseAndDec64, 32> RSQRTE_TABLE = {{
{0x69fa000000000ULL, -0x15a0000000LL},
{0x5f2e000000000ULL, -0x13cc000000LL},
{0x554a000000000ULL, -0x1234000000LL},
{0x4c30000000000ULL, -0x10d4000000LL},
{0x43c8000000000ULL, -0x0f9c000000LL},
{0x3bfc000000000ULL, -0x0e88000000LL},
{0x34b8000000000ULL, -0x0d94000000LL},
{0x2df0000000000ULL, -0x0cb8000000LL},
{0x2794000000000ULL, -0x0bf0000000LL},
{0x219c000000000ULL, -0x0b40000000LL},
{0x1bfc000000000ULL, -0x0aa0000000LL},
{0x16ae000000000ULL, -0x0a0c000000LL},
{0x11a8000000000ULL, -0x0984000000LL},
{0x0ce6000000000ULL, -0x090c000000LL},
{0x0862000000000ULL, -0x0898000000LL},
{0x0416000000000ULL, -0x082c000000LL},
{0xffe8000000000ULL, -0x1e90000000LL},
{0xf0a4000000000ULL, -0x1c00000000LL},
{0xe2a8000000000ULL, -0x19c0000000LL},
{0xd5c8000000000ULL, -0x17c8000000LL},
{0xc9e4000000000ULL, -0x1610000000LL},
{0xbedc000000000ULL, -0x1490000000LL},
{0xb498000000000ULL, -0x1330000000LL},
{0xab00000000000ULL, -0x11f8000000LL},
{0xa204000000000ULL, -0x10e8000000LL},
{0x9994000000000ULL, -0x0fe8000000LL},
{0x91a0000000000ULL, -0x0f08000000LL},
{0x8a1c000000000ULL, -0x0e38000000LL},
{0x8304000000000ULL, -0x0d78000000LL},
{0x7c48000000000ULL, -0x0cc8000000LL},
{0x75e4000000000ULL, -0x0c28000000LL},
{0x6fd0000000000ULL, -0x0b98000000LL},
}};
[[nodiscard]] static inline double frsqrte(const double val) {
c64 bits(val);
uint64_t mantissa = bits.u & MANTISSA_MASK_F64;
int64_t exponent = bits.u & EXPONENT_MASK_F64;
bool sign = (bits.u & SIGN_MASK_F64) != 0;
// Handle 0 case
if (mantissa == 0 && exponent == 0) {
return std::copysign(std::numeric_limits<double>::infinity(), bits.f);
}
// Handle NaN-like
if (exponent == EXPONENT_MASK_F64) {
if (mantissa == 0) {
return sign ? std::numeric_limits<double>::quiet_NaN() : 0.0;
}
return val;
}
// Handle negative inputs
if (sign) {
return std::numeric_limits<double>::quiet_NaN();
}
if (exponent == 0) {
// Shift so one bit goes to where the exponent would be,
// then clear that bit to mimic a not-subnormal number!
// Aka, if there are 12 leading zeroes, shift left once
uint32_t shift = std::countl_zero(mantissa) - static_cast<uint32_t>(63 - EXPONENT_SHIFT_F64);
mantissa <<= shift;
mantissa &= MANTISSA_MASK_F64;
// The shift is subtracted by 1 because denormals by default
// are offset by 1 (exponent 0 doesn't have implied 1 bit)
exponent -= static_cast<int64_t>(shift - 1) << EXPONENT_SHIFT_F64;
}
// In reality this doesn't get the full exponent -- Only the least significant bit
// Only that's needed because square roots of higher exponent bits simply multiply the
// result by 2!!
uint32_t key = static_cast<uint32_t>((static_cast<uint64_t>(exponent) | mantissa) >> 37);
uint64_t new_exp =
(static_cast<uint64_t>((0xbfcLL << EXPONENT_SHIFT_F64) - exponent) >> 1) & EXPONENT_MASK_F64;
// Remove the bits relating to anything higher than the LSB of the exponent
const auto &entry = RSQRTE_TABLE[0x1f & (key >> 11)];
// The result is given by an estimate then an adjustment based on the original
// key that was computed
uint64_t new_mantissa = static_cast<uint64_t>(entry.base + entry.dec * static_cast<int64_t>(key & 0x7ff));
return c64(new_exp | new_mantissa).f;
}
#endif // _SRC_DUSK_MATH_H_
+103
View File
@@ -0,0 +1,103 @@
#ifndef DUSK_TIME_H
#define DUSK_TIME_H
#include <chrono>
#include <numeric>
#include <array>
#ifdef _WIN32
#ifndef WIN32_LEAN_AND_MEAN
#define WIN32_LEAN_AND_MEAN
#endif
#ifndef NOMINMAX
#define NOMINMAX
#endif
#include <Windows.h>
#include <shellapi.h>
#endif
#include "dusk/logging.h"
constexpr auto DUSK_FRAME_PERIOD = std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::duration<double>(1001.0 / 30000.0));
class Limiter {
using delta_clock = std::chrono::high_resolution_clock;
using duration_t = std::chrono::nanoseconds;
public:
void Reset() { m_oldTime = delta_clock::now(); }
void Sleep(duration_t targetFrameTime) {
if (targetFrameTime.count() == 0) {
return;
}
auto start = delta_clock::now();
duration_t adjustedSleepTime = SleepTime(targetFrameTime);
if (adjustedSleepTime.count() > 0) {
NanoSleep(adjustedSleepTime);
duration_t overslept = TimeSince(start) - adjustedSleepTime;
if (overslept < duration_t{targetFrameTime}) {
m_overheadTimes[m_overheadTimeIdx] = overslept;
m_overheadTimeIdx = (m_overheadTimeIdx + 1) % m_overheadTimes.size();
}
}
Reset();
}
duration_t SleepTime(duration_t targetFrameTime) {
const auto sleepTime = duration_t{targetFrameTime} - TimeSince(m_oldTime);
m_overhead = std::accumulate(m_overheadTimes.begin(), m_overheadTimes.end(), duration_t{}) / m_overheadTimes.size();
if (sleepTime > m_overhead) {
return sleepTime - m_overhead;
}
return duration_t{0};
}
private:
delta_clock::time_point m_oldTime;
std::array<duration_t, 4> m_overheadTimes{};
size_t m_overheadTimeIdx = 0;
duration_t m_overhead = duration_t{0};
duration_t TimeSince(delta_clock::time_point start) {
return std::chrono::duration_cast<duration_t>(delta_clock::now() - start);
}
#if _WIN32
void NanoSleep(const duration_t duration) {
static bool initialized = false;
static double countPerNs;
static size_t numSleeps = 0;
// QueryPerformanceFrequency's result is constant, but calling it occasionally
// appears to stabilize QueryPerformanceCounter. Without it, the game drifts
// from 60hz to 144hz. (Cursed, but I suspect it's NVIDIA/G-SYNC related)
if (!initialized || numSleeps++ % 1000 == 0) {
LARGE_INTEGER freq;
if (QueryPerformanceFrequency(&freq) == 0) {
DuskLog.warn("QueryPerformanceFrequency failed: {}", GetLastError());
return;
}
countPerNs = static_cast<double>(freq.QuadPart) / 1e9;
initialized = true;
numSleeps = 0;
}
LARGE_INTEGER start, current;
QueryPerformanceCounter(&start);
LONGLONG ticksToWait = static_cast<LONGLONG>(duration.count() * countPerNs);
if (DWORD ms = std::chrono::duration_cast<std::chrono::milliseconds>(duration).count(); ms > 1) {
::Sleep(ms - 1);
}
do {
QueryPerformanceCounter(&current);
_mm_pause(); // Yield CPU
} while (current.QuadPart - start.QuadPart < ticksToWait);
}
#else
void NanoSleep(const duration_t duration) { std::this_thread::sleep_for(duration); }
#endif
};
#endif
+1
View File
@@ -46,6 +46,7 @@ public:
static u32 getHoldZ(u32 pad) { return getHold(pad) & PAD_TRIGGER_Z; }
static u32 getHoldY(u32 pad) { return getHold(pad) & PAD_BUTTON_Y; }
static u32 getHoldX(u32 pad) { return getHold(pad) & PAD_BUTTON_X; }
static u32 getHoldStart(u32 pad) { return getHold(pad) & PAD_BUTTON_START; }
static f32 getStickX(u32 pad) { return getCpadInfo(pad).mMainStickPosX; }
static f32 getStickY(u32 pad) { return getCpadInfo(pad).mMainStickPosY; }
static f32 getStickX3D(u32 pad) { return getCpadInfo(pad).mMainStickPosX; }
+1 -1
View File
@@ -582,7 +582,7 @@ public:
f32* getSize(int i_idx) { return mpLines[i_idx].field_0x4; }
private:
/* 0x08 */ GXTexObj mTextureObject;
/* 0x08 */ TGXTexObj mTextureObject;
/* 0x28 */ GXColor mColor;
/* 0x2C */ dKy_tevstr_c* mpTevStr;
/* 0x30 */ u16 mNumLines;
+5 -5
View File
@@ -237,8 +237,8 @@ public:
static GXColor& getFadeColor() { return mFadeColor; }
static GXColor& getBackColor() { return mBackColor; }
static void endRender() { JFWDisplay::getManager()->endRender(); }
static GXTexObj* getZbufferTexObj() { return &mZbufferTexObj; }
static GXTexObj* getFrameBufferTexObj() { return &mFrameBufferTexObj; }
static TGXTexObj* getZbufferTexObj() { return &mZbufferTexObj; }
static TGXTexObj* getFrameBufferTexObj() { return &mFrameBufferTexObj; }
static void setFrameRate(u16 i_rate) { JFWDisplay::getManager()->setFrameRate(i_rate); }
static int getFrameBufferSize() {
@@ -285,8 +285,8 @@ public:
static void setWindowSize(AuroraWindowSize const& size);
#endif
static GXTexObj mFrameBufferTexObj;
static GXTexObj mZbufferTexObj;
static TGXTexObj mFrameBufferTexObj;
static TGXTexObj mZbufferTexObj;
static bloom_c m_bloom;
static Mtx mBlureMtx;
static GXColor mBackColor;
@@ -331,7 +331,7 @@ public:
static u8 mWideZoom;
static ResTIMG* m_fullFrameBufferTimg;
static void* m_fullFrameBufferTex;
static GXTexObj m_fullFrameBufferTexObj;
static TGXTexObj m_fullFrameBufferTexObj;
static f32 m_aspect;
static f32 m_scale;
+3 -1
View File
@@ -4,6 +4,8 @@
#include "JSystem/J3DU/J3DUClipper.h"
#include <dolphin/gx/GXStruct.h>
#include "dusk/gx_helper.h"
typedef struct Vec Vec;
struct ResTIMG;
@@ -37,7 +39,7 @@ struct mDoLib_clipper {
};
void mDoLib_project(Vec* src, Vec* dst);
u32 mDoLib_setResTimgObj(ResTIMG const* res, GXTexObj* o_texObj, u32 tlut_name,
u32 mDoLib_setResTimgObj(ResTIMG const* res, TGXTexObj* o_texObj, u32 tlut_name,
GXTlutObj* o_tlutObj);
void mDoLib_pos2camera(Vec* src, Vec* dst);