Merge branch 'main' into rmlui-integration

# Conflicts:
#	extern/aurora
This commit is contained in:
Luke Street
2026-05-01 21:24:24 -06:00
22 changed files with 3372 additions and 220 deletions
+4
View File
@@ -91,6 +91,10 @@ public:
void calcCursor();
void drawCursor();
#if TARGET_PC
void dMapBgWide();
#endif
void setDPDFloorSelCurPos(s8 i_pos) { field_0xdd6 = i_pos; }
f32 getMapWidth() { return mMapWidth; }
+8
View File
@@ -81,6 +81,10 @@ public:
void calcDrawPriority();
void setArrowPosAxis(f32, f32);
#if TARGET_PC
void fMapBackWide();
#endif
virtual void draw();
virtual ~dMenu_Fmap2DBack_c();
@@ -330,6 +334,10 @@ public:
void setHIO(bool);
bool isWarpAccept();
#if TARGET_PC
void fMapTopWide();
#endif
virtual void draw();
virtual ~dMenu_Fmap2DTop_c();
@@ -207,4 +207,11 @@ 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,6 +24,9 @@ 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;
-1
View File
@@ -302,7 +302,6 @@ 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,6 +442,7 @@ 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);
}
+255 -113
View File
@@ -9,6 +9,9 @@
#include <mtx.h>
#include <gx.h>
#if TARGET_PC
#include "dusk/frame_interpolation.h"
#endif
#include "tracy/Tracy.hpp"
void JPASetPointSize(JPAEmitterWorkData* work) {
@@ -418,50 +421,95 @@ static projectionFunc p_prj[3] = {
loadPrjAnm,
};
void JPADrawBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
#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)) {
return;
}
JGeometry::TVec3<f32> local_48;
MTXMultVec(work->mPosCamMtx, &param_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);
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);
GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
}
void JPADrawRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* param_1) {
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
void JPADrawRotBillboard(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
return;
}
JGeometry::TVec3<f32> local_48;
MTXMultVec(work->mPosCamMtx, &param_1->mPosition, &local_48);
f32 sinRot = JMASSin(param_1->mRotateAngle);
f32 cosRot = JMASCos(param_1->mRotateAngle);
f32 particleX = work->mGlobalPtclScl.x * param_1->mParticleScaleX;
f32 particleY = work->mGlobalPtclScl.y * param_1->mParticleScaleY;
if (work->mpRes->getUsrIdx() == 0x89d7) {
int a = 0;
}
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);
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);
GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
}
@@ -484,7 +532,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, 0);
GXLoadPosMtxImm(local_38, GX_PNMTX0);
p_prj[work->mPrjType](work, local_38);
GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
}
@@ -517,7 +565,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, 0);
GXLoadPosMtxImm(local_38, GX_PNMTX0);
p_prj[work->mPrjType](work, local_38);
GXCallDisplayList(jpa_dl, sizeof(jpa_dl));
}
@@ -681,103 +729,197 @@ static u8* p_dl[2] = {
jpa_dl_x,
};
void JPADrawDirection(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
#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;
}
ZoneScoped;
axisY.normalize();
axisZ.cross(ptcl->mBaseAxis, axisY);
JGeometry::TVec3<f32> local_6c;
JGeometry::TVec3<f32> local_78;
p_direction[param_0->mDirType](param_0, param_1, &local_6c);
if (local_6c.isZero()) {
if (axisZ.isZero()) {
return;
}
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));
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 JPADrawRotDirection(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
if (param_1->checkStatus(JPAPtclStts_Invisible)) {
void JPAInterpRotDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
f32 sinRot = JMASSin(ptcl->mRotateAngle);
f32 cosRot = JMASCos(ptcl->mRotateAngle);
JGeometry::TVec3<f32> axisY;
JGeometry::TVec3<f32> axisZ;
p_direction[work->mDirType](work, ptcl, &axisY);
if (axisY.isZero()) {
return;
}
axisY.normalize();
axisZ.cross(ptcl->mBaseAxis, axisY);
if (axisZ.isZero()) {
return;
}
axisZ.normalize();
ptcl->mBaseAxis.cross(axisY, axisZ);
ptcl->mBaseAxis.normalize();
f32 scaleX = work->mGlobalPtclScl.x * ptcl->mParticleScaleX;
f32 scaleY = work->mGlobalPtclScl.y * ptcl->mParticleScaleY;
Mtx mtx1;
Mtx mtx2;
p_rot[work->mRotType](sinRot, cosRot, mtx1);
p_plane[work->mPlaneType](mtx1, scaleX, scaleY);
mtx2[0][0] = ptcl->mBaseAxis.x;
mtx2[0][1] = axisY.x;
mtx2[0][2] = axisZ.x;
mtx2[0][3] = ptcl->mPosition.x;
mtx2[1][0] = ptcl->mBaseAxis.y;
mtx2[1][1] = axisY.y;
mtx2[1][2] = axisZ.y;
mtx2[1][3] = ptcl->mPosition.y;
mtx2[2][0] = ptcl->mBaseAxis.z;
mtx2[2][1] = axisY.z;
mtx2[2][2] = axisZ.z;
mtx2[2][3] = ptcl->mPosition.z;
MTXConcat(mtx2, mtx1, mtx1);
dusk::frame_interp::record_final_mtx(mtx1, ptcl);
}
#endif
void JPADrawDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
return;
}
ZoneScoped;
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);
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);
if (local_6c.isZero()) {
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);
}
MTXConcat(work->mPosCamMtx, posMtx, posMtx);
GXLoadPosMtxImm(posMtx, GX_PNMTX0);
p_prj[work->mPrjType](work, posMtx);
GXCallDisplayList(p_dl[work->mDLType], sizeof(jpa_dl));
}
void JPADrawRotDirection(JPAEmitterWorkData* work, JPABaseParticle* ptcl) {
if (ptcl->checkStatus(JPAPtclStts_Invisible)) {
return;
}
local_6c.normalize();
local_78.cross(param_1->mBaseAxis, local_6c);
ZoneScoped;
if (local_78.isZero()) {
return;
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);
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);
}
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));
MTXConcat(work->mPosCamMtx, mtx1, mtx2);
GXLoadPosMtxImm(mtx2, GX_PNMTX0);
p_prj[work->mPrjType](work, mtx2);
GXCallDisplayList(p_dl[work->mDLType], sizeof(jpa_dl));
}
void JPADrawDBillboard(JPAEmitterWorkData* param_0, JPABaseParticle* param_1) {
@@ -204,6 +204,24 @@ void JPABaseParticle::init_c(JPAEmitterWorkData* work, JPABaseParticle* parent)
mTexAnmIdx = 0;
}
#if TARGET_PC
void JPABaseParticle::interp(JPAEmitterWorkData* work, void const* drawFunc) {
// 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;
@@ -247,6 +265,17 @@ 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;
}
@@ -289,6 +318,23 @@ 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;
}
+4 -1
View File
@@ -4962,13 +4962,16 @@ 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);
if (dComIfG_resLoad(&mShieldPhaseReq, mShieldArcName, mpShieldArcHeap) != cPhs_COMPLEATE_e) {
JKRHEAP_NAME(mpShieldArcHeap, "Alink ShieldArcHeap");
if (dComIfG_resLoad(&mShieldPhaseReq, mShieldArcName, mpShieldArcHeap) != cPhs_COMPLEATE_e)
{
return cPhs_INIT_e;
}
-1
View File
@@ -46,7 +46,6 @@ 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;
}
}
+11 -7
View File
@@ -62,6 +62,16 @@ 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;
@@ -205,13 +215,6 @@ 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;
}
@@ -253,6 +256,7 @@ int daObj_Balloon_c::create() {
}
if (!hio_set) {
IF_DUSK(minigameReset());
mHIOInit = true;
hio_set = true;
l_HIO.field_0x04 = -1;
+2 -5
View File
@@ -59,8 +59,7 @@ void dScissorBegin_packet_c::draw() {
}
if (sp50 >= 4) {
IF_DUSK(GXSetColorUpdate(GX_FALSE));
IF_NOT_DUSK(GXSetScissor(FB_WIDTH + 1, FB_HEIGHT + 1, 0, 0));
GXSetScissor(FB_WIDTH + 1, FB_HEIGHT + 1, 0, 0);
return;
}
@@ -171,8 +170,7 @@ void dScissorBegin_packet_c::draw() {
}
if (spBC.z < 0.0f || var_f31 > sp6C || sp7C < sp70 || var_f30 > sp64 || sp78 < sp68) {
IF_DUSK(GXSetColorUpdate(GX_FALSE));
IF_NOT_DUSK(GXSetScissor(FB_WIDTH + 1, FB_HEIGHT + 1, 0, 0));
GXSetScissor(FB_WIDTH + 1, FB_HEIGHT + 1, 0, 0);
} else {
var_f31 = cLib_minLimit<f32>(var_f31, sp70);
sp7C = cLib_maxLimit<f32>(sp7C, sp6C);
@@ -189,7 +187,6 @@ void dScissorEnd_packet_c::draw() {
#endif
GXSetScissor(l_scissor[0], l_scissor[1], l_scissor[2], l_scissor[3]);
IF_DUSK(GXSetColorUpdate(GX_TRUE));
}
static int createSolidHeap(fopAc_ac_c* i_this) {
+16 -3
View File
@@ -1481,7 +1481,7 @@ void dCamera_c::CalcTrimSize() {
mTrimHeight += -mTrimHeight * 0.25f;
break;
case 2:
#if WIDESCREEN_SUPPORT
#if !TARGET_PC && WIDESCREEN_SUPPORT
if (mDoGph_gInf_c::isWide() && mDoGph_gInf_c::isWideZoom()) {
mTrimHeight += (16.0f - mTrimHeight) * 0.25f;
break;
@@ -11161,12 +11161,25 @@ 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
+45 -9
View File
@@ -22,6 +22,10 @@
#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 {
@@ -1062,7 +1066,15 @@ void dDlst_shadowReal_c::reset() {
}
void dDlst_shadowReal_c::imageDraw(Mtx param_0) {
GXSetProjection(mRenderProjMtx, GX_ORTHOGRAPHIC);
#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);
}
JUT_ASSERT(1916, mModelNum);
J3DModelData* model_data;
J3DModel** models = mpModels;
@@ -1075,7 +1087,15 @@ 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);
shape_pkt->setBaseMtxPtr(&mViewMtx);
#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->drawFast();
shape_pkt->setBaseMtxPtr((Mtx*)param_0);
}
@@ -1096,7 +1116,18 @@ 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);
GXLoadTexMtxImm(mReceiverProjMtx, GX_TEXMTX0, GX_MTX3x4);
#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);
}
mShadowRealPoly.draw();
}
@@ -1253,6 +1284,13 @@ 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;
}
@@ -1277,6 +1315,10 @@ 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) {
@@ -1370,12 +1412,6 @@ 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) {
+39
View File
@@ -856,7 +856,46 @@ 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;
+29 -1
View File
@@ -20,6 +20,15 @@
#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);
@@ -267,6 +276,10 @@ dMenu_Fmap2DBack_c::~dMenu_Fmap2DBack_c() {
}
void dMenu_Fmap2DBack_c::draw() {
#if TARGET_PC
fMapBackWide();
#endif
calcBlink();
J2DGrafContext* grafPort = dComIfGp_getCurrentGrafPort();
@@ -1199,7 +1212,7 @@ f32 dMenu_Fmap2DBack_c::getMapScissorAreaSizeX() {
}
f32 dMenu_Fmap2DBack_c::getMapScissorAreaSizeRealX() {
#if PLATFORM_GCN && !TARGET_PC
#if PLATFORM_GCN
return getMapScissorAreaSizeX();
#else
return getMapScissorAreaSizeX() * mDoGph_gInf_c::getScale();
@@ -2179,6 +2192,17 @@ 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;
@@ -2572,6 +2596,10 @@ 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();
+4
View File
@@ -2306,6 +2306,10 @@ 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
}
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -180,9 +180,9 @@ namespace dusk {
void ShowHeapDetailed(JKRHeap* heap, OpenHeapData& data, bool& open) {
char title[128];
const char* name = data.Safe ? heap->getName() : "INVALID";
snprintf(title, sizeof(title), "Heap %s##%p", heap->getName(), static_cast<const void*>(heap));
snprintf(title, sizeof(title), "Heap %s##%p", name, static_cast<const void*>(heap));
if (!ImGui::Begin(name, &open)) {
if (!ImGui::Begin(title, &open)) {
ImGui::End();
return;
}
@@ -195,7 +195,7 @@ namespace dusk {
heap->lock();
ImGui::Text("Name: %s", heap->getName());
ImGui::Text("Name: %s", name);
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());
+336 -75
View File
@@ -13,6 +13,7 @@
#include "d/actor/d_a_player.h"
#include <map>
#include <bit>
namespace dusk {
enum ItemType {
@@ -1295,8 +1296,33 @@ namespace dusk {
membit.offDungeonItem(flag);
}
}
static void genCommonAreaFlags(dSv_memBit_c& membit) {
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + 10.0f);
void genMembitFlags(const char* id, dSv_memBit_c& membit) {
genDungeonItemCheckbox(membit, "Got Map", dSv_memBit_c::MAP);
ImGui::SameLine(230.0f);
genDungeonItemCheckbox(membit, "Got Compass", dSv_memBit_c::COMPASS);
genDungeonItemCheckbox(membit, "Got Boss Key", dSv_memBit_c::BOSS_KEY);
ImGui::SameLine(230.0f);
genDungeonItemCheckbox(membit, "Saw Boss Demo", dSv_memBit_c::STAGE_BOSS_DEMO);
genDungeonItemCheckbox(membit, "Got Heart Container", dSv_memBit_c::STAGE_LIFE);
ImGui::SameLine(230.0f);
genDungeonItemCheckbox(membit, "Defeated Boss", dSv_memBit_c::STAGE_BOSS_ENEMY);
genDungeonItemCheckbox(membit, "Defeated Miniboss", dSv_memBit_c::STAGE_BOSS_ENEMY_2);
ImGui::SameLine(230.0f);
genDungeonItemCheckbox(membit, "Got Ooccoo", dSv_memBit_c::OOCCOO_NOTE);
int keyTemp = membit.getKeyNum();
if (ImGui::SliderInt("Keys", &keyTemp, 0, 5)) {
membit.setKeyNum(keyTemp);
}
}
static 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]);
@@ -1322,29 +1348,10 @@ namespace dusk {
drawFlagList(fmt::format("##_item{}", j).c_str(), membit.mItem[j]);
}
ImGuiEndGroupPanel();
ImVec2 post_item_custor = ImGui::GetCursorPos();
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);
}
ImGui::SetCursorPos({post_item_custor.x, post_switch_cursor.y});
// genCommonAreaFlags(membit);
}
template <typename T>
@@ -1392,74 +1399,326 @@ namespace dusk {
}
}
void ImGuiSaveEditor::drawFlagsTab() {
if (ImGui::TreeNode("Current Region Flags")) {
dSv_memBit_c& membit = g_dComIfG_gameInfo.info.mMemory.mBit;
genMembitFlags("##TempSceneFlags", membit);
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;
};
stage_stag_info_class* pstag = dComIfGp_getStageStagInfo();
if (pstag != nullptr) {
int stageNo = dStage_stagInfo_GetSaveTbl(pstag);
if (ImGui::Button("Save##SaveTempFlags")) {
dComIfGs_putSave(stageNo);
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));
}
ImGui::SameLine();
if (ImGui::Button("Load##LoadSaveFlags")) {
dComIfGs_getSave(stageNo);
} 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();
ImGui::TreePop();
}
if (ImGui::TreeNode("Region Saved Flags")) {
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",
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" }
};
if (ImGui::BeginCombo("Region", regionNames[m_selectedRegion])) {
for (int i = 0; i < regionNames.size(); i++) {
if (strcmp(regionNames[i], "Reserved") == 0) continue;
if (m_selectedRegion.name == nullptr)
{
const auto& firstRegion = *regionNames.find(0);
m_selectedRegion = { firstRegion.first, firstRegion.second };
}
if (ImGui::Selectable(regionNames[i])) {
m_selectedRegion = i;
if (ImGui::BeginCombo("Region", m_selectedRegion.name)) {
for (const auto& [id, name] : regionNames) {
if (ImGui::Selectable(name)) {
m_selectedRegion = {id, name};
}
}
ImGui::EndCombo();
}
dSv_memBit_c* membit = &dComIfGs_getSaveData()->mSave[m_selectedRegion].mBit;
if (membit != nullptr) {
genMembitFlags("##SaveSceneFlags", *membit);
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();
}
ImGui::TreePop();
@@ -1530,7 +1789,9 @@ namespace dusk {
}
for (const auto& e : duskImguiEventFlags) {
if (!filter.PassFilter((e.location + "\n" + e.description + "\n" + e.flagName).c_str()))
if (!filter.PassFilter(e.location.c_str()) &&
!filter.PassFilter(e.description.c_str()) &&
!filter.PassFilter(e.flagName.c_str()))
{
continue;
}
+4 -1
View File
@@ -21,7 +21,10 @@ namespace dusk {
void drawConfigTab();
private:
int m_selectedRegion = 0;
struct {
uint8_t id;
const char* name;
} m_selectedRegion = {0, nullptr};
};
}
+1
View File
@@ -999,6 +999,7 @@ int mDoMch_Create() {
JKRDvdRipper::setSZSBufferSize(0x4000);
#if TARGET_PC
JKRHeap* dvdHeap = JKRCreateExpHeap(0x10000, NULL, false);
JKRHEAP_NAME(dvdHeap, "dvdHeap");
assert(dvdHeap != NULL);
JKRDvdRipper::setHeap(dvdHeap);
#endif