mirror of
https://github.com/TwilitRealm/dusklight
synced 2026-07-04 11:19:58 -04:00
Compare commits
71 Commits
tracy-ci
...
rpx-loading
| Author | SHA1 | Date | |
|---|---|---|---|
| 529a61001a | |||
| d23a5c6fd1 | |||
| f5642f3073 | |||
| cc9c15de54 | |||
| 1fd8a2ca3c | |||
| 0c9c8795ce | |||
| 9eb9acfa11 | |||
| ea034bf884 | |||
| 2b266048c6 | |||
| c99241a662 | |||
| 7f503c9d8f | |||
| 776ee9b978 | |||
| f0c2544d53 | |||
| cda5a17c2d | |||
| 645d64a73a | |||
| 849edf4a58 | |||
| 1d1ece9cb2 | |||
| cb85470214 | |||
| 273c58d927 | |||
| 6692eff3a3 | |||
| 43817ea4e5 | |||
| 55ceab9b2d | |||
| 7f2dc7902c | |||
| e345323f0a | |||
| 3d5b55ad33 | |||
| 8182f6123b | |||
| 4d63aa3aad | |||
| 17d9dad1d9 | |||
| dc798a931c | |||
| 55a81adfad | |||
| a2ddd3b580 | |||
| b99ad37541 | |||
| b6b71a32c7 | |||
| 458ffb17c2 | |||
| 7c17b1f5f7 | |||
| e1d0f99fc3 | |||
| 228d4d2bd1 | |||
| a50a8b21e1 | |||
| fd1a9ebd4e | |||
| f73f28b4c6 | |||
| f6d4eba130 | |||
| 20885959b7 | |||
| ae11304c66 | |||
| bd8b3aafeb | |||
| 9c001114f7 | |||
| 34c55700a2 | |||
| a99c8096d5 | |||
| 0b93dd9698 | |||
| be771e1a83 | |||
| e0de71b5b4 | |||
| 010a4b5094 | |||
| a71bd56058 | |||
| 63a86a456f | |||
| 6304866b38 | |||
| 54dbf20480 | |||
| f11d4b14d9 | |||
| 31298f24ba | |||
| 8ae35dc9ea | |||
| 9abb6bafd1 | |||
| 81c0c6f4d3 | |||
| 41fe3a85a2 | |||
| 307f626c57 | |||
| cd0b8b3172 | |||
| 8e55961e3c | |||
| fd204062f7 | |||
| 89b8debe51 | |||
| c498bf8fb8 | |||
| 290f592098 | |||
| 9a80f3a08a | |||
| 41e128c582 | |||
| aa23ae244f |
+1
-1
@@ -1,3 +1,3 @@
|
||||
[submodule "extern/aurora"]
|
||||
path = extern/aurora
|
||||
url = https://github.com/encounter/aurora.git
|
||||
url = https://github.com/Lurs/aurora.git
|
||||
|
||||
+2
-2
@@ -363,7 +363,7 @@ set(DUSK_COPYRIGHT "Copyright (C) Twilit Realm contributors")
|
||||
source_group("dolzel" FILES ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${REL_FILES})
|
||||
source_group("dusklight" FILES ${DUSK_FILES} ${DUSK_HTTP_BACKEND_FILES})
|
||||
|
||||
set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0 MTX_USE_PS=1)
|
||||
set(GAME_COMPILE_DEFS TARGET_PC WIDESCREEN_SUPPORT=1 AVOID_UB=1 VERSION=0 MTX_USE_PS=1 DUSK_TPHD=1)
|
||||
|
||||
set(GAME_INCLUDE_DIRS
|
||||
include
|
||||
@@ -378,7 +378,7 @@ set(GAME_INCLUDE_DIRS
|
||||
find_package(Threads REQUIRED)
|
||||
set(GAME_LIBS aurora::core aurora::gx aurora::gd aurora::si aurora::vi aurora::pad aurora::mtx aurora::os aurora::dvd
|
||||
aurora::card freeverb cxxopts::cxxopts absl::flat_hash_map nlohmann_json::nlohmann_json TracyClient fmt::fmt
|
||||
Threads::Threads zstd::libzstd)
|
||||
Threads::Threads zstd::libzstd ZLIB::ZLIB)
|
||||
|
||||
if (DUSK_ENABLE_SENTRY_NATIVE)
|
||||
list(APPEND GAME_LIBS sentry)
|
||||
|
||||
Vendored
+1
-1
Submodule extern/aurora updated: 3f1c26f2a6...cc1b2e3e5a
+10
@@ -1546,6 +1546,16 @@ set(DUSK_FILES
|
||||
src/dusk/discord_presence.cpp
|
||||
src/dusk/version.cpp
|
||||
src/dusk/action_bindings.cpp
|
||||
src/dusk/tphd/TphdPack.hpp
|
||||
src/dusk/tphd/TphdPack.cpp
|
||||
src/dusk/tphd/GtxParser.hpp
|
||||
src/dusk/tphd/GtxParser.cpp
|
||||
src/dusk/tphd/AddrLib.hpp
|
||||
src/dusk/tphd/AddrLib.cpp
|
||||
src/dusk/tphd/HdAssetLayer.hpp
|
||||
src/dusk/tphd/HdAssetLayer.cpp
|
||||
src/dusk/tphd/LosTable.hpp
|
||||
src/dusk/tphd/LosTable.cpp
|
||||
)
|
||||
|
||||
set(DUSK_HTTP_BACKEND_FILES
|
||||
|
||||
@@ -158,6 +158,10 @@ enum Z2Scene {
|
||||
/* 0x4E */ Z2SCENE_GROTTO_ROCK_2,
|
||||
/* 0x4F */ Z2SCENE_GROTTO_POND,
|
||||
/* 0x50 */ Z2SCENE_FARON_WOODS_CAVE,
|
||||
|
||||
#if TARGET_PC
|
||||
/* 0x51 */ Z2SCENE_CAVE_OF_SHADOWS,
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* Z2SCENEMGR_H */
|
||||
|
||||
@@ -4556,10 +4556,12 @@ public:
|
||||
void handleWolfHowl();
|
||||
void handleQuickTransform();
|
||||
bool checkAimContext();
|
||||
bool checkTouchAimCaptureContext();
|
||||
bool checkAimInputContext();
|
||||
|
||||
void onIronBallChainInterpCallback();
|
||||
|
||||
f32 mLosStickValue;
|
||||
|
||||
static const int IRON_BALL_CHAIN_COUNT = 102;
|
||||
cXyz mIBChainInterpPrevPos[IRON_BALL_CHAIN_COUNT];
|
||||
cXyz mIBChainInterpCurrPos[IRON_BALL_CHAIN_COUNT];
|
||||
|
||||
@@ -18,16 +18,24 @@ public:
|
||||
TGXTexObj& getTexObj() { return mTexObj; }
|
||||
cXyz* getQuad() { return mQuad; }
|
||||
|
||||
#if TARGET_PC
|
||||
// TP HD reflects across N floor quads (F_SP117 room 2 uses 6); GC uses 1.
|
||||
static const int MAX_QUADS = 6;
|
||||
#endif
|
||||
|
||||
/* 0x010 */ TGXTexObj mTexObj;
|
||||
/* 0x030 */ u8 mModelCount;
|
||||
/* 0x034 */ J3DModel* mModels[0x40];
|
||||
/* 0x134 */ cXyz mQuad[4];
|
||||
/* 0x134 */ cXyz mQuad[DUSK_IF_ELSE(MAX_QUADS*4, 4)];
|
||||
/* 0x164 */ cXyz mMinVal;
|
||||
/* 0x170 */ cXyz mMaxVal;
|
||||
/* 0x17C */ cXyz mViewScale;
|
||||
#if TARGET_PC
|
||||
bool mbReset = false;
|
||||
bool mbHadEntry = false;
|
||||
cXyz mQuadBoxMin[MAX_QUADS];
|
||||
cXyz mQuadBoxMax[MAX_QUADS];
|
||||
int mQuadCount = 1;
|
||||
#endif
|
||||
};
|
||||
|
||||
|
||||
@@ -142,12 +142,12 @@ namespace daObjSwpush {
|
||||
int Mthd_Execute();
|
||||
int Mthd_Draw();
|
||||
|
||||
static s16 const M_bmd[3];
|
||||
static s16 const M_dzb[3];
|
||||
static u32 const M_heap_size[3];
|
||||
static s16 const M_bmd[DUSK_IF_ELSE(4, 3)];
|
||||
static s16 const M_dzb[DUSK_IF_ELSE(4, 3)];
|
||||
static u32 const M_heap_size[DUSK_IF_ELSE(4, 3)];
|
||||
static Hio_c::Attr_c const M_attr[5];
|
||||
static u8 const M_op_vtx[4];
|
||||
static DUSK_CONST char* M_arcname[3];
|
||||
static DUSK_CONST char* M_arcname[DUSK_IF_ELSE(4, 3)];
|
||||
|
||||
/* 0x568 */ request_of_phase_process_class mPhase;
|
||||
/* 0x570 */ dBgWSv* mpBgW;
|
||||
|
||||
@@ -400,4 +400,8 @@ BOOL isBottleItem(u8 item_no);
|
||||
u8 check_itemno(int i_itemNo);
|
||||
BOOL isInsect(u8 i_itemNo);
|
||||
|
||||
#if TARGET_PC
|
||||
void item_func_WALLET_LV4();
|
||||
#endif
|
||||
|
||||
#endif /* D_D_ITEM_H */
|
||||
|
||||
@@ -350,4 +350,11 @@ enum {
|
||||
/* 0xFF */ dItemNo_NONE_e,
|
||||
};
|
||||
|
||||
#if TARGET_PC
|
||||
// HD item mappings
|
||||
enum {
|
||||
dItemNo_WALLET_LV4_e = 0xDA,
|
||||
};
|
||||
#endif
|
||||
|
||||
#endif /* D_D_ITEM_DATA_H */
|
||||
|
||||
@@ -57,7 +57,7 @@ public:
|
||||
return &mpTypeGroupData[i_typeGroupNo];
|
||||
}
|
||||
|
||||
/* 0x0 */ fmpTresTypeGroupDataList_c mpTypeGroupData[17];
|
||||
/* 0x0 */ fmpTresTypeGroupDataList_c mpTypeGroupData[DUSK_IF_ELSE(35, 17)];
|
||||
};
|
||||
|
||||
class dMenu_Fmap_data_c {
|
||||
|
||||
+11
-2
@@ -172,6 +172,15 @@ public:
|
||||
int event041(mesg_flow_node_event*, fopAc_ac_c*);
|
||||
int event042(mesg_flow_node_event*, fopAc_ac_c*);
|
||||
|
||||
#if TARGET_PC
|
||||
// HD additions
|
||||
u16 query054(mesg_flow_node_branch*, fopAc_ac_c*, int);
|
||||
u16 query055(mesg_flow_node_branch*, fopAc_ac_c*, int);
|
||||
int event043(mesg_flow_node_event*, fopAc_ac_c*);
|
||||
int event044(mesg_flow_node_event*, fopAc_ac_c*);
|
||||
int event045(mesg_flow_node_event*, fopAc_ac_c*);
|
||||
#endif
|
||||
|
||||
void initWord(fopAc_ac_c*, const char*, u8, int, fopAc_ac_c**);
|
||||
|
||||
#if DEBUG
|
||||
@@ -185,8 +194,8 @@ public:
|
||||
void setMsg(u32 msg) { mMsg = msg; }
|
||||
bool checkEndFlow() { return (u32)field_0x26 == 1; }
|
||||
|
||||
static queryFunc mQueryList[53];
|
||||
static eventFunc mEventList[43];
|
||||
static queryFunc mQueryList[DUSK_IF_ELSE(55, 53)];
|
||||
static eventFunc mEventList[DUSK_IF_ELSE(46, 43)];
|
||||
|
||||
private:
|
||||
/* 0x04 */ u8* mFlow_p;
|
||||
|
||||
@@ -1416,6 +1416,11 @@ dStage_KeepDoorInfo* dStage_GetKeepDoorInfo();
|
||||
dStage_KeepDoorInfo* dStage_GetRoomKeepDoorInfo();
|
||||
void dStage_dt_c_fieldMapLoader(void* i_data, dStage_dt_c* i_stage);
|
||||
|
||||
#if TARGET_PC
|
||||
// TP HD Cave of Shadows (D_SB11): reveal the los next-floor when a descent gate opens.
|
||||
void dStage_showLOSNextFloor(int fromRoom);
|
||||
#endif
|
||||
|
||||
#if DEBUG
|
||||
void dStage_DebugDisp();
|
||||
#endif
|
||||
|
||||
@@ -28,4 +28,11 @@ bool LoadRelAsset(void* dst, const char* dvdPath, std::initializer_list<OffsetVe
|
||||
*/
|
||||
bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, std::initializer_list<OffsetVersion> offset, s32 size);
|
||||
|
||||
#ifdef DUSK_TPHD
|
||||
/**
|
||||
* Load bytes from the RPX by Wii U virtual address
|
||||
*/
|
||||
bool LoadRPXAsset(void* dst, uint32_t virtualAddress, s32 size);
|
||||
#endif
|
||||
|
||||
} // namespace dusk
|
||||
|
||||
@@ -602,6 +602,50 @@ static const auto gameRegions = std::to_array({
|
||||
MapEntry("Grotto 5", "D_SB09", {
|
||||
{4, {0, 1}},
|
||||
}),
|
||||
MapEntry("HD: Cave Of Shadows", "D_SB11", {
|
||||
// ordered by floor rather than room number
|
||||
{19, {0}},
|
||||
{35, {0}},
|
||||
{21, {0}},
|
||||
{23, {0}},
|
||||
{10, {0}},
|
||||
{25, {0}},
|
||||
{26, {0}},
|
||||
{8, {0}},
|
||||
{5, {0}},
|
||||
{28, {0}},
|
||||
{47, {0}},
|
||||
{15, {0}},
|
||||
{22, {0}},
|
||||
{33, {0}},
|
||||
{31, {0}},
|
||||
{7, {0}},
|
||||
{13, {0}},
|
||||
{46, {0}},
|
||||
{48, {0}},
|
||||
{34, {0}},
|
||||
{2, {0}},
|
||||
{36, {0}},
|
||||
{27, {0}},
|
||||
{32, {0}},
|
||||
{18, {0}},
|
||||
{3, {0}},
|
||||
{44, {0}},
|
||||
{40, {0}},
|
||||
{4, {0}},
|
||||
{30, {0}},
|
||||
{29, {0}},
|
||||
{17, {0}},
|
||||
{41, {0}},
|
||||
{43, {0}},
|
||||
{16, {0}},
|
||||
{38, {0}},
|
||||
{1, {0}},
|
||||
{42, {0}},
|
||||
{45, {0}},
|
||||
{49, {0}},
|
||||
}
|
||||
),
|
||||
}),
|
||||
RegionEntry("Misc", {
|
||||
MapEntry("Title Screen / King Bulblin 1", "F_SP102", {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <filesystem>
|
||||
|
||||
#include "dusk/config_var.hpp"
|
||||
#include "dusk/ui/controls.hpp"
|
||||
@@ -273,6 +274,9 @@ struct UserSettings {
|
||||
struct {
|
||||
ConfigVar<std::string> isoPath;
|
||||
ConfigVar<DiscVerificationState> isoVerification;
|
||||
#if DUSK_TPHD
|
||||
ConfigVar<std::string> hdContentPath;
|
||||
#endif
|
||||
ConfigVar<std::string> graphicsBackend;
|
||||
ConfigVar<bool> skipPreLaunchUI;
|
||||
ConfigVar<bool> showPipelineCompilation;
|
||||
@@ -295,6 +299,9 @@ struct UserSettings {
|
||||
|
||||
UserSettings& getSettings();
|
||||
|
||||
std::filesystem::path tphd_content_path();
|
||||
bool tphd_active();
|
||||
|
||||
void registerSettings();
|
||||
|
||||
// Transient settings
|
||||
|
||||
@@ -1761,6 +1761,16 @@ public:
|
||||
virtual ~J3DIndBlockNull() {}
|
||||
};
|
||||
|
||||
#ifdef DUSK_TPHD
|
||||
struct PolygonOffset {
|
||||
BE(f32) mFrontOffset;
|
||||
BE(f32) mFrontScale;
|
||||
BE(f32) mBackOffset;
|
||||
BE(f32) mBackScale;
|
||||
BE(f32) mClamp;
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup jsystem-j3d
|
||||
*
|
||||
@@ -1793,6 +1803,10 @@ public:
|
||||
virtual void setDither(u8 const*) {}
|
||||
virtual void setDither(u8) {}
|
||||
virtual u8 getDither() const { return 0; }
|
||||
#ifdef DUSK_TPHD
|
||||
virtual void setPolygonOffset(const PolygonOffset&) {}
|
||||
virtual PolygonOffset* getPolygonOffset() { return NULL; }
|
||||
#endif
|
||||
virtual u32 getFogOffset() const { return 0; }
|
||||
virtual void setFogOffset(u32) {}
|
||||
virtual ~J3DPEBlock() {}
|
||||
@@ -1956,12 +1970,25 @@ public:
|
||||
virtual void setFogOffset(u32 fogOffset) { mFogOffset = fogOffset; }
|
||||
virtual ~J3DPEBlockFull() {}
|
||||
|
||||
#ifdef DUSK_TPHD
|
||||
virtual void setPolygonOffset(const PolygonOffset& offset) {
|
||||
mPolygonOffset = offset;
|
||||
}
|
||||
|
||||
virtual PolygonOffset* getPolygonOffset() {
|
||||
return &mPolygonOffset;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* 0x04 */ J3DFog mFog;
|
||||
/* 0x30 */ J3DAlphaComp mAlphaComp;
|
||||
/* 0x34 */ J3DBlend mBlend;
|
||||
/* 0x38 */ J3DZMode mZMode;
|
||||
/* 0x3A */ u8 mZCompLoc;
|
||||
/* 0x3B */ u8 mDither;
|
||||
#ifdef DUSK_TPHD
|
||||
PolygonOffset mPolygonOffset;
|
||||
#endif
|
||||
/* 0x3C */ u32 mFogOffset;
|
||||
}; // Size: 0x40
|
||||
|
||||
|
||||
@@ -46,6 +46,13 @@ struct J3DMaterialInitData {
|
||||
/* 0x14A */ BE(u16) mNBTScaleIdx;
|
||||
}; // size 0x14C
|
||||
|
||||
|
||||
#ifdef DUSK_TPHD
|
||||
struct J3DMaterialInitData_MAT4 : public J3DMaterialInitData {
|
||||
/* 0x14C */ BE(u16) mPolygonOffsetIdx;
|
||||
}; // size 0x14E
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup jsystem-j3d
|
||||
*
|
||||
@@ -143,10 +150,29 @@ public:
|
||||
J3DNBTScale newNBTScale(int) const;
|
||||
|
||||
u16 getMaterialID(int idx) const { return mpMaterialID[idx]; }
|
||||
#ifdef DUSK_TPHD
|
||||
u8 getMaterialMode(int idx) const { return getMatInitData(idx)->mMaterialMode; }
|
||||
#else
|
||||
u8 getMaterialMode(int idx) const { return mpMaterialInitData[mpMaterialID[idx]].mMaterialMode; }
|
||||
#endif
|
||||
|
||||
#if DUSK_TPHD
|
||||
const PolygonOffset newPolygonOffset(int) const;
|
||||
|
||||
J3DMaterialInitData* getMatInitData(int idx) const {
|
||||
static const u32 sInitDataSizes[] = {0, 0, 0x138, 0x14C, 0x14E};
|
||||
|
||||
return (J3DMaterialInitData*)((u8*)mpMaterialInitData + sInitDataSizes[mBlockType] * getMaterialID(idx));
|
||||
}
|
||||
|
||||
u16 mBlockType;
|
||||
#endif
|
||||
/* 0x00 */ u16 mMaterialNum;
|
||||
#if DUSK_TPHD
|
||||
/* 0x04 */ void* mpMaterialInitData;
|
||||
#else
|
||||
/* 0x04 */ J3DMaterialInitData* mpMaterialInitData;
|
||||
#endif
|
||||
/* 0x08 */ BE(u16)* mpMaterialID;
|
||||
/* 0x0C */ J3DIndInitData* mpIndInitData;
|
||||
/* 0x10 */ GXColor* mpMatColor;
|
||||
@@ -175,6 +201,9 @@ public:
|
||||
/* 0x6C */ u8* mpZCompLoc;
|
||||
/* 0x70 */ u8* mpDither;
|
||||
/* 0x74 */ J3DNBTScaleInfo* mpNBTScaleInfo;
|
||||
#ifdef DUSK_TPHD
|
||||
PolygonOffset* mpPolygonOffsets;
|
||||
#endif
|
||||
/* 0x78 */ J3DDisplayListInit* mpDisplayListInit;
|
||||
/* 0x7C */ J3DPatchingInfo* mpPatchingInfo;
|
||||
/* 0x80 */ J3DCurrentMtxInfo* mpCurrentMtxInfo;
|
||||
|
||||
@@ -169,6 +169,12 @@ struct J3DMaterialBlock_v21 : public J3DModelBlock {
|
||||
/* 0x74 */ OFFSET_PTR_V0 mpNBTScaleInfo;
|
||||
};
|
||||
|
||||
#ifdef DUSK_TPHD
|
||||
struct J3DMaterialBlock_MAT4 : public J3DMaterialBlock {
|
||||
/* 0x84 */ OFFSET_PTR_V0 mpPolygonOffsets;
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @ingroup jsystem-j3d
|
||||
*
|
||||
|
||||
@@ -7,6 +7,9 @@
|
||||
#include "JSystem/J3DGraphBase/J3DMaterial.h"
|
||||
#include "JSystem/JMath/JMath.h"
|
||||
#include "m_Do/m_Do_mtx.h"
|
||||
#if TARGET_PC
|
||||
#include "dusk/settings.h"
|
||||
#endif
|
||||
|
||||
void J3DMtxCalcJ3DSysInitBasic::init(Vec const& scale, Mtx const& mtx) {
|
||||
J3DSys::mCurrentS = scale;
|
||||
@@ -178,7 +181,23 @@ void J3DJoint::entryIn() {
|
||||
matPacket->setMaterialAnmID(mesh->getMaterialAnm());
|
||||
matPacket->setShapePacket(shapePacket);
|
||||
bool isDrawModeOpaTexEdge = mesh->isDrawModeOpaTexEdge() == FALSE;
|
||||
#if TARGET_PC
|
||||
// TP HD J3DJoint::entryIn (FUN_02b57690):
|
||||
J3DDrawBuffer* drawBuffer = j3dSys.getDrawBuffer(isDrawModeOpaTexEdge);
|
||||
u8 r24;
|
||||
if (dusk::tphd_active() && (mesh->mMaterialID & 0x80000000) != 0 &&
|
||||
(mesh->getMaterialMode() & 0x20) != 0 &&
|
||||
drawBuffer->getSortMode() == J3DDrawBufSortMode_Mat)
|
||||
{
|
||||
matPacket->drawClear();
|
||||
shapePacket->drawClear();
|
||||
r24 = drawBuffer->entryImm(matPacket, 1);
|
||||
} else {
|
||||
r24 = matPacket->entry(drawBuffer);
|
||||
}
|
||||
#else
|
||||
u8 r24 = matPacket->entry(j3dSys.getDrawBuffer(isDrawModeOpaTexEdge));
|
||||
#endif
|
||||
if (r24) {
|
||||
j3dSys.setMatPacket(matPacket);
|
||||
J3DDrawBuffer::entryNum++;
|
||||
|
||||
@@ -230,6 +230,13 @@ void J3DMatPacket::draw() {
|
||||
#endif
|
||||
packet->getShape()->loadPreDrawSetting();
|
||||
|
||||
#if DUSK_TPHD
|
||||
{
|
||||
const auto* offs = mpMaterial->getPEBlock()->getPolygonOffset();
|
||||
GX2SetPolygonOffset(offs->mFrontOffset, offs->mFrontScale, offs->mBackOffset, offs->mBackScale, offs->mClamp);
|
||||
}
|
||||
#endif
|
||||
|
||||
while (packet != NULL) {
|
||||
if (packet->getDisplayListObj() != NULL) {
|
||||
packet->getDisplayListObj()->callDL();
|
||||
|
||||
@@ -12,6 +12,9 @@
|
||||
#include "dusk/logging.h"
|
||||
|
||||
J3DMaterialFactory::J3DMaterialFactory(J3DMaterialBlock const& i_block) {
|
||||
#ifdef DUSK_TPHD
|
||||
mBlockType = (i_block.mBlockType & 0xFF) - 0x30; // get number at last byte of block name
|
||||
#endif
|
||||
mMaterialNum = i_block.mMaterialNum;
|
||||
mpMaterialInitData = JSUConvertOffsetToPtr<J3DMaterialInitData>(&i_block, i_block.mpMaterialInitData);
|
||||
mpMaterialID = JSUConvertOffsetToPtr<BE(u16)>(&i_block, i_block.mpMaterialID);
|
||||
@@ -46,6 +49,11 @@ J3DMaterialFactory::J3DMaterialFactory(J3DMaterialBlock const& i_block) {
|
||||
mpZCompLoc = JSUConvertOffsetToPtr<u8>(&i_block, i_block.mpZCompLoc);
|
||||
mpDither = JSUConvertOffsetToPtr<u8>(&i_block, i_block.mpDither);
|
||||
mpNBTScaleInfo = JSUConvertOffsetToPtr<J3DNBTScaleInfo>(&i_block, i_block.mpNBTScaleInfo);
|
||||
#ifdef DUSK_TPHD
|
||||
if(mBlockType >= 4) {
|
||||
mpPolygonOffsets = JSUConvertOffsetToPtr<PolygonOffset>(&i_block, reinterpret_cast<const J3DMaterialBlock_MAT4&>(i_block).mpPolygonOffsets);
|
||||
}
|
||||
#endif
|
||||
mpDisplayListInit = NULL;
|
||||
mpPatchingInfo = NULL;
|
||||
mpCurrentMtxInfo = NULL;
|
||||
@@ -74,7 +82,11 @@ u16 J3DMaterialFactory::countUniqueMaterials() {
|
||||
}
|
||||
|
||||
u32 J3DMaterialFactory::countTexGens(int i_idx) const {
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
if (mtl_init_data->mTexGenNumIdx != 0xff) {
|
||||
return mpTexGenNum[mtl_init_data->mTexGenNumIdx];
|
||||
}
|
||||
@@ -82,7 +94,11 @@ u32 J3DMaterialFactory::countTexGens(int i_idx) const {
|
||||
}
|
||||
|
||||
u32 J3DMaterialFactory::countStages(int i_idx) const {
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
u32 count1 = 0;
|
||||
u32 count2 = 0;
|
||||
if (mtl_init_data->mTevStageNumIdx != 0xff) {
|
||||
@@ -157,6 +173,9 @@ J3DMaterial* J3DMaterialFactory::createNormalMaterial(J3DMaterial* i_material, i
|
||||
i_material->mPEBlock->setZMode(newZMode(i_idx));
|
||||
i_material->mPEBlock->setZCompLoc(newZCompLoc(i_idx));
|
||||
i_material->mPEBlock->setDither(newDither(i_idx));
|
||||
#ifdef DUSK_TPHD
|
||||
i_material->mPEBlock->setPolygonOffset(newPolygonOffset(i_idx));
|
||||
#endif
|
||||
i_material->mTevBlock->setTevStageNum(newTevStageNum(i_idx));
|
||||
for (u8 i = 0; i < tex_num; i++) {
|
||||
i_material->mTevBlock->setTexNo(i, newTexNo(i_idx, i));
|
||||
@@ -165,7 +184,11 @@ J3DMaterial* J3DMaterialFactory::createNormalMaterial(J3DMaterial* i_material, i
|
||||
i_material->mTevBlock->setTevOrder(i, newTevOrder(i_idx, i));
|
||||
}
|
||||
for (u8 i = 0; i < tev_stage_num_max; i++) {
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* material_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* material_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
i_material->mTevBlock->setTevStage(i, newTevStage(i_idx, i));
|
||||
if (material_init_data->mTevSwapModeIdx[i] != 0xffff) {
|
||||
i_material->mTevBlock->getTevStage(i)->setTexSel(
|
||||
@@ -200,7 +223,11 @@ J3DMaterial* J3DMaterialFactory::createNormalMaterial(J3DMaterial* i_material, i
|
||||
for (u8 i = 0; i < 8; i++) {
|
||||
i_material->mTexGenBlock->setTexMtx(i, newTexMtx(i_idx, i));
|
||||
}
|
||||
J3DMaterialInitData* material_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* material_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* material_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
for (u8 i = 0; i < tev_stage_num_max; i++) {
|
||||
if (material_init_data->mTevKColorSel[i] != 0xff) {
|
||||
i_material->mTevBlock->setTevKColorSel(i, material_init_data->mTevKColorSel[i]);
|
||||
@@ -273,7 +300,11 @@ J3DMaterial* J3DMaterialFactory::createPatchedMaterial(J3DMaterial* i_material,
|
||||
i_material->mTevBlock->setTevColor(i, newTevColor(i_idx, i));
|
||||
}
|
||||
for (u8 i = 0; i < tev_stage_num; i++) {
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* material_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* material_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
i_material->mTevBlock->setTevStage(i, newTevStage(i_idx, i));
|
||||
if (material_init_data->mTevSwapModeIdx[i] != 0xffff) {
|
||||
i_material->mTevBlock->getTevStage(i)->setTexSel(
|
||||
@@ -282,7 +313,11 @@ J3DMaterial* J3DMaterialFactory::createPatchedMaterial(J3DMaterial* i_material,
|
||||
mpTevSwapModeInfo[material_init_data->mTevSwapModeIdx[i]].mRasSel);
|
||||
}
|
||||
}
|
||||
J3DMaterialInitData* init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
for (u8 i = 0; i < tev_stage_num; i++) {
|
||||
if (init_data->mTevKColorSel[i] != 0xff) {
|
||||
i_material->mTevBlock->setTevKColorSel(i, init_data->mTevKColorSel[i]);
|
||||
@@ -423,7 +458,11 @@ u32 J3DMaterialFactory::calcSizeNormalMaterial(J3DMaterial* i_material, int i_id
|
||||
size += J3DMaterial::calcSizeTevBlock((u16)tev_stage_num_max);
|
||||
size += J3DMaterial::calcSizeIndBlock(ind_flag);
|
||||
size += J3DMaterial::calcSizePEBlock(pe_flag, getMaterialMode(i_idx));
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
for (u32 i = 0; i < 8; i++) {
|
||||
if (init_data->mTexMtxIdx[i] != 0xffff) {
|
||||
size += sizeof(J3DTexMtx);
|
||||
@@ -444,7 +483,11 @@ u32 J3DMaterialFactory::calcSizePatchedMaterial(J3DMaterial* i_material, int i_i
|
||||
size += sizeof(J3DTevBlockPatched);
|
||||
size += J3DMaterial::calcSizeIndBlock(ind_flag);
|
||||
size += J3DMaterial::calcSizePEBlock(0x10000000, getMaterialMode(i_idx));
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
for (u32 i = 0; i < 8; i++) {
|
||||
if (init_data->mTexMtxIdx[i] != 0xffff) {
|
||||
size += sizeof(J3DTexMtx);
|
||||
@@ -474,7 +517,11 @@ J3DGXColor J3DMaterialFactory::newMatColor(int i_idx, int i_no) const {
|
||||
#else
|
||||
J3DGXColor dflt = GXColor{0xff, 0xff, 0xff, 0xff};
|
||||
#endif
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
if (mtl_init_data->mMatColorIdx[i_no] != 0xffff) {
|
||||
return (GXColor) mpMatColor[mtl_init_data->mMatColorIdx[i_no]];
|
||||
} else {
|
||||
@@ -483,7 +530,11 @@ J3DGXColor J3DMaterialFactory::newMatColor(int i_idx, int i_no) const {
|
||||
}
|
||||
|
||||
const u8 J3DMaterialFactory::newColorChanNum(int i_idx) const {
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
if (mtl_init_data->mColorChanNumIdx != 0xff) {
|
||||
return mpColorChanNum[mtl_init_data->mColorChanNumIdx];
|
||||
} else {
|
||||
@@ -493,7 +544,11 @@ const u8 J3DMaterialFactory::newColorChanNum(int i_idx) const {
|
||||
|
||||
J3DColorChan J3DMaterialFactory::newColorChan(int i_idx, int i_no) const {
|
||||
u32 r29 = 0;
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
if (init_data->mColorChanIdx[i_no] != 0xffff) {
|
||||
return J3DColorChan(mpColorChanInfo[init_data->mColorChanIdx[i_no]]);
|
||||
} else {
|
||||
@@ -507,7 +562,11 @@ J3DGXColor J3DMaterialFactory::newAmbColor(int i_idx, int i_no) const {
|
||||
#else
|
||||
J3DGXColor dflt = GXColor{0x32, 0x32, 0x32, 0x32};
|
||||
#endif
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
if (mtl_init_data->mAmbColorIdx[i_no] != 0xffff) {
|
||||
return (GXColor) mpAmbColor[mtl_init_data->mAmbColorIdx[i_no]];
|
||||
} else {
|
||||
@@ -517,7 +576,11 @@ J3DGXColor J3DMaterialFactory::newAmbColor(int i_idx, int i_no) const {
|
||||
|
||||
u32 J3DMaterialFactory::newTexGenNum(int i_idx) const {
|
||||
u32 r30 = 0;
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
if (mtl_init_data->mTexGenNumIdx != 0xff) {
|
||||
return mpTexGenNum[mtl_init_data->mTexGenNumIdx];
|
||||
} else {
|
||||
@@ -526,7 +589,11 @@ u32 J3DMaterialFactory::newTexGenNum(int i_idx) const {
|
||||
}
|
||||
|
||||
J3DTexCoord J3DMaterialFactory::newTexCoord(int i_idx, int i_no) const {
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
if (mtl_init_data->mTexCoordIdx[i_no] != 0xffff) {
|
||||
return J3DTexCoord(mpTexCoordInfo[mtl_init_data->mTexCoordIdx[i_no]]);
|
||||
} else {
|
||||
@@ -536,7 +603,11 @@ J3DTexCoord J3DMaterialFactory::newTexCoord(int i_idx, int i_no) const {
|
||||
|
||||
J3DTexMtx* J3DMaterialFactory::newTexMtx(int i_idx, int i_no) const {
|
||||
J3DTexMtx* tex_mtx = NULL;
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
if (mtl_init_data->mTexMtxIdx[i_no] != 0xffff) {
|
||||
#if TARGET_LITTLE_ENDIAN
|
||||
auto tex_mtx_info = mpTexMtxInfo[mtl_init_data->mTexMtxIdx[i_no]];
|
||||
@@ -558,7 +629,11 @@ J3DTexMtx* J3DMaterialFactory::newTexMtx(int i_idx, int i_no) const {
|
||||
|
||||
u8 J3DMaterialFactory::newCullMode(int i_idx) const {
|
||||
u32 r30 = 0;
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
if (mtl_init_data->mCullModeIdx != 0xff) {
|
||||
return mpCullMode[mtl_init_data->mCullModeIdx];
|
||||
} else {
|
||||
@@ -567,7 +642,11 @@ u8 J3DMaterialFactory::newCullMode(int i_idx) const {
|
||||
}
|
||||
|
||||
u16 J3DMaterialFactory::newTexNo(int i_idx, int i_no) const {
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
if (mtl_init_data->mTexNoIdx[i_no] != 0xffff) {
|
||||
return mpTexNo[mtl_init_data->mTexNoIdx[i_no]];
|
||||
} else {
|
||||
@@ -576,7 +655,11 @@ u16 J3DMaterialFactory::newTexNo(int i_idx, int i_no) const {
|
||||
}
|
||||
|
||||
J3DTevOrder J3DMaterialFactory::newTevOrder(int i_idx, int i_no) const {
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
if (mtl_init_data->mTevOrderIdx[i_no] != 0xffff) {
|
||||
return J3DTevOrder(mpTevOrderInfo[mtl_init_data->mTevOrderIdx[i_no]]);
|
||||
} else {
|
||||
@@ -587,7 +670,11 @@ J3DTevOrder J3DMaterialFactory::newTevOrder(int i_idx, int i_no) const {
|
||||
J3DGXColorS10 J3DMaterialFactory::newTevColor(int i_idx, int i_no) const {
|
||||
GXColorS10 _dflt = {0, 0, 0, 0};
|
||||
J3DGXColorS10 dflt = _dflt;
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
if (mtl_init_data->mTevColorIdx[i_no] != 0xffff) {
|
||||
return (GXColorS10) mpTevColor[mtl_init_data->mTevColorIdx[i_no]];
|
||||
} else {
|
||||
@@ -601,7 +688,11 @@ J3DGXColor J3DMaterialFactory::newTevKColor(int i_idx, int i_no) const {
|
||||
#else
|
||||
J3DGXColor dflt = GXColor{0xff, 0xff, 0xff, 0xff};
|
||||
#endif
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
if (mtl_init_data->mTevKColorIdx[i_no] != 0xffff) {
|
||||
return (GXColor) mpTevKColor[mtl_init_data->mTevKColorIdx[i_no]];
|
||||
} else {
|
||||
@@ -610,7 +701,11 @@ J3DGXColor J3DMaterialFactory::newTevKColor(int i_idx, int i_no) const {
|
||||
}
|
||||
|
||||
const u8 J3DMaterialFactory::newTevStageNum(int i_idx) const {
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
if (mtl_init_data->mTevStageNumIdx != 0xff) {
|
||||
return mpTevStageNum[mtl_init_data->mTevStageNumIdx];
|
||||
} else {
|
||||
@@ -619,7 +714,11 @@ const u8 J3DMaterialFactory::newTevStageNum(int i_idx) const {
|
||||
}
|
||||
|
||||
J3DTevStage J3DMaterialFactory::newTevStage(int i_idx, int i_no) const {
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
if (mtl_init_data->mTevStageIdx[i_no] != 0xffff) {
|
||||
return J3DTevStage(mpTevStageInfo[mtl_init_data->mTevStageIdx[i_no]]);
|
||||
} else {
|
||||
@@ -628,7 +727,11 @@ J3DTevStage J3DMaterialFactory::newTevStage(int i_idx, int i_no) const {
|
||||
}
|
||||
|
||||
J3DTevSwapModeTable J3DMaterialFactory::newTevSwapModeTable(int i_idx, int i_no) const {
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
if (mtl_init_data->mTevSwapModeTableIdx[i_no] != 0xffff) {
|
||||
return J3DTevSwapModeTable(mpTevSwapModeTableInfo[mtl_init_data->mTevSwapModeTableIdx[i_no]]);
|
||||
} else {
|
||||
@@ -689,7 +792,11 @@ J3DIndTexCoordScale J3DMaterialFactory::newIndTexCoordScale(int i_idx, int i_no)
|
||||
|
||||
J3DFog J3DMaterialFactory::newFog(int i_idx) const {
|
||||
J3DFog fog;
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
if (mtl_init_data->mFogIdx != 0xffff) {
|
||||
#if TARGET_LITTLE_ENDIAN
|
||||
J3DFogInfo fogInfo = mpFogInfo[mtl_init_data->mFogIdx];
|
||||
@@ -709,7 +816,11 @@ J3DFog J3DMaterialFactory::newFog(int i_idx) const {
|
||||
}
|
||||
|
||||
J3DAlphaComp J3DMaterialFactory::newAlphaComp(int i_idx) const {
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
if (mtl_init_data->mAlphaCompIdx != 0xffff) {
|
||||
return J3DAlphaComp(mpAlphaCompInfo[mtl_init_data->mAlphaCompIdx]);
|
||||
} else {
|
||||
@@ -718,7 +829,11 @@ J3DAlphaComp J3DMaterialFactory::newAlphaComp(int i_idx) const {
|
||||
}
|
||||
|
||||
J3DBlend J3DMaterialFactory::newBlend(int i_idx) const {
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
if (mtl_init_data->mBlendIdx != 0xffff) {
|
||||
return J3DBlend(mpBlendInfo[mtl_init_data->mBlendIdx]);
|
||||
} else {
|
||||
@@ -728,7 +843,11 @@ J3DBlend J3DMaterialFactory::newBlend(int i_idx) const {
|
||||
|
||||
J3DZMode J3DMaterialFactory::newZMode(int i_idx) const {
|
||||
u32 r29 = 0;
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
if (mtl_init_data->mZModeIdx != 0xff) {
|
||||
return J3DZMode(mpZModeInfo[mtl_init_data->mZModeIdx]);
|
||||
} else {
|
||||
@@ -737,7 +856,11 @@ J3DZMode J3DMaterialFactory::newZMode(int i_idx) const {
|
||||
}
|
||||
|
||||
const u8 J3DMaterialFactory::newZCompLoc(int i_idx) const {
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
if (mtl_init_data->mZCompLocIdx != 0xff){
|
||||
return mpZCompLoc[mtl_init_data->mZCompLocIdx];
|
||||
} else {
|
||||
@@ -746,7 +869,11 @@ const u8 J3DMaterialFactory::newZCompLoc(int i_idx) const {
|
||||
}
|
||||
|
||||
const u8 J3DMaterialFactory::newDither(int i_idx) const {
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
if (mtl_init_data->mDitherIdx != 0xff){
|
||||
return mpDither[mtl_init_data->mDitherIdx];
|
||||
} else {
|
||||
@@ -754,9 +881,24 @@ const u8 J3DMaterialFactory::newDither(int i_idx) const {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DUSK_TPHD
|
||||
const PolygonOffset J3DMaterialFactory::newPolygonOffset(int i_idx) const {
|
||||
J3DMaterialInitData_MAT4* mtl_init_data = (J3DMaterialInitData_MAT4*)getMatInitData(i_idx);
|
||||
if (mBlockType >= 4 && mtl_init_data->mPolygonOffsetIdx != 0xffff){
|
||||
return mpPolygonOffsets[mtl_init_data->mPolygonOffsetIdx];
|
||||
} else {
|
||||
return PolygonOffset{0.0f, 0.0f, 0.0f, 0.0f, 0.0f};
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
J3DNBTScale J3DMaterialFactory::newNBTScale(int i_idx) const {
|
||||
J3DNBTScale dflt(j3dDefaultNBTScaleInfo);
|
||||
#ifdef DUSK_TPHD
|
||||
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
|
||||
#else
|
||||
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
|
||||
#endif
|
||||
if (mtl_init_data->mNBTScaleIdx != 0xffff) {
|
||||
return J3DNBTScale(mpNBTScaleInfo[mtl_init_data->mNBTScaleIdx]);
|
||||
} else {
|
||||
|
||||
@@ -103,6 +103,9 @@ J3DModelData* J3DModelLoader::load(void const* i_data, u32 i_flags) {
|
||||
readJoint((J3DJointBlock*)block);
|
||||
break;
|
||||
case 'MAT3':
|
||||
#if DUSK_TPHD
|
||||
case 'MAT4':
|
||||
#endif
|
||||
readMaterial((J3DMaterialBlock*)block, (s32)i_flags);
|
||||
break;
|
||||
case 'MAT2':
|
||||
@@ -147,6 +150,9 @@ J3DMaterialTable* J3DModelLoader::loadMaterialTable(void const* i_data) {
|
||||
for (u32 block_no = 0; block_no < data->mBlockNum; block_no++) {
|
||||
switch (block->mBlockType) {
|
||||
case 'MAT3':
|
||||
#if DUSK_TPHD
|
||||
case 'MAT4':
|
||||
#endif
|
||||
readMaterialTable((J3DMaterialBlock*)block, flags);
|
||||
break;
|
||||
case 'MAT2':
|
||||
@@ -212,6 +218,9 @@ J3DModelData* J3DModelLoader::loadBinaryDisplayList(void const* i_data, u32 i_fl
|
||||
modifyMaterial(i_flags);
|
||||
break;
|
||||
case 'MAT3':
|
||||
#if DUSK_TPHD
|
||||
case 'MAT4':
|
||||
#endif
|
||||
flags = 0x50100000;
|
||||
flags |= (i_flags & 0x3000000);
|
||||
mpMaterialBlock = (J3DMaterialBlock*)block;
|
||||
@@ -308,8 +317,22 @@ static GXVtxAttrFmtList getFmt(GXVtxAttrFmtList* i_fmtList, GXAttr i_attr) {
|
||||
return *i_fmtList;
|
||||
}
|
||||
}
|
||||
|
||||
#if DUSK_TPHD
|
||||
// HD BMDs occasionally have vertex arrays without a format entry. Mirror
|
||||
// the GC runtime: fall back to J3DSys::initGX defaults.
|
||||
GXVtxAttrFmtList def{};
|
||||
def.attr = i_attr;
|
||||
def.frac = 0;
|
||||
if (i_attr == GX_VA_POS) { def.cnt = GX_POS_XYZ; def.type = GX_F32; }
|
||||
else if (i_attr == GX_VA_NRM) { def.cnt = GX_NRM_XYZ; def.type = GX_F32; }
|
||||
else if (i_attr == GX_VA_NBT) { def.cnt = GX_NRM_NBT; def.type = GX_F32; }
|
||||
else if (i_attr >= GX_VA_CLR0 &&
|
||||
i_attr <= GX_VA_CLR1) { def.cnt = GX_CLR_RGBA; def.type = GX_RGBA8; }
|
||||
else { def.cnt = GX_TEX_ST; def.type = GX_F32; }
|
||||
return def;
|
||||
#else
|
||||
OSPanic(__FILE__, __LINE__, "Unable to find vertex attribute format!");
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ u16 J3DModelLoader::countMaterialNum(const void* stream) {
|
||||
const J3DModelBlock* block = header->mBlocks;
|
||||
for (int i = 0; i < header->mBlockNum; i++)
|
||||
{
|
||||
if (block->mBlockType == 'MAT3') {
|
||||
if (block->mBlockType == 'MAT3' || block->mBlockType == 'MAT4') {
|
||||
const J3DMaterialBlock* materialBlock = (const J3DMaterialBlock*)block;
|
||||
return materialBlock->mMaterialNum;
|
||||
}
|
||||
@@ -45,6 +45,7 @@ u32 J3DModelLoader::calcLoadSize(void const* stream, u32 flags_) {
|
||||
size += calcSizeJoint((const J3DJointBlock*)nextBlock);
|
||||
break;
|
||||
case 'MAT3':
|
||||
case 'MAT4':
|
||||
size += calcSizeMaterial((const J3DMaterialBlock*)nextBlock, flags);
|
||||
break;
|
||||
case 'SHP1':
|
||||
@@ -86,6 +87,7 @@ u32 J3DModelLoader::calcLoadMaterialTableSize(const void* stream) {
|
||||
for (u32 i = 0; i < header->mBlockNum; i++) {
|
||||
switch (nextBlock->mBlockType) {
|
||||
case 'MAT3':
|
||||
case 'MAT4':
|
||||
size += calcSizeMaterialTable((const J3DMaterialBlock*)nextBlock, flags);
|
||||
break;
|
||||
case 'TEX1':
|
||||
@@ -135,7 +137,8 @@ u32 J3DModelLoader::calcLoadBinaryDisplayListSize(const void* stream, u32 flags)
|
||||
case 'MDL3':
|
||||
size += calcSizeMaterialDL((const J3DMaterialDLBlock*)nextBlock, flags);
|
||||
break;
|
||||
case 'MAT3': {
|
||||
case 'MAT3':
|
||||
case 'MAT4': {
|
||||
u32 flags2 = (J3DMLF_21 | J3DMLF_Material_PE_Full | J3DMLF_Material_Color_LightOn);
|
||||
flags2 |= (u32)flags & (J3DMLF_Material_UseIndirect | J3DMLF_26);
|
||||
mpMaterialBlock = (const J3DMaterialBlock*)nextBlock;
|
||||
|
||||
@@ -9,6 +9,24 @@
|
||||
#include "JSystem/JKernel/JKRMemArchive.h"
|
||||
#include "JSystem/JUtility/JUTAssert.h"
|
||||
|
||||
#if DUSK_TPHD
|
||||
#include "dusk/tphd/HdAssetLayer.hpp"
|
||||
|
||||
namespace {
|
||||
void register_copied_hd_resource(
|
||||
JKRArchive* archive, JKRArchive::SDIFileEntry* fileEntry, void* buffer, u32 resourceSize) {
|
||||
if (archive == NULL || fileEntry == NULL || buffer == NULL || resourceSize == 0 ||
|
||||
archive->mStringTable == NULL)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
dusk::tphd::register_copied_hd_resource(archive->mEntryNum,
|
||||
archive->mStringTable + fileEntry->getNameOffset(), buffer, resourceSize);
|
||||
}
|
||||
} // namespace
|
||||
#endif
|
||||
|
||||
JKRArchive* JKRArchive::check_mount_already(s32 entryNum, JKRHeap* heap) {
|
||||
if (heap == NULL) {
|
||||
heap = JKRGetCurrentHeap();
|
||||
@@ -196,6 +214,9 @@ u32 JKRArchive::readResource(void* buffer, u32 bufferSize, u32 type, const char*
|
||||
if (fileEntry) {
|
||||
u32 resourceSize;
|
||||
fetchResource(buffer, bufferSize, fileEntry, &resourceSize);
|
||||
#if DUSK_TPHD
|
||||
register_copied_hd_resource(this, fileEntry, buffer, resourceSize);
|
||||
#endif
|
||||
return resourceSize;
|
||||
}
|
||||
|
||||
@@ -214,6 +235,9 @@ u32 JKRArchive::readResource(void* buffer, u32 bufferSize, const char* path) {
|
||||
if (fileEntry) {
|
||||
u32 resourceSize;
|
||||
fetchResource(buffer, bufferSize, fileEntry, &resourceSize);
|
||||
#if DUSK_TPHD
|
||||
register_copied_hd_resource(this, fileEntry, buffer, resourceSize);
|
||||
#endif
|
||||
return resourceSize;
|
||||
}
|
||||
|
||||
@@ -226,6 +250,9 @@ u32 JKRArchive::readIdxResource(void* buffer, u32 bufferSize, u32 index) {
|
||||
if (fileEntry) {
|
||||
u32 resourceSize;
|
||||
fetchResource(buffer, bufferSize, fileEntry, &resourceSize);
|
||||
#if DUSK_TPHD
|
||||
register_copied_hd_resource(this, fileEntry, buffer, resourceSize);
|
||||
#endif
|
||||
return resourceSize;
|
||||
}
|
||||
|
||||
@@ -238,6 +265,9 @@ u32 JKRArchive::readResource(void* buffer, u32 bufferSize, u16 id) {
|
||||
if (fileEntry) {
|
||||
u32 resourceSize;
|
||||
fetchResource(buffer, bufferSize, fileEntry, &resourceSize);
|
||||
#if DUSK_TPHD
|
||||
register_copied_hd_resource(this, fileEntry, buffer, resourceSize);
|
||||
#endif
|
||||
return resourceSize;
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,10 @@
|
||||
#include <stdint.h>
|
||||
#include "os_report.h"
|
||||
|
||||
#if DUSK_TPHD
|
||||
#include "dusk/tphd/HdAssetLayer.hpp"
|
||||
#endif
|
||||
|
||||
JKRMemArchive::JKRMemArchive(s32 entryNum, JKRArchive::EMountDirection mountDirection)
|
||||
: JKRArchive(entryNum, MOUNT_MEM) {
|
||||
mIsMounted = false;
|
||||
@@ -67,8 +71,13 @@ bool JKRMemArchive::open(s32 entryNum, JKRArchive::EMountDirection mountDirectio
|
||||
mIsOpen = false;
|
||||
mMountDirection = mountDirection;
|
||||
|
||||
#ifdef TARGET_PC
|
||||
u32 loadedSize = 0;
|
||||
#endif
|
||||
if (mMountDirection == JKRArchive::MOUNT_DIRECTION_HEAD) {
|
||||
#ifndef TARGET_PC
|
||||
u32 loadedSize;
|
||||
#endif
|
||||
mArcHeader = (SArcHeader *)JKRDvdToMainRam(
|
||||
entryNum, NULL, EXPAND_SWITCH_UNKNOWN1, 0, mHeap, JKRDvdRipper::ALLOC_DIRECTION_FORWARD,
|
||||
0, (int *)&mCompression, &loadedSize);
|
||||
@@ -77,7 +86,9 @@ bool JKRMemArchive::open(s32 entryNum, JKRArchive::EMountDirection mountDirectio
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifndef TARGET_PC
|
||||
u32 loadedSize;
|
||||
#endif
|
||||
mArcHeader = (SArcHeader *)JKRDvdToMainRam(
|
||||
entryNum, NULL, EXPAND_SWITCH_UNKNOWN1, 0, mHeap,
|
||||
JKRDvdRipper::ALLOC_DIRECTION_BACKWARD, 0, (int *)&mCompression, &loadedSize);
|
||||
@@ -90,6 +101,9 @@ bool JKRMemArchive::open(s32 entryNum, JKRArchive::EMountDirection mountDirectio
|
||||
mMountMode = UNKNOWN_MOUNT_MODE;
|
||||
}
|
||||
else {
|
||||
#if DUSK_TPHD
|
||||
dusk::tphd::register_mounted_hd_archive(entryNum, mArcHeader, loadedSize);
|
||||
#endif
|
||||
JUT_ASSERT(438, mArcHeader->signature == 'RARC');
|
||||
mArcInfoBlock = (SArcDataInfo *)((u8 *)mArcHeader + mArcHeader->header_length);
|
||||
mNodes = (SDIDirEntry *)((u8 *)&mArcInfoBlock->num_nodes + mArcInfoBlock->node_offset);
|
||||
|
||||
@@ -15,6 +15,9 @@ static const char* sSpotName[] = {
|
||||
"D_MN08A", "D_MN08D", "D_MN09", "D_MN09A", "D_MN09B", "D_MN09C", "D_SB00", "D_SB01",
|
||||
"D_SB02", "D_SB03", "D_SB04", "D_SB05", "D_SB06", "D_SB07", "D_SB08", "D_SB09",
|
||||
"D_SB10",
|
||||
#if TARGET_PC
|
||||
"D_SB11",
|
||||
#endif
|
||||
};
|
||||
|
||||
#endif /* SPOTNAME_H */
|
||||
|
||||
@@ -1603,13 +1603,35 @@ void Z2SceneMgr::setSceneName(char* spot, s32 room, s32 layer) {
|
||||
bgm_wave1 = 0x45;
|
||||
}
|
||||
break;
|
||||
#if TARGET_PC
|
||||
case Z2SCENE_CAVE_OF_SHADOWS:
|
||||
if (room == 29) {
|
||||
se_wave2 = 0x16;
|
||||
} else if (room == 40) {
|
||||
se_wave2 = 0x12;
|
||||
} else {
|
||||
se_wave2 = 0x36;
|
||||
}
|
||||
|
||||
bgm_wave1 = 0x45;
|
||||
se_wave1 = 0x51;
|
||||
mDoAud_zelAudio_c::onBgmSet();
|
||||
bgm_id = Z2BGM_SUB_DUNGEON;
|
||||
|
||||
if (BGM_ID == Z2BGM_SUB_DUNGEON) {
|
||||
if (sceneNum == Z2SCENE_CAVE_OF_ORDEALS) {
|
||||
BGM_ID = -1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
/*dSv_event_flag_c::M_071 - Cutscene - [cutscene: 20] Zant appears (during Midna's desperate hour) */
|
||||
if (dComIfGs_isEventBit(dSv_event_flag_c::saveBitLabels[104])
|
||||
/* dSv_event_flag_c::F_0250 - Cutscene - [cutscene: 21] reunion with Zelda / Midna revived (Hyrule Castle barrier appears) */
|
||||
&& !dComIfGs_isEventBit(dSv_event_flag_c::saveBitLabels[250])
|
||||
&& demo_wave == 0 && spotNo != Z2SCENE_ELDIN_BRIDGE_BATTLE)
|
||||
&& demo_wave == 0 && spotNo != Z2SCENE_ELDIN_BRIDGE_BATTLE IF_DUSK(&& spotNo != Z2SCENE_CAVE_OF_SHADOWS))
|
||||
{
|
||||
bgm_wave1 = 0x36;
|
||||
if (spotNo == Z2SCENE_CASTLE_TOWN_SHOPS && room == 5) {
|
||||
|
||||
@@ -583,6 +583,12 @@ void Z2SeqMgr::bgmStreamPlay() {
|
||||
}
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::tphd_active()) {
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !PLATFORM_SHIELD
|
||||
else if (getStreamBgmID() == 0x2000000) {
|
||||
if (mStreamBgmHandle) {
|
||||
|
||||
+33
-31
@@ -5,51 +5,53 @@
|
||||
|
||||
#include "d/dolzel.h" // IWYU pragma: keep
|
||||
|
||||
#include "d/actor/d_a_alink.h"
|
||||
#include "JSystem/J2DGraph/J2DAnmLoader.h"
|
||||
#include "JSystem/J3DGraphBase/J3DDrawBuffer.h"
|
||||
#include "JSystem/J3DGraphBase/J3DMaterial.h"
|
||||
#include "JSystem/J3DGraphLoader/J3DAnmLoader.h"
|
||||
#include "JSystem/J3DGraphBase/J3DDrawBuffer.h"
|
||||
#include "JSystem/JHostIO/JORServer.h"
|
||||
#include "JSystem/JKernel/JKRExpHeap.h"
|
||||
#include "SSystem/SComponent/c_math.h"
|
||||
#include "d/d_item.h"
|
||||
#include "d/d_meter2_draw.h"
|
||||
#include "d/d_pane_class.h"
|
||||
#include "d/d_demo.h"
|
||||
#include "d/actor/d_a_alink.h"
|
||||
#include "d/actor/d_a_b_mgn.h"
|
||||
#include "d/actor/d_a_canoe.h"
|
||||
#include "d/actor/d_a_cow.h"
|
||||
#include "d/actor/d_a_crod.h"
|
||||
#include "d/actor/d_a_horse.h"
|
||||
#include "d/actor/d_a_kytag05.h"
|
||||
#include "d/actor/d_a_mg_rod.h"
|
||||
#include "d/actor/d_a_midna.h"
|
||||
#include "d/actor/d_a_mirror.h"
|
||||
#include "d/actor/d_a_spinner.h"
|
||||
#include "d/actor/d_a_tbox.h"
|
||||
#include "d/actor/d_a_tag_Lv6Gate.h"
|
||||
#include "d/actor/d_a_tag_kmsg.h"
|
||||
#include "d/actor/d_a_tag_magne.h"
|
||||
#include "d/actor/d_a_tag_wljump.h"
|
||||
#include "d/actor/d_a_npc_tk.h"
|
||||
#include "d/actor/d_a_cow.h"
|
||||
#include "d/actor/d_a_obj_crope.h"
|
||||
#include "d/actor/d_a_obj_wchain.h"
|
||||
#include "d/actor/d_a_tag_hstop.h"
|
||||
#include "d/actor/d_a_scene_exit.h"
|
||||
#include "d/actor/d_a_tag_mhint.h"
|
||||
#include "d/actor/d_a_tag_mmsg.h"
|
||||
#include "d/actor/d_a_tag_lantern.h"
|
||||
#include "d/actor/d_a_horse.h"
|
||||
#include "m_Do/m_Do_controller_pad.h"
|
||||
#include "d/d_bomb.h"
|
||||
#include "d/d_meter2_info.h"
|
||||
#include "d/actor/d_a_kytag05.h"
|
||||
#include "d/actor/d_a_b_mgn.h"
|
||||
#include "d/actor/d_a_ni.h"
|
||||
#include "d/actor/d_a_npc_bou.h"
|
||||
#include "d/actor/d_a_npc_kolin.h"
|
||||
#include "f_op/f_op_kankyo_mng.h"
|
||||
#include "d/actor/d_a_npc_tk.h"
|
||||
#include "d/actor/d_a_obj_crope.h"
|
||||
#include "d/actor/d_a_obj_wchain.h"
|
||||
#include "d/actor/d_a_scene_exit.h"
|
||||
#include "d/actor/d_a_spinner.h"
|
||||
#include "d/actor/d_a_tag_Lv6Gate.h"
|
||||
#include "d/actor/d_a_tag_hstop.h"
|
||||
#include "d/actor/d_a_tag_kmsg.h"
|
||||
#include "d/actor/d_a_tag_lantern.h"
|
||||
#include "d/actor/d_a_tag_magne.h"
|
||||
#include "d/actor/d_a_tag_mhint.h"
|
||||
#include "d/actor/d_a_tag_mmsg.h"
|
||||
#include "d/actor/d_a_tag_mstop.h"
|
||||
#include "d/actor/d_a_tag_mwait.h"
|
||||
#include "d/actor/d_a_canoe.h"
|
||||
#include "d/actor/d_a_ni.h"
|
||||
#include "d/actor/d_a_tag_wljump.h"
|
||||
#include "d/actor/d_a_tbox.h"
|
||||
#include "d/d_bomb.h"
|
||||
#include "d/d_demo.h"
|
||||
#include "d/d_item.h"
|
||||
#include "d/d_meter2_draw.h"
|
||||
#include "d/d_meter2_info.h"
|
||||
#include "d/d_pane_class.h"
|
||||
#include "d/d_s_play.h"
|
||||
#include "dusk/tphd/LosTable.hpp"
|
||||
#include "dusk/tphd/TphdPack.hpp"
|
||||
#include "f_op/f_op_kankyo_mng.h"
|
||||
#include "m_Do/m_Do_controller_pad.h"
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/action_bindings.h"
|
||||
@@ -17452,7 +17454,7 @@ int daAlink_c::procCoMetamorphoseInit() {
|
||||
mProcVar2.field_0x300c = shape_angle.x;
|
||||
|
||||
daMidna_c* midna = (daMidna_c*)getMidnaActor();
|
||||
if (checkMidnaRide() && daMidna_c::checkMidnaRealBody() && midna->checkDemoTypeNone())
|
||||
if (checkMidnaRide() && (daMidna_c::checkMidnaRealBody() IF_DUSK(|| dusk::tphd::is_los_active())) && midna->checkDemoTypeNone())
|
||||
{
|
||||
midna->changeOriginalDemo();
|
||||
midna->changeDemoMode(daPy_demo_c::DEMO_UNK_15_e);
|
||||
|
||||
@@ -737,6 +737,12 @@ void daAlink_c::setDemoData() {
|
||||
} else {
|
||||
mDemo.setStick(1.0f);
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::tphd::is_los_active() && mLosStickValue > 0.0f) {
|
||||
mDemo.setStick(mLosStickValue);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if ((demo_mode == daPy_demo_c::DEMO_UNK_2_e || demo_mode == daPy_demo_c::DEMO_UNK_3_e) && prm1_p != NULL && *prm1_p == 1) {
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include "d/d_meter2.h"
|
||||
#include "d/d_meter2_draw.h"
|
||||
#include "d/d_meter2_info.h"
|
||||
#include "dusk/tphd/LosTable.hpp"
|
||||
|
||||
void daAlink_c::handleWolfHowl() {
|
||||
if (checkWolf()) {
|
||||
@@ -71,6 +72,11 @@ void daAlink_c::handleQuickTransform() {
|
||||
return;
|
||||
}
|
||||
|
||||
if (dusk::tphd::is_los_active() && !dusk::getSettings().game.canTransformAnywhere) {
|
||||
Z2GetAudioMgr()->seStart(Z2SE_SYS_ERROR, NULL, 0, 0, 1.0f, 1.0f, -1.0f, -1.0f, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Check to see if Link has the ability to transform.
|
||||
if (!dComIfGs_isEventBit(dSv_event_flag_c::M_077)) {
|
||||
return;
|
||||
@@ -176,7 +182,7 @@ bool daAlink_c::checkAimContext() {
|
||||
}
|
||||
}
|
||||
|
||||
bool daAlink_c::checkTouchAimCaptureContext() {
|
||||
bool daAlink_c::checkAimInputContext() {
|
||||
switch (mProcID) {
|
||||
case PROC_HOOKSHOT_ROOF_WAIT:
|
||||
case PROC_HOOKSHOT_WALL_WAIT:
|
||||
|
||||
@@ -123,7 +123,7 @@ BOOL daAlink_c::setBodyAngleToCamera() {
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::getSettings().game.enableMouseAim && checkAimContext()) {
|
||||
if (dusk::getSettings().game.enableMouseAim && checkAimInputContext()) {
|
||||
sp8 = mBodyAngle.x;
|
||||
} else
|
||||
#endif
|
||||
@@ -142,7 +142,7 @@ BOOL daAlink_c::setBodyAngleToCamera() {
|
||||
#if TARGET_PC
|
||||
if ((dusk::getSettings().game.enableGyroAim ||
|
||||
dusk::getSettings().game.enableMouseAim) &&
|
||||
checkAimContext())
|
||||
checkAimInputContext())
|
||||
{
|
||||
f32 gyro_scale = 1.0f;
|
||||
if (checkWolfEyeUp()) {
|
||||
@@ -174,7 +174,7 @@ BOOL daAlink_c::setBodyAngleToCamera() {
|
||||
}
|
||||
}
|
||||
|
||||
if (dusk::getSettings().game.enableTouchControls && checkAimContext()) {
|
||||
if (dusk::getSettings().game.enableTouchControls && checkAimInputContext()) {
|
||||
f32 touchYawDp = 0.0f;
|
||||
f32 touchPitchDp = 0.0f;
|
||||
if (dusk::touch_camera::consume_delta(touchYawDp, touchPitchDp)) {
|
||||
@@ -452,4 +452,8 @@ daAlink_c::daAlink_c()
|
||||
mFaceBtkHeap(0x400),
|
||||
mFaceBckHeap(0xC00),
|
||||
mAnmHeap9(0x800)
|
||||
{}
|
||||
{
|
||||
#if TARGET_PC
|
||||
mLosStickValue = -1.0f;
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -85,6 +85,17 @@ int daAlink_c::loadModelDVD() {
|
||||
}
|
||||
cPhs_Reset(&mPhaseReq);
|
||||
mpArcHeap->freeAll();
|
||||
#if TARGET_PC
|
||||
field_0x06d0 = NULL;
|
||||
field_0x06d4 = NULL;
|
||||
field_0x06d8 = NULL;
|
||||
field_0x06dc = NULL;
|
||||
field_0x06e0 = NULL;
|
||||
field_0x06e4 = NULL;
|
||||
field_0x06e8 = NULL;
|
||||
field_0x06ec = NULL;
|
||||
field_0x06f0 = NULL;
|
||||
#endif
|
||||
|
||||
if (mProcID == PROC_METAMORPHOSE || mProcID == PROC_METAMORPHOSE_ONLY) {
|
||||
setArcName(!checkWolf());
|
||||
|
||||
+62
-2
@@ -13,6 +13,7 @@
|
||||
#include "d/d_bg_parts.h"
|
||||
#include "m_Do/m_Do_lib.h"
|
||||
#include "d/d_demo.h"
|
||||
#include "dusk/tphd/LosTable.hpp"
|
||||
#include "JSystem/JKernel/JKRExpHeap.h"
|
||||
#include "JSystem/JKernel/JKRSolidHeap.h"
|
||||
#include "JSystem/J3DGraphAnimator/J3DMaterialAnm.h"
|
||||
@@ -297,6 +298,25 @@ int daBg_c::draw() {
|
||||
dComIfGd_setListBG();
|
||||
mDoLib_clipper::changeFar(1000000.0f);
|
||||
|
||||
#if TARGET_PC
|
||||
bool losClip = false;
|
||||
Mtx losBgMtx;
|
||||
if (dusk::tphd_active()) {
|
||||
// TPHD Cave of Shadows rooms have a base matrix far from identity; it gets the room translation from 'los.bin'
|
||||
// HD daBg::draw clips the shape bbox in world space, so recompute the room base matrix to transform it.
|
||||
if (strcmp(dComIfGp_getStartStageName(), "D_SB11") == 0) {
|
||||
f32 hx, hy, hz;
|
||||
s16 ha;
|
||||
if (dusk::tphd::los_get_room_trans(roomNo, &hx, &hy, &hz, &ha)) {
|
||||
mDoMtx_stack_c::transS(hx, hy, hz);
|
||||
mDoMtx_stack_c::YrotM(ha);
|
||||
mDoMtx_copy(mDoMtx_stack_c::get(), losBgMtx);
|
||||
losClip = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
J3DModelData* modelData;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
sp8 = 0;
|
||||
@@ -325,8 +345,22 @@ int daBg_c::draw() {
|
||||
for (u16 j = 0; j < modelData->getShapeNum(); j++) {
|
||||
J3DShape* shape = modelData->getShapeNodePointer(j);
|
||||
|
||||
if (mDoLib_clipper::clip(j3dSys.getViewMtx(), (Vec*)shape->getMin(),
|
||||
(Vec*)shape->getMax())) {
|
||||
Vec* clipMin = (Vec*)shape->getMin();
|
||||
Vec* clipMax = (Vec*)shape->getMax();
|
||||
#if TARGET_PC
|
||||
if (dusk::tphd_active()) {
|
||||
Vec losClipMin, losClipMax;
|
||||
if (losClip) {
|
||||
// HD transforms the bbox min/max by the room base matrix; clip rebuilds
|
||||
// the 8 corners (exact for the room angles, which are multiples of 90).
|
||||
mDoMtx_multVec(losBgMtx, clipMin, &losClipMin);
|
||||
mDoMtx_multVec(losBgMtx, clipMax, &losClipMax);
|
||||
clipMin = &losClipMin;
|
||||
clipMax = &losClipMax;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
if (mDoLib_clipper::clip(j3dSys.getViewMtx(), clipMin, clipMax)) {
|
||||
shape->hide();
|
||||
} else {
|
||||
shape->show();
|
||||
@@ -565,17 +599,43 @@ int daBg_c::create() {
|
||||
}
|
||||
|
||||
J3DModelData* modelData;
|
||||
#if TARGET_PC
|
||||
f32 transX = 0.0f;
|
||||
f32 transY = 0.0f;
|
||||
f32 transVert = 0.0f;
|
||||
s16 angle = 0;
|
||||
bool foundMapTrans = false;
|
||||
|
||||
if (dusk::tphd_active()) {
|
||||
// TPHD positions Cave of Shadows rooms via los.bin (per-room world X/Y/Z +
|
||||
// Y-rotation, incl. the vertical Y that GC's MULT lacks). Retail gates
|
||||
// this on g_dComIfG_gameInfo.field_0x1e448; los.bin only carries
|
||||
// D_SB11's room data, so restrict it to that stage and fall back to MULT.
|
||||
if (strcmp(dComIfGp_getStartStageName(), "D_SB11") == 0) {
|
||||
foundMapTrans = dusk::tphd::los_get_room_trans(roomNo, &transX, &transVert, &transY, &angle);
|
||||
}
|
||||
}
|
||||
|
||||
if (!foundMapTrans)
|
||||
foundMapTrans = dComIfGp_getMapTrans(roomNo, &transX, &transY, &angle);
|
||||
if (foundMapTrans) {
|
||||
#else
|
||||
f32 transX;
|
||||
f32 transY;
|
||||
s16 angle;
|
||||
if (dComIfGp_getMapTrans(roomNo, &transX, &transY, &angle)) {
|
||||
#endif
|
||||
daBg_Part* bgPart = mBgParts;
|
||||
J3DModel* model;
|
||||
for (int i = 0; i < 6; i++) {
|
||||
model = bgPart->model;
|
||||
|
||||
if (model != NULL) {
|
||||
#if TARGET_PC
|
||||
mDoMtx_stack_c::transS(transX, transVert, transY);
|
||||
#else
|
||||
mDoMtx_stack_c::transS(transX, 0.0f, transY);
|
||||
#endif
|
||||
mDoMtx_stack_c::YrotM(angle);
|
||||
model->setBaseTRMtx(mDoMtx_stack_c::get());
|
||||
|
||||
|
||||
@@ -144,7 +144,11 @@ bool daBgObj_c::spec_data_c::Set(void* i_ptr) {
|
||||
default:
|
||||
// Invalid data block type
|
||||
OS_REPORT_ERROR("データブロックタイプが不正です<%d>\n", block_type);
|
||||
#if DUSK_TPHD
|
||||
return 0; // HD-port: skip actor instead of asserting.
|
||||
#else
|
||||
JUT_ASSERT(527, FALSE);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (block_type == 0) {
|
||||
@@ -185,7 +189,11 @@ bool daBgObj_c::spec_data_c::Set(void* i_ptr) {
|
||||
default:
|
||||
// Invalid data block type
|
||||
OS_REPORT_ERROR("データブロックタイプが不正です<%d>\n", block_type);
|
||||
#if DUSK_TPHD
|
||||
return 0;
|
||||
#else
|
||||
JUT_ASSERT(570, FALSE);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (block_type == 0) {
|
||||
@@ -226,8 +234,12 @@ bool daBgObj_c::spec_data_c::Set(void* i_ptr) {
|
||||
default:
|
||||
// "Data Block type invalid<%d>\n"
|
||||
OSReport_Error("データブロックタイプが不正です<%d>\n", block_type);
|
||||
#if DUSK_TPHD
|
||||
return 0;
|
||||
#else
|
||||
JUT_ASSERT(619, FALSE);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (block_type == 0) {
|
||||
|
||||
@@ -403,7 +403,10 @@ void e_ai_class::e_ai_damage() {
|
||||
if (m_timers[1] == 0) {
|
||||
m_sound.startCreatureSound(Z2SE_EN_AI_FLASH, 0, -1);
|
||||
mpEmitter = dComIfGp_particle_set(0x81ED, ¤t.pos, &tevStr, &shape_angle, NULL);
|
||||
mpEmitter->becomeImmortalEmitter();
|
||||
if (mpEmitter != NULL) {
|
||||
mpEmitter->becomeImmortalEmitter();
|
||||
}
|
||||
|
||||
m_timers[1] = 1000;
|
||||
m_timers[2] = 56;
|
||||
}
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
#include "Z2AudioLib/Z2Instances.h"
|
||||
#include <cstring>
|
||||
|
||||
#include "dusk/tphd/LosTable.hpp"
|
||||
#include "dusk/tphd/TphdPack.hpp"
|
||||
|
||||
enum E_ww_RES_File_ID {
|
||||
/* BCK */
|
||||
/* 0x04 */ BCK_WW_APPEAR = 0x4,
|
||||
@@ -466,7 +469,7 @@ f32 daE_WW_c::checkCreateBg(cXyz i_vector) {
|
||||
return -G_CM3D_F_INF;
|
||||
}
|
||||
|
||||
if (dComIfG_Bgsp().GetSpecialCode(gnd_chk) == 5 || dComIfG_Bgsp().GetPolyAtt0(gnd_chk) == 0xD) {
|
||||
if (dComIfG_Bgsp().GetSpecialCode(gnd_chk) == 5 || dComIfG_Bgsp().GetPolyAtt0(gnd_chk) == 0xD IF_DUSK(|| dusk::tphd::is_los_active())) {
|
||||
cXyz temp_r1 = daPy_getPlayerActorClass()->current.pos;
|
||||
temp_r1.y += 100.0f;
|
||||
sp14 = i_vector;
|
||||
@@ -666,8 +669,14 @@ void daE_WW_c::executeMaster() {
|
||||
sp30.set(0.0f, 0.0f, 3000.0f);
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::tphd::is_los_active()) {
|
||||
sp30.z = 600.0f;
|
||||
}
|
||||
#endif
|
||||
|
||||
cLib_offsetPos(&sp3C, &sp48, fopCamM_GetAngleY(camera), &sp30);
|
||||
if (current.pos.abs(sp3C) < field_0x6a8) {
|
||||
if ((current.pos.abs(sp3C) < field_0x6a8) IF_DUSK(|| (dusk::tphd::is_los_active() && current.pos.y - sp48.y < field_0x6a8))) {
|
||||
f32 temp_f31 = checkCreateBg(sp3C);
|
||||
if (-G_CM3D_F_INF != temp_f31) {
|
||||
sp3C.y = temp_f31;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "d/actor/d_a_player.h"
|
||||
#include "d/d_com_inf_game.h"
|
||||
#include <cstring>
|
||||
#include <dusk/ui/settings.hpp>
|
||||
|
||||
static int daKytag04_Draw(kytag04_class* i_this) {
|
||||
dScnKy_env_light_c* kankyo = dKy_getEnvlight();
|
||||
@@ -260,12 +261,25 @@ static int daKytag04_Create(fopAc_ac_c* i_this) {
|
||||
|
||||
a_this->mNeedDropNum = i_this->current.angle.z & 0xFF;
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::tphd_active()) {
|
||||
a_this->mNeedDropNum = 12;
|
||||
}
|
||||
#endif
|
||||
|
||||
int phase_state = dComIfG_resLoad(&a_this->mPhase, "Kytag04");
|
||||
if (phase_state == cPhs_COMPLEATE_e) {
|
||||
a_this->field_0x5b4 = (fopAcM_GetParam(i_this) >> 8) & 7;
|
||||
a_this->mStageNo = (i_this->current.angle.z >> 8) & 0xFF;
|
||||
a_this->mExitID = fopAcM_GetParam(i_this) & 0xFF;
|
||||
a_this->mNeedDropNum = i_this->current.angle.z & 0xFF;
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::tphd_active()) {
|
||||
a_this->mNeedDropNum = 12;
|
||||
}
|
||||
#endif
|
||||
|
||||
a_this->field_0x5b5 = fopAcM_GetParam(i_this) >> 0x10;
|
||||
a_this->field_0x5b6 = fopAcM_GetParam(i_this) >> 0x18;
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@ static dPath* get_Extent_pos_end_get(kytag10_class* i_this, dPath* i_path, cXyz*
|
||||
}
|
||||
|
||||
static void sparks_move(kytag10_class* i_this) {
|
||||
|
||||
camera_process_class* camera_p = dComIfGp_getCamera(0);
|
||||
|
||||
cXyz ratio_pos_1;
|
||||
|
||||
@@ -5,16 +5,17 @@
|
||||
|
||||
#include "d/dolzel_rel.h" // IWYU pragma: keep
|
||||
|
||||
#include "d/actor/d_a_midna.h"
|
||||
#include "JSystem/J3DGraphLoader/J3DAnmLoader.h"
|
||||
#include "d/d_meter2_info.h"
|
||||
#include "d/actor/d_a_alink.h"
|
||||
#include "d/actor/d_a_kago.h"
|
||||
#include "d/actor/d_a_midna.h"
|
||||
#include "d/d_debug_viewer.h"
|
||||
#include "d/d_demo.h"
|
||||
#include "d/d_meter2_info.h"
|
||||
#include "d/d_msg_object.h"
|
||||
#include "d/d_s_play.h"
|
||||
#include "d/d_debug_viewer.h"
|
||||
#include "dusk/frame_interpolation.h"
|
||||
#include "dusk/tphd/LosTable.hpp"
|
||||
|
||||
static f32 dummy_lit_3777(int idx, u8 foo) {
|
||||
Vec dummy_vec = {0.0f, 0.0f, 0.0f};
|
||||
@@ -3308,7 +3309,14 @@ int daMidna_c::execute() {
|
||||
}
|
||||
}
|
||||
onStateFlg0(FLG0_UNK_8000);
|
||||
mMsgFlow.init(this, 0xbb9, 0, NULL);
|
||||
#if TARGET_PC
|
||||
if (dusk::tphd::is_los_active() && !dusk::getSettings().game.canTransformAnywhere) {
|
||||
mMsgFlow.init(this, 0x457, 0, NULL);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
mMsgFlow.init(this, 0xbb9, 0, NULL);
|
||||
}
|
||||
} else if (mMsgFlow.doFlow(this, NULL, 0)) {
|
||||
int item_id;
|
||||
u16 event_id = mMsgFlow.getEventId(&item_id);
|
||||
|
||||
@@ -15,6 +15,8 @@
|
||||
#include "m_Do/m_Do_lib.h"
|
||||
#if TARGET_PC
|
||||
#include "dusk/frame_interpolation.h"
|
||||
#include "dusk/settings.h"
|
||||
#include <cstring>
|
||||
#endif
|
||||
|
||||
#ifndef __MWERKS__
|
||||
@@ -50,6 +52,32 @@ void dMirror_packet_c::calcMinMax() {
|
||||
mMinVal.set(FLT_MAX, FLT_MAX, FLT_MAX);
|
||||
mMaxVal.set(-FLT_MAX, -FLT_MAX, -FLT_MAX);
|
||||
|
||||
#if TARGET_PC
|
||||
// HD: per-quad cull box + global bbox over all mQuadCount quads.
|
||||
for (int q = 0; q < mQuadCount; q++) {
|
||||
cXyz& bmin = mQuadBoxMin[q];
|
||||
cXyz& bmax = mQuadBoxMax[q];
|
||||
bmin.set(FLT_MAX, FLT_MAX, FLT_MAX);
|
||||
bmax.set(-FLT_MAX, -FLT_MAX, -FLT_MAX);
|
||||
|
||||
cXyz* quad = &mQuad[q * 4];
|
||||
for (int i = 0; i < 4; i++, quad++) {
|
||||
if (quad->x < bmin.x) bmin.x = quad->x;
|
||||
if (quad->x > bmax.x) bmax.x = quad->x;
|
||||
if (quad->y < bmin.y) bmin.y = quad->y;
|
||||
if (quad->y > bmax.y) bmax.y = quad->y;
|
||||
if (quad->z < bmin.z) bmin.z = quad->z;
|
||||
if (quad->z > bmax.z) bmax.z = quad->z;
|
||||
}
|
||||
|
||||
if (bmin.x < mMinVal.x) mMinVal.x = bmin.x;
|
||||
if (bmax.x > mMaxVal.x) mMaxVal.x = bmax.x;
|
||||
if (bmin.y < mMinVal.y) mMinVal.y = bmin.y;
|
||||
if (bmax.y > mMaxVal.y) mMaxVal.y = bmax.y;
|
||||
if (bmin.z < mMinVal.z) mMinVal.z = bmin.z;
|
||||
if (bmax.z > mMaxVal.z) mMaxVal.z = bmax.z;
|
||||
}
|
||||
#else
|
||||
cXyz* quad = mQuad;
|
||||
for (int i = 0; i < 4; i++, quad++) {
|
||||
f32 val = quad->x;
|
||||
@@ -82,6 +110,7 @@ void dMirror_packet_c::calcMinMax() {
|
||||
mMaxVal.z = val;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
int dMirror_packet_c::entryModel(J3DModel* i_model) {
|
||||
@@ -103,6 +132,10 @@ int dMirror_packet_c::entryModel(J3DModel* i_model) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
static f32 dMirror_quadDist(const cXyz& p, const cXyz& bmin, const cXyz& bmax);
|
||||
#endif
|
||||
|
||||
void dMirror_packet_c::mirrorZdraw(f32* param_0, f32* param_1, f32 param_2, f32 param_3,
|
||||
f32 param_4, f32 param_5, f32 param_6, f32 param_7) {
|
||||
ZoneScoped;
|
||||
@@ -131,11 +164,82 @@ void dMirror_packet_c::mirrorZdraw(f32* param_0, f32* param_1, f32 param_2, f32
|
||||
GXLoadPosMtxImm(j3dSys.getViewMtx(), 0);
|
||||
GXSetCurrentMtx(0);
|
||||
|
||||
#if TARGET_PC
|
||||
// HD FUN_0247d9fc: with count>=2, tint only the same-height quad group nearest the camera
|
||||
u32 groupMask = 1;
|
||||
int groupCount = 1;
|
||||
if (mQuadCount >= 2) {
|
||||
const cXyz& eye = dComIfGd_getView()->lookat.eye;
|
||||
int nearest = 0;
|
||||
f32 best = FLT_MAX;
|
||||
for (int q = 0; q < mQuadCount; q++) {
|
||||
f32 dist = dMirror_quadDist(eye, mQuadBoxMin[q], mQuadBoxMax[q]);
|
||||
if (dist < best) {
|
||||
best = dist;
|
||||
nearest = q;
|
||||
}
|
||||
}
|
||||
groupMask = 0;
|
||||
groupCount = 0;
|
||||
for (int q = 0; q < mQuadCount; q++) {
|
||||
if (fabsf(mQuadBoxMin[q].y - mQuadBoxMin[nearest].y) < 0.0001f) {
|
||||
groupMask |= 1u << q;
|
||||
groupCount++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GXBegin(GX_QUADS, GX_VTXFMT0, groupCount * 4);
|
||||
for (int q = 0; q < mQuadCount; q++) {
|
||||
if (groupMask & (1u << q)) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
GXPosition3f32(mQuad[q * 4 + i].x, mQuad[q * 4 + i].y, mQuad[q * 4 + i].z);
|
||||
}
|
||||
}
|
||||
}
|
||||
GXEnd();
|
||||
|
||||
if (mQuadCount >= 2 && GX2SupportsStencil()) {
|
||||
GXSetColorUpdate(GX_DISABLE);
|
||||
GXSetAlphaUpdate(GX_DISABLE);
|
||||
GXSetBlendMode(GX_BM_NONE, GX_BL_SRCALPHA, GX_BL_INVSRCALPHA, GX_LO_CLEAR);
|
||||
GXSetAlphaCompare(GX_ALWAYS, 0, GX_AOP_OR, GX_ALWAYS, 0);
|
||||
GX2SetStencilMask(0xff, 0xff, 0, 0xff, 0xff, 0);
|
||||
GX2SetDepthStencilControl(0, 0, 7, 1, 0, 7, 3, 3, 0, 0, 0, 0, 0);
|
||||
GXBegin(GX_QUADS, GX_VTXFMT0, groupCount * 4);
|
||||
for (int q = 0; q < mQuadCount; q++) {
|
||||
if (groupMask & (1u << q)) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
GXPosition3f32(mQuad[q * 4 + i].x, mQuad[q * 4 + i].y, mQuad[q * 4 + i].z);
|
||||
}
|
||||
}
|
||||
}
|
||||
GXEnd();
|
||||
|
||||
GX2SetDepthStencilControl(1, 1, 7, 1, 0, 2, 1, 1, 1, 0, 0, 0, 0);
|
||||
Mtx44 proj;
|
||||
C_MTXOrtho(proj, param_1[1], param_1[1] + param_1[3], param_1[0],
|
||||
param_1[0] + param_1[2], 0, 100.0f);
|
||||
GXSetProjection(proj, GX_ORTHOGRAPHIC);
|
||||
GXLoadPosMtxImm(mDoMtx_getIdentity(), 0);
|
||||
GXBegin(GX_QUADS, GX_VTXFMT0, 4);
|
||||
GXPosition3f32(param_1[0], param_1[1], -100.0f);
|
||||
GXPosition3f32(param_1[0] + param_1[2], param_1[1], -100.0f);
|
||||
GXPosition3f32(param_1[0] + param_1[2], param_1[1] + param_1[3], -100.0f);
|
||||
GXPosition3f32(param_1[0], param_1[1] + param_1[3], -100.0f);
|
||||
GXEnd();
|
||||
GXSetProjectionv(param_0);
|
||||
GXSetColorUpdate(GX_ENABLE);
|
||||
GXSetAlphaUpdate(GX_DISABLE); // no stencil-off: the next material's zmode write disables it
|
||||
return;
|
||||
}
|
||||
#else
|
||||
GXBegin(GX_QUADS, GX_VTXFMT0, 4);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
GXPosition3f32(mQuad[i].x, mQuad[i].y, mQuad[i].z);
|
||||
}
|
||||
GXEnd();
|
||||
#endif
|
||||
|
||||
if (mViewScale.y > 0.0f) {
|
||||
GXSetZMode(GX_ENABLE, GX_ALWAYS, GX_ENABLE);
|
||||
@@ -265,10 +369,223 @@ void dMirror_packet_c::modelDraw(J3DModel* i_model, Mtx param_1) {
|
||||
}
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
// FUN_0247c89c: HD multi-quad floor reflection helpers (F_SP117 room 2):
|
||||
static f32 dMirror_quadDist(const cXyz& p, const cXyz& bmin, const cXyz& bmax) {
|
||||
f32 ox = bmin.x - p.x;
|
||||
if (ox < 0.0f) ox = 0.0f;
|
||||
f32 oz = bmin.z - p.z;
|
||||
if (oz < 0.0f) oz = 0.0f;
|
||||
f32 px = p.x - bmax.x;
|
||||
if (px < 0.0f) px = 0.0f;
|
||||
f32 pz = p.z - bmax.z;
|
||||
if (pz < 0.0f) pz = 0.0f;
|
||||
return fabsf(p.y - bmin.y) + ox + oz + px + pz;
|
||||
}
|
||||
|
||||
static void dMirror_accumQuadBBox(view_class* view, view_port_class* view_port, const u32 scissor[4],
|
||||
cXyz* quad, f32& minX, f32& maxX, f32& minY, f32& maxY, f32& maxZ) {
|
||||
cXyz sp19C[5];
|
||||
int prjPosNum = 4;
|
||||
f32 nearZ = -view->near_;
|
||||
|
||||
int behind = 0;
|
||||
int lastFront = 0;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
cMtx_multVec(view->viewMtx, &quad[i], &sp19C[i]);
|
||||
if (sp19C[i].z >= nearZ) {
|
||||
behind++;
|
||||
} else {
|
||||
lastFront = i;
|
||||
}
|
||||
}
|
||||
if (behind >= 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
int var_r28 = lastFront;
|
||||
if (behind != 0) {
|
||||
int var_r27 = -1;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
int temp_r5 = (var_r28 + 1) % 4;
|
||||
if (var_r27 < 0) {
|
||||
if (sp19C[temp_r5].z >= nearZ) {
|
||||
var_r27 = temp_r5;
|
||||
}
|
||||
} else if (sp19C[temp_r5].z < nearZ) {
|
||||
int temp_r29 = (var_r27 + 3) % 4;
|
||||
cXyz d0 = sp19C[var_r27] - sp19C[temp_r29];
|
||||
d0 *= (nearZ - sp19C[temp_r29].z) / d0.z;
|
||||
sp19C[4] = sp19C[temp_r29] + d0;
|
||||
prjPosNum++;
|
||||
|
||||
cXyz d1 = sp19C[var_r28] - sp19C[temp_r5];
|
||||
d1 *= (nearZ - sp19C[temp_r5].z) / d1.z;
|
||||
sp19C[var_r28] = sp19C[temp_r5] + d1;
|
||||
|
||||
for (int j = var_r27; j != var_r28; j = (j + 1) % 4) {
|
||||
sp19C[j] = sp19C[var_r28];
|
||||
}
|
||||
break;
|
||||
}
|
||||
var_r28 = temp_r5;
|
||||
}
|
||||
}
|
||||
|
||||
f32 aspect = view->aspect;
|
||||
f32 tanHalf = tanf(MTXDegToRad(view->fovy * 0.5f));
|
||||
f32 vx, vy, vw, vh;
|
||||
if (view_port->x_orig != 0.0f) {
|
||||
vx = (((view_port->x_orig * 2.0f) + view_port->width) * 0.5f) - (FB_WIDTH / 2);
|
||||
vw = FB_WIDTH;
|
||||
} else {
|
||||
vx = view_port->x_orig;
|
||||
vw = view_port->width;
|
||||
}
|
||||
if (view_port->y_orig != 0.0f) {
|
||||
vy = (((view_port->y_orig * 2.0f) + view_port->height) * 0.5f) - (FB_HEIGHT / 2);
|
||||
vh = FB_HEIGHT;
|
||||
} else {
|
||||
vy = view_port->y_orig;
|
||||
vh = view_port->height;
|
||||
}
|
||||
|
||||
f32 sxMin = scissor[0];
|
||||
f32 sxMax = sxMin + scissor[2];
|
||||
f32 syMin = scissor[1];
|
||||
f32 syMax = syMin + scissor[3];
|
||||
|
||||
Vec* p = sp19C;
|
||||
for (int i = 0; i < prjPosNum; i++, p++) {
|
||||
p->y = p->y / (p->z * tanHalf);
|
||||
p->x = p->x / (aspect * (-p->z * tanHalf));
|
||||
p->x = vx + ((1.0f + p->x) * (vw * 0.5f));
|
||||
p->y = vy + ((1.0f + p->y) * (vh * 0.5f));
|
||||
p->x = cLib_minMaxLimit<f32>(p->x, sxMin, sxMax);
|
||||
p->y = cLib_minMaxLimit<f32>(p->y, syMin, syMax);
|
||||
if (p->x < minX) minX = p->x;
|
||||
if (p->x > maxX) maxX = p->x;
|
||||
if (p->y < minY) minY = p->y;
|
||||
if (p->y > maxY) maxY = p->y;
|
||||
if (p->z > maxZ) maxZ = p->z;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
void dMirror_packet_c::mainDraw() {
|
||||
ZoneScoped;
|
||||
j3dSys.reinitGX();
|
||||
|
||||
#if TARGET_PC
|
||||
f32 sp150[7];
|
||||
GXGetProjectionv(sp150);
|
||||
|
||||
f32 sp138[6];
|
||||
GXGetViewportv(sp138);
|
||||
|
||||
u32 scissor[4];
|
||||
GXGetScissor(&scissor[0], &scissor[1], &scissor[2], &scissor[3]);
|
||||
|
||||
view_class* view = dComIfGd_getView();
|
||||
view_port_class* view_port = dComIfGd_getViewport();
|
||||
|
||||
// HD mainDraw (FUN_0247e6e8):
|
||||
f32 minX = FLT_MAX, minY = FLT_MAX;
|
||||
f32 maxX = -FLT_MAX, maxY = -FLT_MAX, maxZ = -FLT_MAX;
|
||||
for (int q = 0; q < mQuadCount; q++) {
|
||||
dMirror_accumQuadBBox(view, view_port, scissor, &mQuad[q * 4], minX, maxX, minY, maxY, maxZ);
|
||||
}
|
||||
|
||||
if (maxX <= minX || maxY <= minY) {
|
||||
return;
|
||||
}
|
||||
if (fabsf(maxX - minX) < 8.0f || fabsf(maxY - minY) < 8.0f) {
|
||||
return;
|
||||
}
|
||||
|
||||
GXSetScissor((u32)minX, (u32)minY, (u32)(maxX - minX), (u32)(maxY - minY));
|
||||
|
||||
Mtx reflMtx[MAX_QUADS];
|
||||
for (int q = 0; q < mQuadCount; q++) {
|
||||
cXyz* quad = &mQuad[q * 4];
|
||||
cXyz e0 = quad[1] - quad[0];
|
||||
cXyz e1 = quad[2] - quad[1];
|
||||
cXyz n = e0.outprod(e1);
|
||||
n.normalizeZP();
|
||||
|
||||
f32 planeD = (n.x * quad[0].x) + (n.y * quad[0].y) + (n.z * quad[0].z);
|
||||
f32 dCenter = ((n.x * view->lookat.center.x) + (n.y * view->lookat.center.y) +
|
||||
(n.z * view->lookat.center.z)) -
|
||||
planeD;
|
||||
cXyz reflEye =
|
||||
view->lookat.eye -
|
||||
(n * (2.0f * (((n.x * view->lookat.eye.x) + (n.y * view->lookat.eye.y) +
|
||||
(n.z * view->lookat.eye.z)) -
|
||||
planeD)));
|
||||
cXyz reflCenter = view->lookat.center - (n * (2.0f * dCenter));
|
||||
|
||||
cXyz up(0.0f, 1.0f, 0.0f);
|
||||
if (mViewScale.y > 0.0f) {
|
||||
cXyz a = reflEye - view->lookat.eye;
|
||||
cXyz b = a.outprod(view->lookat.up);
|
||||
up = a.outprod(b);
|
||||
up.normalizeZP();
|
||||
up *= cXyz(-1.0f, -1.0f, -1.0f);
|
||||
}
|
||||
|
||||
Mtx look;
|
||||
mDoMtx_lookAt(look, &reflEye, &reflCenter, &up, view->bank);
|
||||
mDoMtx_stack_c::scaleS(mViewScale);
|
||||
mDoMtx_stack_c::concat(look);
|
||||
|
||||
f32 (*cur)[4] = mDoMtx_stack_c::get();
|
||||
for (int r = 0; r < 3; r++) {
|
||||
for (int c = 0; c < 4; c++) {
|
||||
reflMtx[q][r][c] = cur[r][c];
|
||||
}
|
||||
}
|
||||
}
|
||||
J3DShape::resetVcdVatCache();
|
||||
|
||||
bool wallQuad = !dusk::tphd_active() ||
|
||||
(mQuadCount <= 1 && mQuadBoxMax[0].y - mQuadBoxMin[0].y > 0.1f);
|
||||
for (int i = 0; i < mModelCount; i++) {
|
||||
Mtx& bm = mModels[i]->getBaseTRMtx();
|
||||
cXyz pos(bm[0][3], bm[1][3], bm[2][3]);
|
||||
int best = 0;
|
||||
if (!wallQuad) {
|
||||
const cXyz& eye = view->lookat.eye;
|
||||
best = -1;
|
||||
f32 bestDist = FLT_MAX;
|
||||
for (int q = 0; q < mQuadCount; q++) {
|
||||
if ((mQuadBoxMin[q].x <= pos.x || mQuadBoxMin[q].x <= eye.x) &&
|
||||
(mQuadBoxMin[q].z <= pos.z || mQuadBoxMin[q].z <= eye.z) &&
|
||||
(pos.x <= mQuadBoxMax[q].x || eye.x <= mQuadBoxMax[q].x) &&
|
||||
(pos.z <= mQuadBoxMax[q].z || eye.z <= mQuadBoxMax[q].z))
|
||||
{
|
||||
f32 dist = dMirror_quadDist(pos, mQuadBoxMin[q], mQuadBoxMax[q]);
|
||||
if (dist < bestDist) {
|
||||
bestDist = dist;
|
||||
best = q;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (best < 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
modelDraw(mModels[i], reflMtx[best]);
|
||||
}
|
||||
|
||||
j3dSys.reinitGX();
|
||||
if (dusk::tphd_active()) {
|
||||
mirrorZdraw(sp150, sp138, view->far_, minX, minY, maxX, maxY, maxZ);
|
||||
GXSetScissor(scissor[0], scissor[1], scissor[2], scissor[3]);
|
||||
} else {
|
||||
GXSetScissor(scissor[0], scissor[1], scissor[2], scissor[3]);
|
||||
mirrorZdraw(sp150, sp138, view->far_, minX, minY, maxX, maxY, maxZ);
|
||||
}
|
||||
#else
|
||||
cXyz sp19C[5];
|
||||
|
||||
Mtx sp16C;
|
||||
@@ -456,6 +773,7 @@ void dMirror_packet_c::mainDraw() {
|
||||
GXSetScissor(scissor[0], scissor[1], scissor[2], scissor[3]);
|
||||
mirrorZdraw(sp150, sp138, view->far_, var_f31, var_f30, var_f29, var_f28, var_f27);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void dMirror_packet_c::draw() {
|
||||
@@ -536,6 +854,36 @@ int daMirror_c::create() {
|
||||
mPacket.getViewScale().set(-1.0f, 1.0f, 1.0f);
|
||||
} else {
|
||||
if (type == 1) {
|
||||
#if TARGET_PC
|
||||
if (dusk::tphd_active() && strcmp(dComIfGp_getStartStageName(), "F_SP117") == 0 &&
|
||||
dComIfGp_getStartStageRoomNo() == 2)
|
||||
{
|
||||
// HD const DAT_1002f070 (world-space floor rects)
|
||||
static const struct {
|
||||
f32 xMin, xMax, y, zMin, zMax;
|
||||
} l_tot_quads[dMirror_packet_c::MAX_QUADS] = {
|
||||
{-1800.0f, 1800.0f, 999.0f, 747.0f, 5600.0f},
|
||||
{-670.0f, 670.0f, 999.0f, 5600.0f, 6400.0f},
|
||||
{-3530.0f, 3530.0f, 1526.0f, -8151.0f, -2014.0f},
|
||||
{-3530.0f, -1040.0f, 1526.0f, -2014.0f, -1089.0f},
|
||||
{1040.0f, 3530.0f, 1526.0f, -2014.0f, -1089.0f},
|
||||
{-700.0f, 700.0f, 2887.0f, -10700.0f, -8300.0f},
|
||||
};
|
||||
cXyz* q = mPacket.getQuad();
|
||||
for (int i = 0; i < dMirror_packet_c::MAX_QUADS; i++) {
|
||||
q[i * 4 + 0].set(l_tot_quads[i].xMin, l_tot_quads[i].y, l_tot_quads[i].zMin);
|
||||
q[i * 4 + 1].set(l_tot_quads[i].xMax, l_tot_quads[i].y, l_tot_quads[i].zMin);
|
||||
q[i * 4 + 2].set(l_tot_quads[i].xMax, l_tot_quads[i].y, l_tot_quads[i].zMax);
|
||||
q[i * 4 + 3].set(l_tot_quads[i].xMin, l_tot_quads[i].y, l_tot_quads[i].zMax);
|
||||
}
|
||||
mPacket.mQuadCount = dMirror_packet_c::MAX_QUADS;
|
||||
mPacket.getViewScale().set(1.0f, -1.0f, 1.0f);
|
||||
m_myObj = this;
|
||||
mPacket.calcMinMax();
|
||||
eyePos.set(current.pos.x, current.pos.y, current.pos.z);
|
||||
return cPhs_COMPLEATE_e;
|
||||
}
|
||||
#endif
|
||||
scale *= 10.0f;
|
||||
mPacket.getViewScale().set(1.0, -1.0, 1.0);
|
||||
} else {
|
||||
|
||||
@@ -10,8 +10,11 @@
|
||||
#include <cstring>
|
||||
|
||||
|
||||
static DUSK_CONSTEXPR daNpcT_evtData_c l_evtList[1] = {
|
||||
static DUSK_CONSTEXPR daNpcT_evtData_c l_evtList[DUSK_IF_ELSE(2, 1)] = {
|
||||
{"", 0},
|
||||
#if TARGET_PC
|
||||
{"DEFAULT_GETITEM", 0},
|
||||
#endif
|
||||
};
|
||||
|
||||
static DUSK_CONST char* l_resNameList[2] = {
|
||||
@@ -145,7 +148,7 @@ int daNpc_FairySeirei_c::Draw() {
|
||||
|
||||
int daNpc_FairySeirei_c::isDelete() {
|
||||
int ret = 0;
|
||||
if (daNpcT_chkEvtBit(0x1F9) == false) {
|
||||
if (IF_DUSK(mType != 4 &&) daNpcT_chkEvtBit(0x1F9) == false) {
|
||||
ret = 1;
|
||||
}
|
||||
return ret;
|
||||
@@ -359,6 +362,15 @@ int daNpc_FairySeirei_c::talk(int param_0) {
|
||||
}
|
||||
if (fopAcM_IsExecuting(mItemPartnerId)) {
|
||||
mTalking = TRUE;
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::tphd_active() && getType() == 4) {
|
||||
mEvtNo = 1;
|
||||
field_0xe33 = true;
|
||||
mSpeakEvent = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
evtChange();
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -14,6 +14,9 @@
|
||||
#include "d/actor/d_a_obj_ystone.h"
|
||||
#include <cstring>
|
||||
|
||||
#include "d/actor/d_a_alink.h"
|
||||
#include "dusk/tphd/LosTable.hpp"
|
||||
|
||||
static DUSK_CONST char* l_arcName = "ef_Portal";
|
||||
|
||||
static char const* l_clearEvName[9] = {
|
||||
@@ -101,7 +104,7 @@ int daObjBossWarp_c::Create() {
|
||||
}
|
||||
mBossClearMapToolId = 0xff;
|
||||
|
||||
if (!isFirst() || level == 8) {
|
||||
if ((!isFirst() || level == 8) IF_DUSK(&& !dusk::tphd::is_los_active())) {
|
||||
mBossWarpInEventId = dComIfGp_getEventManager().getEventIdx(this, "BOSS_WARPIN", 0xff);
|
||||
mBossWarpInMapToolId = 0xff;
|
||||
mAction = 3;
|
||||
@@ -217,6 +220,31 @@ BOOL daObjBossWarp_c::checkDistance() {
|
||||
}
|
||||
|
||||
int daObjBossWarp_c::execute() {
|
||||
#if TARGET_PC
|
||||
if (dusk::tphd::is_los_active()) {
|
||||
u8 sw = getSwNo();
|
||||
if (sw == 0xff || fopAcM_isSwitch(this, sw)) {
|
||||
if (mAction == ACT_WAIT) {
|
||||
mAction = ACT_WAIT_WARP;
|
||||
}
|
||||
|
||||
set_appear();
|
||||
|
||||
if (!dComIfGp_evmng_checkStartDemo()) {
|
||||
field_0x595 = true;
|
||||
field_0x620 = current.pos;
|
||||
}
|
||||
|
||||
event_proc_call();
|
||||
|
||||
daMidna_c* midna = (daMidna_c*)daPy_py_c::getMidnaActor();
|
||||
if (field_0x595 && midna != NULL) {
|
||||
midna->onTagWaitPos(&field_0x620);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (dStage_stagInfo_GetSTType(dComIfGp_getStage()->getStagInfo()) != 3) {
|
||||
u8 sw = getSwNo();
|
||||
if (sw == 0xff || fopAcM_isSwitch(this, sw)) {
|
||||
@@ -476,6 +504,14 @@ int daObjBossWarp_c::demoProc() {
|
||||
disappear(0);
|
||||
break;
|
||||
case 3: // SCENE_CHG
|
||||
#if TARGET_PC
|
||||
if (dusk::tphd::is_los_active()) {
|
||||
// tphd sets some event flags here for bookkeeping, ignoring for now
|
||||
daAlink_getAlinkActorClass()->mLosStickValue = -1.0f;
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
|
||||
int scene;
|
||||
if (isFirst()) {
|
||||
scene = getSceneListNo();
|
||||
@@ -536,6 +572,11 @@ int daObjBossWarp_c::demoProc() {
|
||||
break;
|
||||
case 6: // WALK_TARGET1
|
||||
dComIfGp_evmng_setGoal(¤t.pos);
|
||||
#if TARGET_PC
|
||||
if (dusk::tphd::is_los_active()) {
|
||||
daAlink_getAlinkActorClass()->mLosStickValue = 1.0f;
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 7: // APPEAR_END
|
||||
break;
|
||||
@@ -573,6 +614,14 @@ int daObjBossWarp_c::demoProc() {
|
||||
dComIfGp_evmng_cutEnd(mStaffId);
|
||||
break;
|
||||
case 3: // SCENE_CHG
|
||||
#if TARGET_PC
|
||||
if (dusk::tphd::is_los_active()) {
|
||||
if (mCounter++ == 0) {
|
||||
fopAcM_offDraw(this);
|
||||
dComIfGp_event_remove();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
case 4: // STONE_FALL
|
||||
if (ystone != NULL) {
|
||||
|
||||
@@ -26,6 +26,8 @@
|
||||
daObjDrop_HIO_c l_HIO;
|
||||
#endif
|
||||
|
||||
#include <dusk/ui/settings.hpp>
|
||||
|
||||
static void* searchParentSub(void* pproc, void* pdata) {
|
||||
daObjDrop_c* pdrop = (daObjDrop_c*)pdata;
|
||||
fopAc_ac_c* pym = (fopAc_ac_c*)pproc;
|
||||
@@ -103,9 +105,17 @@ void daObjDrop_c::dropGet() {
|
||||
dComIfGs_setLightDropNum(dComIfGp_getStartStageDarkArea(), num + 1);
|
||||
|
||||
if (dComIfGp_getStartStageDarkArea() == 2 &&
|
||||
#if TARGET_PC
|
||||
((dusk::tphd_active() &&
|
||||
dComIfGs_getLightDropNum(dComIfGp_getStartStageDarkArea()) == 11) ||
|
||||
!dusk::tphd_active() &&
|
||||
dComIfGs_getLightDropNum(dComIfGp_getStartStageDarkArea()) == 15
|
||||
))
|
||||
#else
|
||||
dComIfGs_getLightDropNum(dComIfGp_getStartStageDarkArea()) == 15)
|
||||
#endif
|
||||
{
|
||||
/* dSv_event_flag_c::F_0005 - Misc. - Gathered 14 Tears of Light in area 4 */
|
||||
/* dSv_event_flag_c::F_0005 - Misc. - Gathered 15 Tears of Light in area 4 */
|
||||
dComIfGs_onEventBit(dSv_event_flag_c::saveBitLabels[9]);
|
||||
}
|
||||
|
||||
|
||||
@@ -6,9 +6,10 @@
|
||||
#include "d/dolzel_rel.h" // IWYU pragma: keep
|
||||
|
||||
#include "d/actor/d_a_obj_lv8Lift.h"
|
||||
#include "d/d_bg_w.h"
|
||||
#include "d/d_com_inf_game.h"
|
||||
#include "d/d_path.h"
|
||||
#include "d/d_bg_w.h"
|
||||
#include "dusk/tphd/LosTable.hpp"
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/frame_interpolation.h"
|
||||
@@ -44,14 +45,14 @@ f32 const daL8Lift_c::mSpeed[16] = {
|
||||
};
|
||||
|
||||
int daL8Lift_c::CreateHeap() {
|
||||
J3DModelData* modelData = (J3DModelData*)dComIfG_getObjectRes("L8Lift", 5);
|
||||
J3DModelData* modelData = (J3DModelData*)dComIfG_getObjectRes(DUSK_IF_ELSE(dusk::tphd::is_los_active() ? "L8LiftSt" : "L8Lift", "L8Lift"), 5);
|
||||
JUT_ASSERT(190, modelData != NULL);
|
||||
mpModel = mDoExt_J3DModel__create(modelData, 0, 0x11000284);
|
||||
if (!mpModel) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int res = mBtk.init(modelData, (J3DAnmTextureSRTKey*)dComIfG_getObjectRes("L8Lift", 8),
|
||||
int res = mBtk.init(modelData, (J3DAnmTextureSRTKey*)dComIfG_getObjectRes(DUSK_IF_ELSE(dusk::tphd::is_los_active() ? "L8LiftSt" : "L8Lift", "L8Lift"), 8),
|
||||
1, 0, 1.0f, 0, -1);
|
||||
JUT_ASSERT(207, res == 1);
|
||||
|
||||
@@ -63,9 +64,9 @@ static daL8Lift_HIO_c l_HIO;
|
||||
int daL8Lift_c::create() {
|
||||
fopAcM_ct(this, daL8Lift_c);
|
||||
|
||||
int phase_state = dComIfG_resLoad(&mPhase, "L8Lift");
|
||||
int phase_state = dComIfG_resLoad(&mPhase, DUSK_IF_ELSE(dusk::tphd::is_los_active() ? "L8LiftSt" : "L8Lift", "L8Lift"));
|
||||
if (phase_state == cPhs_COMPLEATE_e) {
|
||||
if (MoveBGCreate("L8Lift", 11, dBgS_MoveBGProc_TypicalRotY, 0xd40, NULL) == cPhs_ERROR_e) {
|
||||
if (MoveBGCreate(DUSK_IF_ELSE(dusk::tphd::is_los_active() ? "L8LiftSt" : "L8Lift", "L8Lift"), 11, dBgS_MoveBGProc_TypicalRotY, DUSK_IF_ELSE(dusk::tphd::is_los_active() ? 0x1D40 : 0xD40, 0xd40) , NULL) == cPhs_ERROR_e) {
|
||||
return cPhs_ERROR_e;
|
||||
}
|
||||
|
||||
@@ -92,8 +93,17 @@ int daL8Lift_c::create() {
|
||||
|
||||
if (mSwbit == 0xff) {
|
||||
mBtk.setFrame(mBtk.getEndFrame() - 1.0f);
|
||||
mLightSet = 1;
|
||||
dKy_plight_set(&mLight);
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::tphd::is_los_active()) {
|
||||
mLightSet = 0;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
mLightSet = 1;
|
||||
dKy_plight_set(&mLight);
|
||||
}
|
||||
|
||||
init_modeWaitInit();
|
||||
} else {
|
||||
mNoRideOffSwTimer = 0;
|
||||
@@ -290,8 +300,15 @@ void daL8Lift_c::init_modeOnAnm() {
|
||||
void daL8Lift_c::modeOnAnm() {
|
||||
if (mBtk.play() == 1) {
|
||||
field_0x808 = 1;
|
||||
mLightSet = 1;
|
||||
dKy_plight_set(&mLight);
|
||||
|
||||
#if TARGET_PC
|
||||
if (!dusk::tphd::is_los_active())
|
||||
#endif
|
||||
{
|
||||
mLightSet = 1;
|
||||
dKy_plight_set(&mLight);
|
||||
}
|
||||
|
||||
init_modeMoveWait();
|
||||
}
|
||||
}
|
||||
@@ -428,20 +445,28 @@ int daL8Lift_c::Draw() {
|
||||
J3DMaterial* mpMatNode = modelData->getMaterialNodePointer(0);
|
||||
dComIfGd_setListDarkBG();
|
||||
|
||||
if (mpMatNode->getTexGenBlock()->getTexMtx(1)) {
|
||||
J3DTexMtxInfo* texMtxInfo = &mpMatNode->getTexGenBlock()->getTexMtx(1)->getTexMtxInfo();
|
||||
if (texMtxInfo) {
|
||||
Mtx mMtx58;
|
||||
C_MTXLightOrtho(mMtx58, 100.0f, -100.0f, -100.0f, 100.0f, 1.0f, 1.0f, 0.0f, 0.0f);
|
||||
mDoMtx_stack_c::XrotS(0x4000);
|
||||
mDoMtx_stack_c::transM(-current.pos.x, -current.pos.y, -current.pos.z);
|
||||
cMtx_concat(mMtx58, mDoMtx_stack_c::get(), texMtxInfo->mEffectMtx);
|
||||
#if TARGET_PC
|
||||
if (dusk::tphd::is_los_active()) {
|
||||
mDoExt_modelUpdateDL(mpModel);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
if (mpMatNode->getTexGenBlock()->getTexMtx(1)) {
|
||||
J3DTexMtxInfo* texMtxInfo = &mpMatNode->getTexGenBlock()->getTexMtx(1)->getTexMtxInfo();
|
||||
if (texMtxInfo) {
|
||||
Mtx mMtx58;
|
||||
C_MTXLightOrtho(mMtx58, 100.0f, -100.0f, -100.0f, 100.0f, 1.0f, 1.0f, 0.0f, 0.0f);
|
||||
mDoMtx_stack_c::XrotS(0x4000);
|
||||
mDoMtx_stack_c::transM(-current.pos.x, -current.pos.y, -current.pos.z);
|
||||
cMtx_concat(mMtx58, mDoMtx_stack_c::get(), texMtxInfo->mEffectMtx);
|
||||
}
|
||||
}
|
||||
|
||||
mBtk.entry(modelData);
|
||||
mDoExt_modelUpdateDL(mpModel);
|
||||
mBtk.remove(modelData);
|
||||
}
|
||||
|
||||
mBtk.entry(modelData);
|
||||
mDoExt_modelUpdateDL(mpModel);
|
||||
mBtk.remove(modelData);
|
||||
dComIfGd_setList();
|
||||
|
||||
J3DGXColor* mColor = mpMatNode->getTevKColor(1);
|
||||
@@ -453,7 +478,7 @@ int daL8Lift_c::Draw() {
|
||||
}
|
||||
|
||||
int daL8Lift_c::Delete() {
|
||||
dComIfG_resDelete(&mPhase, "L8Lift");
|
||||
dComIfG_resDelete(&mPhase, DUSK_IF_ELSE(dusk::tphd::is_los_active() ? "L8LiftSt" : "L8Lift", "L8Lift"));
|
||||
if (mLightSet) {
|
||||
dKy_plight_cut(&mLight);
|
||||
}
|
||||
|
||||
@@ -9,9 +9,19 @@
|
||||
#include "SSystem/SComponent/c_math.h"
|
||||
#include "d/d_com_inf_game.h"
|
||||
|
||||
static DUSK_CONST char* l_resNameIdx[2] = {
|
||||
static DUSK_CONST char* l_resNameIdx[DUSK_IF_ELSE(10, 2)] = {
|
||||
"P_Rgate",
|
||||
"SDGate",
|
||||
#if TARGET_PC
|
||||
"losGate1",
|
||||
"SDGate",
|
||||
"los_Maze",
|
||||
"losGate5",
|
||||
"losGate1",
|
||||
"losGate2",
|
||||
"losGate3",
|
||||
"losGate4",
|
||||
#endif
|
||||
};
|
||||
|
||||
daSwShutter_HIO_c::daSwShutter_HIO_c() {
|
||||
@@ -36,7 +46,20 @@ void daSwShutter_c::setBaseMtx() {
|
||||
mpModel->setBaseTRMtx(mDoMtx_stack_c::get());
|
||||
}
|
||||
|
||||
static const int l_bmdIdx[2] = {4, 4};
|
||||
static const int l_bmdIdx[DUSK_IF_ELSE(10, 2)] = {
|
||||
4,
|
||||
4,
|
||||
#if TARGET_PC
|
||||
4,
|
||||
4,
|
||||
1,
|
||||
4,
|
||||
4,
|
||||
4,
|
||||
4,
|
||||
4,
|
||||
#endif
|
||||
};
|
||||
|
||||
int daSwShutter_c::CreateHeap() {
|
||||
J3DModelData* modelData =
|
||||
@@ -50,7 +73,20 @@ int daSwShutter_c::CreateHeap() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static const int l_dzbIdx[2] = {7, 7};
|
||||
static const int l_dzbIdx[DUSK_IF_ELSE(10, 2)] = {
|
||||
7,
|
||||
7,
|
||||
#if TARGET_PC
|
||||
7,
|
||||
7,
|
||||
2,
|
||||
7,
|
||||
7,
|
||||
7,
|
||||
7,
|
||||
7,
|
||||
#endif
|
||||
};
|
||||
|
||||
int daSwShutter_c::create() {
|
||||
fopAcM_ct(this, daSwShutter_c);
|
||||
@@ -74,9 +110,39 @@ int daSwShutter_c::create() {
|
||||
field_0x5b0 = 0.0f;
|
||||
|
||||
if (fopAcM_isSwitch(this, getSwBit())) {
|
||||
#if TARGET_PC
|
||||
if (dusk::tphd_active()) {
|
||||
switch (getModelType()) {
|
||||
case 4:
|
||||
current.pos.y -= -370.0f;
|
||||
break;
|
||||
case 5:
|
||||
current.pos.y -= -450.0f;
|
||||
break;
|
||||
case 9:
|
||||
current.pos.y -= -740.0f;
|
||||
break;
|
||||
default:
|
||||
current.pos.y += -450.0f;
|
||||
break;
|
||||
}
|
||||
|
||||
init_modeMoveDownEnd();
|
||||
} else {
|
||||
current.pos.y += -450.0f;
|
||||
init_modeMoveDownEnd();
|
||||
}
|
||||
#else
|
||||
current.pos.y += -450.0f;
|
||||
init_modeMoveDownEnd();
|
||||
#endif
|
||||
} else {
|
||||
#if TARGET_PC
|
||||
if (dusk::tphd_active() && getModelType() == 2) {
|
||||
current.pos.y += -450.0f;
|
||||
}
|
||||
#endif
|
||||
|
||||
mShakeRot.x = 0;
|
||||
mShakeRot.y = 0;
|
||||
mShakeRot.z = 0;
|
||||
@@ -142,10 +208,23 @@ void daSwShutter_c::init_modeMoveDownInit() {
|
||||
mMaxAtten = l_HIO.mMaxAtten;
|
||||
mMinAtten = l_HIO.mMinAtten;
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::tphd_active()) {
|
||||
// TPHD: opening a Cave-of-Shadows shutter gate reveals the floor below
|
||||
dStage_showLOSNextFloor(fopAcM_GetRoomNo(this));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (mModelType == TYPE_SUBDAN_e) {
|
||||
dComIfGp_particle_set(0x8C73, ¤t.pos, &shape_angle, NULL);
|
||||
dComIfGp_particle_set(0x8C74, ¤t.pos, &shape_angle, NULL);
|
||||
} else {
|
||||
}
|
||||
#if TARGET_PC
|
||||
else if (dusk::tphd_active() && (mModelType == 0 || mModelType == 3 || mModelType == 4 || mModelType == 5 || mModelType == 9)) {
|
||||
mShakeStrength = 0.0f;
|
||||
}
|
||||
#endif
|
||||
else {
|
||||
dComIfGp_particle_set(0x8709, ¤t.pos, &shape_angle, NULL);
|
||||
dComIfGp_particle_set(0x870A, ¤t.pos, &shape_angle, NULL);
|
||||
}
|
||||
@@ -163,9 +242,16 @@ void daSwShutter_c::modeMoveDownInit() {
|
||||
}
|
||||
|
||||
void daSwShutter_c::init_modeMoveDown() {
|
||||
fopAcM_SetSpeedF(this, l_HIO.mInitSpeed);
|
||||
#if TARGET_PC
|
||||
if (dusk::tphd_active() && mModelType == 2) {
|
||||
fopAcM_SetSpeedF(this, 13.6f);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
fopAcM_SetSpeedF(this, l_HIO.mInitSpeed);
|
||||
}
|
||||
|
||||
if (mModelType == TYPE_SUBDAN_e) {
|
||||
if (mModelType == TYPE_SUBDAN_e IF_DUSK(|| (dusk::tphd_active() && (mModelType != 4 && mModelType != 5 && mModelType != 9)))) {
|
||||
dComIfGp_particle_set(0x8C77, ¤t.pos, &shape_angle, NULL);
|
||||
} else {
|
||||
dComIfGp_particle_set(0x870D, ¤t.pos, &shape_angle, NULL);
|
||||
@@ -175,11 +261,41 @@ void daSwShutter_c::init_modeMoveDown() {
|
||||
}
|
||||
|
||||
void daSwShutter_c::modeMoveDown() {
|
||||
cLib_chaseF(&speedF, l_HIO.mMaxSpeed, l_HIO.mAcceleration);
|
||||
#if TARGET_PC
|
||||
if (dusk::tphd_active() && mModelType == 2) {
|
||||
cLib_chaseF(&speedF, l_HIO.mInitSpeed, l_HIO.mAcceleration);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
cLib_chaseF(&speedF, l_HIO.mMaxSpeed, l_HIO.mAcceleration);
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
f32 target_dist;
|
||||
if (dusk::tphd_active()) {
|
||||
switch (getModelType()) {
|
||||
case 4:
|
||||
target_dist = cLib_addCalc(¤t.pos.y, home.pos.y - -370.0f, 1.0f, fopAcM_GetSpeedF(this), 1.0f);
|
||||
break;
|
||||
case 5:
|
||||
target_dist = cLib_addCalc(¤t.pos.y, home.pos.y - -450.0f, 1.0f, fopAcM_GetSpeedF(this), 1.0f);
|
||||
break;
|
||||
case 9:
|
||||
target_dist = cLib_addCalc(¤t.pos.y, home.pos.y - -740.0f, 1.0f, fopAcM_GetSpeedF(this), 1.0f);
|
||||
break;
|
||||
default:
|
||||
target_dist = cLib_addCalc(¤t.pos.y, home.pos.y + -450.0f, 1.0f, fopAcM_GetSpeedF(this), 1.0f);
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
target_dist = cLib_addCalc(¤t.pos.y, home.pos.y + -450.0f, 1.0f, fopAcM_GetSpeedF(this), 1.0f);
|
||||
}
|
||||
#else
|
||||
f32 target_dist =
|
||||
cLib_addCalc(¤t.pos.y, home.pos.y + -450.0f, 1.0f, fopAcM_GetSpeedF(this), 1.0f);
|
||||
#endif
|
||||
|
||||
if (mModelType == TYPE_SUBDAN_e) {
|
||||
if (mModelType == TYPE_SUBDAN_e IF_DUSK(|| (dusk::tphd_active() && (mModelType != 4 && mModelType != 5 && mModelType != 9)))) {
|
||||
mEmitterID0 = dComIfGp_particle_set(mEmitterID0, 0x8C75, ¤t.pos, &shape_angle, NULL);
|
||||
mEmitterID1 = dComIfGp_particle_set(mEmitterID1, 0x8C76, ¤t.pos, &shape_angle, NULL);
|
||||
} else {
|
||||
|
||||
@@ -54,14 +54,27 @@ BOOL daObjSwpush::Act_c::solidHeapCB(fopAc_ac_c* a_this) {
|
||||
return static_cast<daObjSwpush::Act_c*>(a_this)->create_heap();
|
||||
}
|
||||
|
||||
s16 const daObjSwpush::Act_c::M_bmd[3] = {BMDR_KBOTA_00, BMDR_S_LV3BOTA, BMDR_S_LV6BOTA};
|
||||
s16 const daObjSwpush::Act_c::M_bmd[DUSK_IF_ELSE(4, 3)] = {
|
||||
BMDR_KBOTA_00, BMDR_S_LV3BOTA, BMDR_S_LV6BOTA,
|
||||
#if TARGET_PC
|
||||
4
|
||||
#endif
|
||||
};
|
||||
|
||||
s16 const daObjSwpush::Act_c::M_dzb[3] = {DZB_KBOTA_00, DZB_KBOTA2_00, DZB_KBOTA3_00};
|
||||
s16 const daObjSwpush::Act_c::M_dzb[DUSK_IF_ELSE(4, 3)] = {
|
||||
DZB_KBOTA_00, DZB_KBOTA2_00, DZB_KBOTA3_00,
|
||||
#if TARGET_PC
|
||||
7
|
||||
#endif
|
||||
};
|
||||
|
||||
DUSK_CONST char* daObjSwpush::Act_c::M_arcname[3] = {
|
||||
DUSK_CONST char* daObjSwpush::Act_c::M_arcname[DUSK_IF_ELSE(4, 3)] = {
|
||||
"Kbota_00",
|
||||
"S_lv3bota",
|
||||
"S_lv6bota",
|
||||
#if TARGET_PC
|
||||
"S_losbota",
|
||||
#endif
|
||||
};
|
||||
|
||||
bool daObjSwpush::Act_c::create_heap() {
|
||||
@@ -117,7 +130,12 @@ cPhs_Step daObjSwpush::Act_c::create_res_load() {
|
||||
return cPhs_COMPLEATE_e;
|
||||
}
|
||||
|
||||
u32 const daObjSwpush::Act_c::M_heap_size[3] = {0x1000, 0x1000, 0x1000};
|
||||
u32 const daObjSwpush::Act_c::M_heap_size[DUSK_IF_ELSE(4, 3)] = {
|
||||
0x1000, 0x1000, 0x1000,
|
||||
#if TARGET_PC
|
||||
0x2000,
|
||||
#endif
|
||||
};
|
||||
|
||||
daObjSwpush::Hio_c::Attr_c const daObjSwpush::Act_c::M_attr[5] = {
|
||||
{
|
||||
|
||||
@@ -371,11 +371,41 @@ JKRHeap* daPy_anmHeap_c::setAnimeHeap() {
|
||||
#include "dusk/dvd_asset.hpp"
|
||||
using GameVersion = dusk::version::GameVersion;
|
||||
static const u8* l_sightDL_get() {
|
||||
#if DUSK_TPHD
|
||||
if(dusk::tphd_active()) {
|
||||
static u8 buf[0x89];
|
||||
static bool _ = (
|
||||
dusk::LoadRPXAsset(
|
||||
buf,
|
||||
0x1011a260,
|
||||
0x89
|
||||
),
|
||||
true
|
||||
);
|
||||
return buf;
|
||||
}
|
||||
else {
|
||||
static u8 buf[0x89];
|
||||
static bool _ = (
|
||||
dusk::LoadDolAsset(
|
||||
buf,
|
||||
{
|
||||
{GameVersion::GcnUsa, 0x803BA0C0},
|
||||
{GameVersion::GcnPal, 0x803BBDA0},
|
||||
{GameVersion::GcnJpn, 0x803B4220}
|
||||
},
|
||||
0x89
|
||||
),
|
||||
true
|
||||
);
|
||||
return buf;
|
||||
}
|
||||
#else
|
||||
static u8 buf[0x89];
|
||||
static bool _ = (
|
||||
dusk::LoadDolAsset(
|
||||
buf,
|
||||
{
|
||||
{
|
||||
{GameVersion::GcnUsa, 0x803BA0C0},
|
||||
{GameVersion::GcnPal, 0x803BBDA0},
|
||||
{GameVersion::GcnJpn, 0x803B4220}
|
||||
@@ -385,6 +415,7 @@ static const u8* l_sightDL_get() {
|
||||
true
|
||||
);
|
||||
return buf;
|
||||
#endif
|
||||
}
|
||||
#define l_sightDL (l_sightDL_get())
|
||||
#else
|
||||
|
||||
@@ -126,6 +126,10 @@ int daSwc00_c::execute() {
|
||||
case 1:
|
||||
case 2:
|
||||
case 7:
|
||||
#if TARGET_PC
|
||||
case 10: // HD Cave of Shadows region switch
|
||||
case 11:
|
||||
#endif
|
||||
case 15:
|
||||
if (sw2 != 0xff && !fopAcM_isSwitch(this, sw2)) {
|
||||
return 1;
|
||||
@@ -179,7 +183,17 @@ int daSwc00_c::execute() {
|
||||
field_0x584 = 1;
|
||||
}
|
||||
break;
|
||||
|
||||
#if TARGET_PC
|
||||
// HD Cave of Shadows region switch (CoS-controller bookkeeping omitted; not in this port)
|
||||
case 10:
|
||||
case 11:
|
||||
if (hitCheck(this)) {
|
||||
dComIfGs_onSwitch(sw1, fopAcM_GetRoomNo(this));
|
||||
field_0x583 = 1;
|
||||
field_0x584 = 1;
|
||||
}
|
||||
break;
|
||||
#endif
|
||||
case 7:
|
||||
case 8:
|
||||
if (hitCheck(this)) {
|
||||
|
||||
@@ -101,7 +101,7 @@ void daTit_HIO_c::genMessage(JORMContext* mctx) {
|
||||
#endif
|
||||
|
||||
int daTitle_c::CreateHeap() {
|
||||
J3DModelData* modelData = (J3DModelData*)dComIfG_getObjectRes(l_arcName, 10);
|
||||
J3DModelData* modelData = (J3DModelData*)dComIfG_getObjectRes(DUSK_IF_ELSE(dusk::tphd_active() ? "Title" : l_arcName, l_arcName), 10);
|
||||
JUT_ASSERT(258, modelData);
|
||||
mpModel = mDoExt_J3DModel__create(modelData, 0x80000, 0x11000285);
|
||||
|
||||
@@ -109,16 +109,16 @@ int daTitle_c::CreateHeap() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int res = mBck.init((J3DAnmTransform*)dComIfG_getObjectRes(l_arcName, 7), 1, 0, 2.0f, 0, -1, false);
|
||||
int res = mBck.init((J3DAnmTransform*)dComIfG_getObjectRes(DUSK_IF_ELSE(dusk::tphd_active() ? "Title" : l_arcName, l_arcName), 7), 1, 0, 2.0f, 0, -1, false);
|
||||
JUT_ASSERT(276, res == 1);
|
||||
|
||||
res = mBpk.init(modelData, (J3DAnmColor*)dComIfG_getObjectRes(l_arcName, 13), 1, 0, 2.0f, 0, -1);
|
||||
res = mBpk.init(modelData, (J3DAnmColor*)dComIfG_getObjectRes(DUSK_IF_ELSE(dusk::tphd_active() ? "Title" : l_arcName, l_arcName), 13), 1, 0, 2.0f, 0, -1);
|
||||
JUT_ASSERT(283, res == 1);
|
||||
|
||||
res = mBrk.init(modelData, (J3DAnmTevRegKey*)dComIfG_getObjectRes(l_arcName, 16), 1, 0, 2.0f, 0, -1);
|
||||
res = mBrk.init(modelData, (J3DAnmTevRegKey*)dComIfG_getObjectRes(DUSK_IF_ELSE(dusk::tphd_active() ? "Title" : l_arcName, l_arcName), 16), 1, 0, 2.0f, 0, -1);
|
||||
JUT_ASSERT(290, res == 1);
|
||||
|
||||
res = mBtk.init(modelData, (J3DAnmTextureSRTKey*)dComIfG_getObjectRes(l_arcName, 19), 1, 0, 2.0f, 0, -1);
|
||||
res = mBtk.init(modelData, (J3DAnmTextureSRTKey*)dComIfG_getObjectRes(DUSK_IF_ELSE(dusk::tphd_active() ? "Title" : l_arcName, l_arcName), 19), 1, 0, 2.0f, 0, -1);
|
||||
JUT_ASSERT(297, res == 1);
|
||||
|
||||
return 1;
|
||||
@@ -132,7 +132,7 @@ static procFunc daTitleProc[6] = {
|
||||
int daTitle_c::create() {
|
||||
fopAcM_ct(this, daTitle_c);
|
||||
|
||||
int phase_state = dComIfG_resLoad(&mPhaseReq, l_arcName);
|
||||
int phase_state = dComIfG_resLoad(&mPhaseReq, DUSK_IF_ELSE(dusk::tphd_active() ? "Title" : l_arcName, l_arcName));
|
||||
if (phase_state != cPhs_COMPLEATE_e) {
|
||||
return phase_state;
|
||||
}
|
||||
@@ -408,7 +408,7 @@ int daTitle_c::Draw() {
|
||||
int daTitle_c::Delete() {
|
||||
mDoHIO_DELETE_CHILD(g_daTitHIO.id);
|
||||
|
||||
dComIfG_resDelete(&mPhaseReq, l_arcName);
|
||||
dComIfG_resDelete(&mPhaseReq, DUSK_IF_ELSE(dusk::tphd_active() ? "Title" : l_arcName, l_arcName));
|
||||
JKR_DELETE(mTitle.Scr);
|
||||
JKR_DELETE(field_0x600);
|
||||
|
||||
|
||||
+1
-1
@@ -7505,7 +7505,7 @@ static bool sTouchFreeCameraActive = false;
|
||||
|
||||
bool dCamera_c::isAimActive() {
|
||||
auto* link = daAlink_getAlinkActorClass();
|
||||
return link != nullptr && link->checkAimContext() &&
|
||||
return link != nullptr && link->checkAimInputContext() &&
|
||||
dComIfGp_checkCameraAttentionStatus(link->field_0x317c, 0x10);
|
||||
}
|
||||
|
||||
|
||||
@@ -25,8 +25,10 @@
|
||||
#include "m_Do/m_Do_graphic.h"
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <dusk/ui/settings.hpp>
|
||||
|
||||
#include "dusk/string.hpp"
|
||||
#include "dusk/tphd/LosTable.hpp"
|
||||
|
||||
void dComIfG_play_c::ct() {
|
||||
mWindowNum = 0;
|
||||
@@ -2573,7 +2575,14 @@ u8 dComIfG_getNowCalcRegion() {
|
||||
|
||||
bool dComIfGp_isLightDropMapVisible() {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
#if TARGET_PC
|
||||
if (dComIfGs_isLightDropGetFlag(i) != FALSE &&
|
||||
((dusk::tphd_active() && dComIfGs_getLightDropNum(i) < 12) ||
|
||||
(!dusk::tphd_active() && dComIfGs_getLightDropNum(i) < 16)))
|
||||
{
|
||||
#else
|
||||
if (dComIfGs_isLightDropGetFlag(i) != FALSE && dComIfGs_getLightDropNum(i) < 16) {
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -2855,6 +2864,12 @@ BOOL dComIfGs_Wolf_Change_Check() {
|
||||
is_wolf = true;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::tphd::is_los_active()) {
|
||||
is_wolf = true;
|
||||
}
|
||||
#endif
|
||||
|
||||
OS_REPORT("dComIfGs_isSaveSwitch 12[%x] 13[%x]\n", dComIfGs_isSaveSwitch(12), dComIfGs_isSaveSwitch(13));
|
||||
|
||||
// Stage is Hyrule Field and Room is Eldin Gorge Entrance
|
||||
|
||||
@@ -1138,7 +1138,14 @@ void dDlst_shadowReal_c::draw() {
|
||||
{
|
||||
GXLoadTexMtxImm(mReceiverProjMtx, GX_TEXMTX0, GX_MTX3x4);
|
||||
}
|
||||
|
||||
#ifdef DUSK_TPHD
|
||||
GX2SetPolygonOffset(-10.0f, -10.0f, -10.0f, -10.0f, 0);
|
||||
#endif
|
||||
mShadowRealPoly.draw();
|
||||
#ifdef DUSK_TPHD
|
||||
GX2SetPolygonOffset(0.0f, 0.0f, 0.0f, 0.0f, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int psdRealCallBack(cBgS_ShdwDraw* param_0, cBgD_Vtx_t* param_1, int param_2,
|
||||
|
||||
+8
-1
@@ -229,7 +229,7 @@ static void (*item_func_ptr[256])() = {
|
||||
item_func_F_MAYFLY,
|
||||
item_func_noentry,
|
||||
item_func_noentry,
|
||||
item_func_noentry,
|
||||
DUSK_IF_ELSE(item_func_WALLET_LV4, item_func_noentry),
|
||||
item_func_noentry,
|
||||
item_func_noentry,
|
||||
item_func_noentry,
|
||||
@@ -2187,4 +2187,11 @@ int addBombCount(u8 i_bombType, u8 i_addNum) {
|
||||
return i_addNum;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
// HD item functions
|
||||
void item_func_WALLET_LV4() {
|
||||
dComIfGs_setWalletSize(3);
|
||||
}
|
||||
#endif
|
||||
|
||||
u8* dEnemyItem_c::mData;
|
||||
|
||||
@@ -221,7 +221,11 @@ dItem_itemResource dItem_data::item_resource[] = {
|
||||
{"O_gD_kagm", 0x0009, 0x000F, 0x0006, 0x000C,-0x0001, -0x1, -0x1, 0x0031, 0x50, 0x0000},
|
||||
{"F_gD_rupy", 0x0004,-0x0001,-0x0001, 0x0007,-0x0001, 0x0, -0x1, 0x002D, 0x64, 0x0000},
|
||||
{"F_gD_rupy", 0x0004,-0x0001,-0x0001, 0x0007,-0x0001, 0x0, -0x1, 0x002D, 0x64, 0x0000},
|
||||
#if TARGET_PC
|
||||
{"O_gD_puL4", 0x0001,-0x0001,-0x0001, -0x0001,-0x0001, -0x1, -0x1, 0x00AF, 0x26, 0x0251},
|
||||
#else
|
||||
{"F_gD_rupy", 0x0004,-0x0001,-0x0001, 0x0007,-0x0001, 0x0, -0x1, 0x002D, 0x64, 0x0000},
|
||||
#endif
|
||||
{"F_gD_rupy", 0x0004,-0x0001,-0x0001, 0x0007,-0x0001, 0x0, -0x1, 0x002D, 0x64, 0x0000},
|
||||
{"F_gD_rupy", 0x0004,-0x0001,-0x0001, 0x0007,-0x0001, 0x0, -0x1, 0x002D, 0x64, 0x0000},
|
||||
{"F_gD_rupy", 0x0004,-0x0001,-0x0001, 0x0007,-0x0001, 0x0, -0x1, 0x002D, 0x64, 0x0000},
|
||||
|
||||
@@ -689,6 +689,8 @@ void dMenu_Collect2D_c::screenSet() {
|
||||
field_0x184[0][3] = 0x199;
|
||||
} else if (dComIfGs_getWalletSize() == BIG_WALLET) {
|
||||
field_0x184[0][3] = 0x19a;
|
||||
} if (dusk::tphd_active() && dComIfGs_getWalletSize() == 3) {
|
||||
field_0x184[0][3] = 0x19c;
|
||||
} else {
|
||||
field_0x184[0][3] = 0x19b;
|
||||
}
|
||||
|
||||
+34
-6
@@ -447,7 +447,7 @@ void dMeter2Draw_c::init() {
|
||||
}
|
||||
|
||||
field_0x61c = 0.0f;
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int i = 0; i < DUSK_IF_ELSE((dusk::tphd_active() ? 12 : 16), 16); i++) {
|
||||
field_0x62c[i] = 0.0f;
|
||||
field_0x66c[i] = 0.0f;
|
||||
}
|
||||
@@ -728,7 +728,8 @@ void dMeter2Draw_c::draw() {
|
||||
|
||||
if (field_0x756 >= 0) {
|
||||
var_f29 = g_drawHIO.mLightDrop.mDropPikariAnimSpeed_Completed;
|
||||
int temp_r5_2 = g_drawHIO.mLightDrop.mPikariInterval * 15;
|
||||
int temp_r5_2 = g_drawHIO.mLightDrop.mPikariInterval * DUSK_IF_ELSE((dusk::tphd_active() ? 11 : 15), 15);
|
||||
|
||||
#ifdef TARGET_PC
|
||||
// FRAME INTERP NOTE: Set even if not advancing
|
||||
var_f28 = g_drawHIO.mLightDrop.mPikariScaleComplete;
|
||||
@@ -749,12 +750,12 @@ void dMeter2Draw_c::draw() {
|
||||
int temp_r5_3 = temp_r5_2 + 1;
|
||||
|
||||
if (field_0x756 == temp_r5_3) {
|
||||
if (field_0x62c[15] == 0.0f) {
|
||||
if (field_0x62c[DUSK_IF_ELSE((dusk::tphd_active() ? 11 : 15), 15)] == 0.0f) {
|
||||
field_0x756++;
|
||||
}
|
||||
var_f28 = g_drawHIO.mLightDrop.mPikariScaleComplete;
|
||||
} else if (field_0x756 >= g_drawHIO.mLightDrop.field_0x54 + temp_r5_3) {
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int i = 0; i < DUSK_IF_ELSE((dusk::tphd_active() ? 12 : 16), 16); i++) {
|
||||
field_0x62c[i] = 18.0f - var_f29;
|
||||
field_0x66c[i] = 18.0f - g_drawHIO.mLightDrop.mPikariLoopAnimSpeed;
|
||||
}
|
||||
@@ -767,7 +768,7 @@ void dMeter2Draw_c::draw() {
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int i = 0; i < DUSK_IF_ELSE((dusk::tphd_active() ? 12 : 16), 16); i++) {
|
||||
if (field_0x66c[i] > 0.0f) {
|
||||
drawPikari(mpSIParts[i][1], &g_drawHIO.mLightDrop.mPikariLoopBackStopFrame,
|
||||
g_drawHIO.mLightDrop.mPikariLoopBackScale,
|
||||
@@ -792,7 +793,7 @@ void dMeter2Draw_c::draw() {
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
for (int i = 0; i < DUSK_IF_ELSE((dusk::tphd_active() ? 12 : 16), 16); i++) {
|
||||
if (field_0x62c[i] > 0.0f) {
|
||||
drawPikari(mpSIParts[i][1], &field_0x62c[i], var_f28,
|
||||
g_drawHIO.mLightDrop.mDropPikariFrontOuter,
|
||||
@@ -1944,6 +1945,33 @@ void dMeter2Draw_c::setAlphaOxygenAnimeMax() {
|
||||
|
||||
void dMeter2Draw_c::drawLightDrop(u8 i_num, u8 i_needNum, f32 i_posX, f32 i_posY, f32 i_vesselScale,
|
||||
f32 param_5, u8 param_6) {
|
||||
#if TARGET_PC
|
||||
if (dusk::tphd_active()) {
|
||||
static u64 const tuta_0[] = {
|
||||
's_00',
|
||||
's_01',
|
||||
's_02',
|
||||
's_03',
|
||||
's_04',
|
||||
's_05',
|
||||
's_06',
|
||||
's_07',
|
||||
's_08',
|
||||
's_09',
|
||||
's_10',
|
||||
's_11',
|
||||
's_12',
|
||||
's_13',
|
||||
's_14',
|
||||
's_15',
|
||||
};
|
||||
|
||||
for (int i = 12; i < 16; i++) {
|
||||
mpScreen->search(tuta_0[i])->hide();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < 16; i++) {
|
||||
if (mpSIParts[i][0] != NULL) {
|
||||
mpSIParts[i][0]->scale(g_drawHIO.mLightDrop.mDropScale,
|
||||
|
||||
+47
-2
@@ -745,7 +745,7 @@ int dMsgFlow_c::getParam(u8* params) {
|
||||
return *(BE(int)*)params;
|
||||
}
|
||||
|
||||
queryFunc dMsgFlow_c::mQueryList[53] = {
|
||||
queryFunc dMsgFlow_c::mQueryList[DUSK_IF_ELSE(55, 53)] = {
|
||||
&dMsgFlow_c::query005, &dMsgFlow_c::query001, &dMsgFlow_c::query002, &dMsgFlow_c::query003,
|
||||
&dMsgFlow_c::query006, &dMsgFlow_c::query007, &dMsgFlow_c::query004, &dMsgFlow_c::query008,
|
||||
&dMsgFlow_c::query009, &dMsgFlow_c::query010, &dMsgFlow_c::query011, &dMsgFlow_c::query012,
|
||||
@@ -760,6 +760,11 @@ queryFunc dMsgFlow_c::mQueryList[53] = {
|
||||
&dMsgFlow_c::query045, &dMsgFlow_c::query046, &dMsgFlow_c::query047, &dMsgFlow_c::query048,
|
||||
&dMsgFlow_c::query049, &dMsgFlow_c::query050, &dMsgFlow_c::query051, &dMsgFlow_c::query052,
|
||||
&dMsgFlow_c::query053,
|
||||
|
||||
#if TARGET_PC
|
||||
&dMsgFlow_c::query054,
|
||||
&dMsgFlow_c::query055,
|
||||
#endif
|
||||
};
|
||||
|
||||
#if DEBUG
|
||||
@@ -1730,7 +1735,7 @@ u16 dMsgFlow_c::query053(mesg_flow_node_branch* i_flowNode_p, fopAc_ac_c* i_spea
|
||||
return ret;
|
||||
}
|
||||
|
||||
eventFunc dMsgFlow_c::mEventList[43] = {
|
||||
eventFunc dMsgFlow_c::mEventList[DUSK_IF_ELSE(46, 43)] = {
|
||||
&dMsgFlow_c::event000, &dMsgFlow_c::event001, &dMsgFlow_c::event002, &dMsgFlow_c::event003,
|
||||
&dMsgFlow_c::event004, &dMsgFlow_c::event005, &dMsgFlow_c::event006, &dMsgFlow_c::event007,
|
||||
&dMsgFlow_c::event008, &dMsgFlow_c::event009, &dMsgFlow_c::event010, &dMsgFlow_c::event011,
|
||||
@@ -1742,6 +1747,12 @@ eventFunc dMsgFlow_c::mEventList[43] = {
|
||||
&dMsgFlow_c::event032, &dMsgFlow_c::event033, &dMsgFlow_c::event034, &dMsgFlow_c::event035,
|
||||
&dMsgFlow_c::event036, &dMsgFlow_c::event037, &dMsgFlow_c::event038, &dMsgFlow_c::event039,
|
||||
&dMsgFlow_c::event040, &dMsgFlow_c::event041, &dMsgFlow_c::event042,
|
||||
|
||||
#if TARGET_PC
|
||||
&dMsgFlow_c::event043,
|
||||
&dMsgFlow_c::event044,
|
||||
&dMsgFlow_c::event045,
|
||||
#endif
|
||||
};
|
||||
|
||||
int dMsgFlow_c::event000(mesg_flow_node_event* i_flowNode_p, fopAc_ac_c* i_speaker_p) {
|
||||
@@ -2587,3 +2598,37 @@ int dMsgFlow_c::event041(mesg_flow_node_event* i_flowNode_p, fopAc_ac_c* i_speak
|
||||
int dMsgFlow_c::event042(mesg_flow_node_event* i_flowNode_p, fopAc_ac_c* i_speaker_p) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
// HD additions
|
||||
u16 dMsgFlow_c::query054(mesg_flow_node_branch* i_flowNode_p, fopAc_ac_c* i_speaker_p, int param_2) {
|
||||
// stub
|
||||
return 1;
|
||||
}
|
||||
|
||||
u16 dMsgFlow_c::query055(mesg_flow_node_branch* i_flowNode_p, fopAc_ac_c* i_speaker_p, int param_2) {
|
||||
// stub
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dMsgFlow_c::event043(mesg_flow_node_event* i_flowNode_p, fopAc_ac_c* i_speaker_p) {
|
||||
// stub
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dMsgFlow_c::event044(mesg_flow_node_event* i_flowNode_p, fopAc_ac_c* i_speaker_p) {
|
||||
// stub
|
||||
// runs when choosing to "withdraw" from cave of shadows
|
||||
|
||||
daAlink_c* player = daAlink_getAlinkActorClass();
|
||||
player->seStartOnlyReverb(Z2SE_WOLF_WARP_OUT);
|
||||
|
||||
JUTGamePad::C3ButtonReset::sResetSwitchPushing = true;
|
||||
return 1;
|
||||
}
|
||||
|
||||
int dMsgFlow_c::event045(mesg_flow_node_event* i_flowNode_p, fopAc_ac_c* i_speaker_p) {
|
||||
// stub
|
||||
return 1;
|
||||
}
|
||||
#endif
|
||||
|
||||
+39
-2
@@ -812,7 +812,14 @@ u32 dMsgObject_c::getMessageIndexAlways(u32 param_0) {
|
||||
}
|
||||
|
||||
u32 dMsgObject_c::getMessageIDAlways(u32 param_0) {
|
||||
return ((JMSMesgInfo_c*)((u8*)mpMsgRes + 0x20))->entries[param_0].message_id;
|
||||
JMSMesgInfo_c* info = (JMSMesgInfo_c*)((u8*)mpMsgRes + 0x20);
|
||||
#if TARGET_PC
|
||||
// 32-bit console wrap: HD r00_in.stb passes top-bit indices (0x80000000|idx)
|
||||
u32 off = (u32)param_0 * (u32)sizeof(JMSMesgEntry_c);
|
||||
return ((JMSMesgEntry_c*)((u8*)info->entries + off))->message_id;
|
||||
#else
|
||||
return info->entries[param_0].message_id;
|
||||
#endif
|
||||
}
|
||||
|
||||
s16 dMsgObject_c::getMessageGroup(u32 param_0) {
|
||||
@@ -1745,7 +1752,37 @@ void dMsgObject_c::readMessageGroupLocal(mDoDvdThd_mountXArchive_c** p_arcMount)
|
||||
#if TARGET_PC
|
||||
// Original game UB
|
||||
|
||||
if (dusk::version::isRegionPal()) {
|
||||
if (dusk::tphd_active()) {
|
||||
switch (dComIfGs_getPalLanguage()) {
|
||||
case dSv_player_config_c::LANGUAGE_GERMAN:
|
||||
snprintf(arcName, sizeof(arcName), "/res/Msgde/bmgres%d.arc", msgGroup);
|
||||
break;
|
||||
case dSv_player_config_c::LANGUAGE_FRENCH:
|
||||
if (dusk::version::isRegionPal()) {
|
||||
snprintf(arcName, sizeof(arcName), "/res/Msgfr/bmgres%d.arc", msgGroup);
|
||||
}
|
||||
else {
|
||||
snprintf(arcName, sizeof(arcName), "/res/Msgusfr/bmgres%d.arc", msgGroup);
|
||||
}
|
||||
break;
|
||||
case dSv_player_config_c::LANGUAGE_SPANISH:
|
||||
if (dusk::version::isRegionPal()) {
|
||||
snprintf(arcName, sizeof(arcName), "/res/Msgsp/bmgres%d.arc", msgGroup);
|
||||
} else {
|
||||
snprintf(arcName, sizeof(arcName), "/res/Msgussp/bmgres%d.arc", msgGroup);
|
||||
}
|
||||
break;
|
||||
case dSv_player_config_c::LANGUAGE_ITALIAN:
|
||||
snprintf(arcName, sizeof(arcName), "/res/Msgit/bmgres%d.arc", msgGroup);
|
||||
break;
|
||||
default:
|
||||
if (dusk::version::isRegionPal()) {
|
||||
snprintf(arcName, sizeof(arcName), "/res/Msguk/bmgres%d.arc", msgGroup);
|
||||
} else {
|
||||
snprintf(arcName, sizeof(arcName), "/res/Msgus/bmgres%d.arc", msgGroup);
|
||||
}
|
||||
}
|
||||
} else if (dusk::version::isRegionPal()) {
|
||||
switch (dComIfGs_getPalLanguage()) {
|
||||
case dSv_player_config_c::LANGUAGE_GERMAN:
|
||||
snprintf(arcName, sizeof(arcName), "/res/Msgde/bmgres%d.arc", msgGroup);
|
||||
|
||||
@@ -1736,6 +1736,7 @@ u32 dPa_control_c::set(u32 param_0, u8 param_1, u16 param_2, cXyz const* pos,
|
||||
level_c::emitter_c* this_00 = field_0x210.get(param_0);
|
||||
u8 uVar7 = getRM_ID(param_2);
|
||||
JPAResourceManager* this_01 = mEmitterMng->getResourceManager(uVar7);
|
||||
|
||||
u32 uVar3 = this_01->getResUserWork(param_2);
|
||||
if (this_00 != NULL) {
|
||||
if (param_2 == this_00->getNameId()) {
|
||||
|
||||
@@ -23,6 +23,9 @@
|
||||
#ifndef __MWERKS__
|
||||
#include "dusk/extras.h"
|
||||
#include "dusk/logging.h"
|
||||
#if DUSK_TPHD
|
||||
#include "dusk/tphd/HdAssetLayer.hpp"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
dRes_info_c::dRes_info_c() {
|
||||
@@ -643,7 +646,20 @@ int dRes_info_c::setRes() {
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
#if DUSK_TPHD
|
||||
// HD-redirected buffers live outside the JKR heap. Use the
|
||||
// registered arc-range size; getSize() would return 0/undefined.
|
||||
void* mArcHdr = ((JKRMemArchive*)mArchive)->mArcHeader;
|
||||
size_t arcSize = 0;
|
||||
if (auto hdRem = dusk::tphd::find_registered_hd_archive_remaining(mArcHdr)) {
|
||||
arcSize = *hdRem;
|
||||
} else {
|
||||
arcSize = JKRGetRootHeap()->getSize(mArcHdr);
|
||||
}
|
||||
mSize = arcSize + JKRGetMemBlockSize(NULL, mDataHeap);
|
||||
#else
|
||||
mSize = JKRGetRootHeap()->getSize(((JKRMemArchive*)mArchive)->mArcHeader) + JKRGetMemBlockSize(NULL, mDataHeap);
|
||||
#endif
|
||||
if (data_8074C6C0_debug) {
|
||||
JKRExpHeap* zeldaHeap = mDoExt_getZeldaHeap();
|
||||
OSReport("\e[33mdRes_info_c::setRes <使用=%08x(work:%08x) 連続空き=%08x 残り空き=%08x (%3d) %s.arc\n\e[m", mSize, r28, zeldaHeap->getFreeSize(), zeldaHeap->getTotalFreeSize(), getResNum(), this);
|
||||
@@ -1020,6 +1036,16 @@ int dRes_control_c::setObjectRes(char const* i_arcName, void* i_archiveRes, u32
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if DUSK_TPHD
|
||||
// HD hook for second JKRMemArchive constructor (see below)
|
||||
const std::string hdPath = fmt::format("/res/Object/{}.arc", i_arcName);
|
||||
if (auto hd = dusk::tphd::try_load_hd_archive(hdPath)) {
|
||||
DuskLog.info("[TPHD] setObjectRes redirect: {} -> HD ({} bytes)",
|
||||
i_arcName, (*hd)->size());
|
||||
i_archiveRes = const_cast<u8*>((*hd)->data());
|
||||
i_bufferSize = static_cast<u32>((*hd)->size());
|
||||
}
|
||||
#endif
|
||||
JKRMemArchive* memArchive = JKR_NEW JKRMemArchive(i_archiveRes, i_bufferSize, JKRMEMBREAK_FLAG_UNKNOWN0);
|
||||
if (memArchive == NULL || !memArchive->isMounted()) {
|
||||
return 0;
|
||||
|
||||
+34
-2
@@ -1504,7 +1504,39 @@ void dScnLogo_c::dvdDataLoad() {
|
||||
mpCardIconCommand = aramMount(ICON_RES_PATH, mDoExt_getJ2dHeap());
|
||||
|
||||
#if TARGET_PC
|
||||
if (getGameVersion() == GameVersion::GcnPal) {
|
||||
if (dusk::tphd_active) {
|
||||
switch (getPalLanguage()) {
|
||||
case 1:
|
||||
mpBmgResCommand = onMemMount("/res/Msgde/bmgres.arc");
|
||||
break;
|
||||
case 2:
|
||||
if (getGameVersion() == GameVersion::GcnPal) {
|
||||
mpBmgResCommand = onMemMount("/res/Msgfr/bmgres.arc");
|
||||
} else {
|
||||
mpBmgResCommand = onMemMount("/res/Msgusfr/bmgres.arc");
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if (getGameVersion() == GameVersion::GcnPal) {
|
||||
mpBmgResCommand = onMemMount("/res/Msgsp/bmgres.arc");
|
||||
} else {
|
||||
mpBmgResCommand = onMemMount("/res/Msgussp/bmgres.arc");
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
mpBmgResCommand = onMemMount("/res/Msgit/bmgres.arc");
|
||||
break;
|
||||
case 0:
|
||||
default:
|
||||
if (getGameVersion() == GameVersion::GcnPal) {
|
||||
mpBmgResCommand = onMemMount("/res/Msguk/bmgres.arc");
|
||||
}
|
||||
else {
|
||||
mpBmgResCommand = onMemMount("/res/Msgus/bmgres.arc");
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else if (getGameVersion() == GameVersion::GcnPal) {
|
||||
switch (getPalLanguage()) {
|
||||
case 1:
|
||||
mpBmgResCommand = onMemMount("/res/Msgde/bmgres.arc");
|
||||
@@ -1612,7 +1644,7 @@ void dScnLogo_c::dvdDataLoad() {
|
||||
mpRubyResCommand = onMemMount("/res/Fontus/rubyres.arc");
|
||||
#endif
|
||||
|
||||
mParticleCommand = mDoDvdThd_toMainRam_c::create(PARTICLE_COM_PATH, 0, dComIfGp_particle_getResHeap());
|
||||
mParticleCommand = mDoDvdThd_toMainRam_c::create(DUSK_IF_ELSE(dusk::tphd_active() ? "/res/Particle/common-r.jpc" : PARTICLE_COM_PATH, PARTICLE_COM_PATH), 0, dComIfGp_particle_getResHeap());
|
||||
|
||||
mItemTableCommand = mDoDvdThd_toMainRam_c::create("/res/ItemTable/item_table.bin", 0, NULL);
|
||||
JUT_ASSERT(2620, mItemTableCommand != NULL);
|
||||
|
||||
+5
-1
@@ -118,7 +118,7 @@ u8 dSv_player_status_a_c::getMixItemIndex(int i_no) const {
|
||||
}
|
||||
|
||||
u16 dSv_player_status_a_c::getRupeeMax() const {
|
||||
if (mWalletSize < 3) { // if you make this a default, it wont match. Compiler, pls.
|
||||
if (mWalletSize < 3 IF_DUSK(|| (dusk::tphd_active() && mWalletSize < 4))) { // if you make this a default, it wont match. Compiler, pls.
|
||||
switch (mWalletSize) {
|
||||
case WALLET:
|
||||
#if TARGET_PC
|
||||
@@ -138,6 +138,10 @@ u16 dSv_player_status_a_c::getRupeeMax() const {
|
||||
#else
|
||||
return 1000;
|
||||
#endif
|
||||
#if TARGET_PC
|
||||
case 3: // colossal wallet
|
||||
return 9999;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+95
-2
@@ -25,8 +25,9 @@
|
||||
#include "dusk/logging.h"
|
||||
#include "dusk/string.hpp"
|
||||
#if TARGET_PC
|
||||
#include <format>
|
||||
#include <fmt/ranges.h>
|
||||
#include "dusk/tphd/LosTable.hpp"
|
||||
#include "os_report.h"
|
||||
#endif
|
||||
|
||||
void dStage_nextStage_c::set(const char* i_stage, s8 i_roomId, s16 i_point, s8 i_layer, s8 i_wipe,
|
||||
@@ -312,7 +313,7 @@ int dStage_roomControl_c::loadRoom(int roomCount, u8* rooms, bool param_2) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
BOOL r26 = TRUE;
|
||||
for (int roomNo = 0; roomNo < ARRAY_SIZE(mStatus); roomNo++) {
|
||||
if (dStage_roomControl_c::checkStatusFlag(roomNo, 0x01)) {
|
||||
@@ -2094,6 +2095,85 @@ static int dStage_doorInfoInit(dStage_dt_c* i_stage, void* i_data, int entryNum,
|
||||
return 1;
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
// Mirrors HD FUN_02ab7e94 (los override): the file RTBL is a linear placeholder chain
|
||||
// (r19 -> [19,18,20]); rewrite each room's m_rooms in place from los.bin floor links.
|
||||
// next gets NO 0x80 (floor not yet unlocked) so it is not bg-loaded at stage-create;
|
||||
// RoomCheck streams it in after the player exists. m_rooms arrays are 3 bytes each
|
||||
// (verified: contiguous, gap=3), so writing up to 3 bytes in place is safe.
|
||||
static void dStage_LOSRoomReadOverride(roomRead_class* p_node) {
|
||||
OFFSET_PTR(roomRead_data_class)* rtbl = p_node->m_entries;
|
||||
|
||||
for (int roomNo = 0; roomNo < p_node->num; roomNo++) {
|
||||
int nextFloorNo = dusk::tphd::los_next_floor(roomNo);
|
||||
int prevFloorNo = dusk::tphd::los_prev_floor(roomNo);
|
||||
u8* roomData = rtbl[roomNo]->m_rooms;
|
||||
int n = 1;
|
||||
|
||||
roomData[0] = (u8)((roomNo & 0x3f) | (roomData[0] & 0xc0));
|
||||
if (nextFloorNo > -1) {
|
||||
// nextFloorNo is bg-loaded only once its floor-unlock switch (roomNo + 0x80) is set
|
||||
u8 nextBg = dComIfGs_isSwitch(roomNo + 0x80, roomNo) ? 0x80 : 0;
|
||||
roomData[1] = (u8)((nextFloorNo & 0x3f) | nextBg);
|
||||
n = 2;
|
||||
}
|
||||
|
||||
if (prevFloorNo > -1) {
|
||||
roomData[n] = (u8)((prevFloorNo & 0x3f) | 0x80);
|
||||
n++;
|
||||
}
|
||||
|
||||
if (nextFloorNo < 0 && prevFloorNo > -1) {
|
||||
int prevPrevFloorNo = dusk::tphd::los_prev_floor(prevFloorNo);
|
||||
if (prevPrevFloorNo > -1) {
|
||||
roomData[n] = (u8)((prevPrevFloorNo & 0x3f) | 0x80);
|
||||
n++;
|
||||
}
|
||||
}
|
||||
|
||||
rtbl[roomNo]->num = (u8)n;
|
||||
OSReport("[SB11] override r%-2d nextFloorNo=%d prevFloorNo=%d -> num=%d [%02x %02x %02x]\n",
|
||||
roomNo, nextFloorNo, prevFloorNo, n, roomData[0], n > 1 ? roomData[1] : 0, n > 2 ? roomData[2] : 0);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if TARGET_PC
|
||||
// Mirrors HD FUN_028290d0's reveal (called by the Cave-of-Shadows gate sWallShutter when it
|
||||
// opens): mark `fromRoom`'s los next-floor as bg (0x80) in fromRoom's m_rooms and clear that
|
||||
// floor's 0x08 status, so its daBg mesh gets created. Without 0x80 the floor streams in but the
|
||||
// mesh stays hidden (objectSetCheck skips fopAcM_create(BG) while status flag 0x08 is set).
|
||||
// No-op outside los stages. This replaces the earlier per-frame RoomCheck reveal (which churned
|
||||
// room loads). HD reveals the next floor at the moment you open the descent gate, not per-frame.
|
||||
void dStage_showLOSNextFloor(int fromRoom) {
|
||||
if (!dusk::tphd::is_los_active()) {
|
||||
return;
|
||||
}
|
||||
|
||||
roomRead_class* room = dComIfGp_getStageRoom();
|
||||
if (room == NULL || fromRoom < 0 || fromRoom >= room->num) {
|
||||
return;
|
||||
}
|
||||
|
||||
int nextFloorNo = dusk::tphd::los_next_floor(fromRoom);
|
||||
if (nextFloorNo < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
roomRead_data_class* e = room->m_entries[fromRoom];
|
||||
u8* roomData = e->m_rooms;
|
||||
for (int j = 0; j < e->num; j++) {
|
||||
if ((roomData[j] & 0x3f) == nextFloorNo) {
|
||||
roomData[j] = (u8)(roomData[j] | 0x80);
|
||||
}
|
||||
}
|
||||
|
||||
dComIfGp_roomControl_offStatusFlag(nextFloorNo, 0x08);
|
||||
OSReport("[SB11] gate reveal: from r%d -> next floor r%d\n", fromRoom, nextFloorNo);
|
||||
}
|
||||
#endif
|
||||
|
||||
static int dStage_roomReadInit(dStage_dt_c* i_stage, void* i_data, int param_2, void* param_3) {
|
||||
UNUSED(param_2);
|
||||
roomRead_class* p_node = (roomRead_class*)((int*)i_data + 1);
|
||||
@@ -2113,6 +2193,12 @@ static int dStage_roomReadInit(dStage_dt_c* i_stage, void* i_data, int param_2,
|
||||
#endif
|
||||
}
|
||||
|
||||
#if TARGET_PC
|
||||
if (dusk::tphd_active() && dusk::tphd::is_los_active()) {
|
||||
dStage_LOSRoomReadOverride(p_node);
|
||||
}
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
@@ -2301,6 +2387,13 @@ static int dStage_mecoInfoInit(dStage_dt_c* i_stage, void* i_data, int param_2,
|
||||
dStage_MemoryConfig_data* entry_p = pd->field_0x4;
|
||||
|
||||
for (int i = 0; i < pd->m_num; i++) {
|
||||
#if TARGET_PC
|
||||
// los stages (D_SB11): the file MEC0 (roomNo%3) collides for los-adjacent floors;
|
||||
// HD re-derives the block from the los floor index instead (FUN_02ab8910).
|
||||
if (dusk::tphd_active() && dusk::tphd::is_los_active()) {
|
||||
entry_p->m_blockID = (u8)(dusk::tphd::los_floor_index(entry_p->m_roomNo) % 3);
|
||||
}
|
||||
#endif
|
||||
dStage_roomControl_c::setMemoryBlockID(entry_p->m_roomNo, entry_p->m_blockID);
|
||||
entry_p++;
|
||||
}
|
||||
|
||||
@@ -617,6 +617,10 @@ void dDlst_TimerScrnDraw_c::setScreen(s32 param_0, JKRArchive* i_archive) {
|
||||
|
||||
static_cast<J2DTextBox*>(mpGetInScreen->search(MULTI_CHAR('get_in_s')))->setFont(mDoExt_getMesgFont());
|
||||
static_cast<J2DTextBox*>(mpGetInScreen->search(MULTI_CHAR('get_in')))->setFont(mDoExt_getMesgFont());
|
||||
#if TARGET_PC
|
||||
static_cast<J2DTextBox*>(mpGetInScreen->search(MULTI_CHAR('get_in_s')))->setString(0x100, "");
|
||||
static_cast<J2DTextBox*>(mpGetInScreen->search(MULTI_CHAR('get_in')))->setString(0x100, "");
|
||||
#endif
|
||||
|
||||
for (int i = 0; i < 51; i++) {
|
||||
m_getin_info[i].bck_frame = 0.0f;
|
||||
|
||||
@@ -6,6 +6,10 @@
|
||||
#include "d/d_path.h"
|
||||
#include "SSystem/SComponent/c_math.h"
|
||||
|
||||
#if TARGET_PC
|
||||
#include "dusk/logging.h"
|
||||
#endif
|
||||
|
||||
static bool data_80450680 = true;
|
||||
|
||||
dTres_c::typeGroupData_c* dTres_c::mTypeGroupData;
|
||||
@@ -49,11 +53,25 @@ void dTres_c::addData(dTres_c::list_class* p_list, s8 roomNo) {
|
||||
data_s* listData = p_list->field_0x4->getDataPointer();
|
||||
typeGroupData_c* groupData = &mTypeGroupData[mNum];
|
||||
for (int i = 0; i < p_list->field_0x0; i++, listData++, groupData++) {
|
||||
#if TARGET_PC
|
||||
if (mNum >= 0x40) {
|
||||
DuskLog.warn("dTres_c::addData: treasure data overflow, skipping remaining entries");
|
||||
break;
|
||||
}
|
||||
#endif
|
||||
*(data_s*)groupData = *listData;
|
||||
groupData->mRoomNo = roomNo;
|
||||
groupData->mStatus = 0;
|
||||
|
||||
u32 typeGroupNo = getTypeToTypeGroupNo(groupData->mType);
|
||||
#if TARGET_PC
|
||||
// Skip TPHD entries for now
|
||||
if (typeGroupNo >= TYPE_GROUP_ENUM_NUMBER) {
|
||||
DuskLog.warn("dTres_c::addData: unknown treasure type 0x{:02x}, skipping", groupData->mType);
|
||||
mNum++;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
groupData->setNextDataPointer(NULL);
|
||||
groupData->setTypeGroupNo(typeGroupNo);
|
||||
|
||||
|
||||
@@ -8,6 +8,11 @@
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#ifdef DUSK_TPHD
|
||||
#include <zlib.h>
|
||||
#include <fstream>
|
||||
#endif
|
||||
|
||||
namespace dusk {
|
||||
|
||||
static const u8* s_dolData = nullptr; // pointer to dol data
|
||||
@@ -136,4 +141,145 @@ bool LoadArchivedRelAsset(void* dst, u32 memType, const char* relFileName, std::
|
||||
return true;
|
||||
}
|
||||
|
||||
#ifdef DUSK_TPHD
|
||||
enum struct SectionType : uint32_t // sh_type
|
||||
{
|
||||
// https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
|
||||
SHT_NULL = 0,
|
||||
SHT_PROGBITS = 1,
|
||||
SHT_SYMTAB = 2,
|
||||
SHT_STRTAB = 3,
|
||||
SHT_RELA = 4,
|
||||
SHT_HASH = 5,
|
||||
SHT_DYNAMIC = 6,
|
||||
SHT_NOTE = 7,
|
||||
SHT_NOBITS = 8,
|
||||
SHT_REL = 9,
|
||||
SHT_SHLIB = 10,
|
||||
SHT_DYNSYM = 11,
|
||||
SHT_INIT_ARRAY = 14,
|
||||
SHT_FINI_ARRAY = 15,
|
||||
SHT_PREINIT_ARRAY = 16,
|
||||
SHT_GROUP = 17,
|
||||
SHT_SYMTAB_SHNDX = 18,
|
||||
|
||||
// https://refspecs.linuxfoundation.org/LSB_2.1.0/LSB-Core-generic/LSB-Core-generic/elftypes.html
|
||||
SHT_LOPROC = 0x70000000,
|
||||
SHT_HIPROC = 0x7fffffff,
|
||||
SHT_LOUSER = 0x80000000,
|
||||
SHT_HIUSER = 0xffffffff,
|
||||
|
||||
// from https://gist.github.com/exjam/b4290ad23828cbc04db4 and looking at the rpx itself
|
||||
SHT_RPL_EXPORTS = 0x80000001,
|
||||
SHT_RPL_IMPORTS = 0x80000002,
|
||||
SHT_RPL_CRCS = 0x80000003,
|
||||
SHT_RPL_FILEINFO = 0x80000004
|
||||
};
|
||||
|
||||
enum struct SectionFlags : uint32_t {
|
||||
// https://en.wikipedia.org/wiki/Executable_and_Linkable_Format
|
||||
SHF_WRITE = 0x1,
|
||||
SHF_ALLOC = 0x2,
|
||||
SHF_EXECINSTR = 0x4,
|
||||
|
||||
// from https://gist.github.com/exjam/b4290ad23828cbc04db4 and looking at the rpx itself
|
||||
SHF_DEFLATED = 0x08000000
|
||||
};
|
||||
|
||||
struct Elf32_Ehdr {
|
||||
uint8_t e_ident[0x10];
|
||||
BE(u16) e_type;
|
||||
BE(u16) e_machine;
|
||||
BE(u32) e_version;
|
||||
BE(u32) e_entry;
|
||||
BE(u32) e_phoff;
|
||||
BE(u32) e_shoff;
|
||||
BE(u32) e_flags;
|
||||
BE(u16) e_ehsize;
|
||||
BE(u16) e_phentsize;
|
||||
BE(u16) e_phnum;
|
||||
BE(u16) e_shentsize;
|
||||
BE(u16) e_shnum;
|
||||
BE(u16) e_shstrndx;
|
||||
};
|
||||
|
||||
struct Elf32_Shdr {
|
||||
BE(u32) sh_name;
|
||||
BE(u32) sh_type; // SectionType
|
||||
BE(u32) sh_flags;
|
||||
BE(u32) sh_addr;
|
||||
BE(u32) sh_offset;
|
||||
BE(u32) sh_size;
|
||||
BE(u32) sh_link;
|
||||
BE(u32) sh_info;
|
||||
BE(u32) sh_addralign;
|
||||
BE(u32) sh_entsize;
|
||||
};
|
||||
|
||||
struct RPXSection {
|
||||
u32 vaddr;
|
||||
std::string data;
|
||||
};
|
||||
|
||||
static std::vector<RPXSection> g_rpxSections;
|
||||
|
||||
static bool EnsureRPXParsed() {
|
||||
if (!g_rpxSections.empty()) return true;
|
||||
|
||||
std::ifstream rpx(dusk::tphd_content_path().parent_path() / "code" / "Zelda.rpx", std::ios::binary);
|
||||
if (!rpx.is_open()) {
|
||||
DuskLog.fatal("dvd_asset: Failed to open Zelda.rpx");
|
||||
return false;
|
||||
}
|
||||
|
||||
Elf32_Ehdr ehdr;
|
||||
rpx.read(reinterpret_cast<char*>(&ehdr), sizeof(ehdr));
|
||||
|
||||
for (int i = 0; i < ehdr.e_shnum; i++) {
|
||||
rpx.seekg(ehdr.e_shoff + ehdr.e_shentsize * i, std::ios::beg);
|
||||
|
||||
Elf32_Shdr shdr;
|
||||
rpx.read(reinterpret_cast<char*>(&shdr), sizeof(shdr));
|
||||
|
||||
if(shdr.sh_addr != 0 && shdr.sh_offset != 0 && (shdr.sh_type & ((int)SectionType::SHT_NULL | (int)SectionType::SHT_NOBITS)) == 0) {
|
||||
rpx.seekg(shdr.sh_offset, std::ios::beg);
|
||||
|
||||
RPXSection& section = g_rpxSections.emplace_back();
|
||||
section.vaddr = shdr.sh_addr;
|
||||
|
||||
if(shdr.sh_flags & (int)SectionFlags::SHF_DEFLATED) {
|
||||
BE(u32) size;
|
||||
std::string inData(shdr.sh_size - 4, '\0');
|
||||
rpx.read(reinterpret_cast<char*>(&size), sizeof(size));
|
||||
rpx.read(inData.data(), inData.size());
|
||||
|
||||
section.data.resize(size);
|
||||
|
||||
unsigned long outSize = section.data.size();
|
||||
uncompress(reinterpret_cast<unsigned char*>(section.data.data()), &outSize, reinterpret_cast<unsigned char*>(inData.data()), inData.size());
|
||||
}
|
||||
else {
|
||||
section.data.resize(shdr.sh_size);
|
||||
rpx.read(section.data.data(), section.data.size());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool LoadRPXAsset(void* dst, uint32_t virtualAddress, s32 size) {
|
||||
if(!EnsureRPXParsed()) return false;
|
||||
|
||||
const auto& it = std::ranges::find_if(g_rpxSections, [virtualAddress, size](const RPXSection& section) { return section.vaddr <= virtualAddress && virtualAddress + size <= section.vaddr + section.data.size(); });
|
||||
if(it == g_rpxSections.end()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
it->data.copy(static_cast<char*>(dst), size, virtualAddress - it->vaddr);
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
} // namespace dusk
|
||||
|
||||
@@ -311,4 +311,5 @@ std::string display_name_for_path(std::string_view path) {
|
||||
#endif
|
||||
return fallback_display_name(path);
|
||||
}
|
||||
|
||||
} // namespace dusk
|
||||
|
||||
@@ -19,4 +19,7 @@ void ShowFolderSelect(
|
||||
|
||||
std::string display_name_for_path(std::string_view path);
|
||||
|
||||
void ShowFolderSelect(FileCallback callback, void* userdata, SDL_Window* window,
|
||||
const char* default_location);
|
||||
|
||||
} // namespace dusk
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include <aurora/lib/internal.hpp>
|
||||
#include <SDL3/SDL_misc.h>
|
||||
|
||||
#include "dusk/tphd/LosTable.hpp"
|
||||
|
||||
#if defined(__APPLE__)
|
||||
#include <TargetConditionals.h>
|
||||
#endif
|
||||
@@ -106,6 +108,10 @@ namespace dusk {
|
||||
ImGui::MenuItem("Stub Log", nullptr, &m_showStubLog);
|
||||
ImGui::MenuItem("Actor Spawner", nullptr, &m_showActorSpawner);
|
||||
|
||||
if (ImGui::MenuItem("Load Cave of Shadows")) {
|
||||
dusk::tphd::set_los_next_stage();
|
||||
}
|
||||
|
||||
if (!dusk::IsGameLaunched) {
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
#include "dusk/settings.h"
|
||||
#include "dusk/config.hpp"
|
||||
#include "dusk/main.h"
|
||||
|
||||
#include <system_error>
|
||||
|
||||
namespace dusk {
|
||||
|
||||
@@ -158,6 +161,9 @@ UserSettings g_userSettings = {
|
||||
.backend = {
|
||||
.isoPath {"backend.isoPath", ""},
|
||||
.isoVerification {"backend.isoVerification", DiscVerificationState::Unknown},
|
||||
#if DUSK_TPHD
|
||||
.hdContentPath {"backend.hdContentPath", ""},
|
||||
#endif
|
||||
.graphicsBackend {"backend.graphicsBackend", "auto"},
|
||||
.skipPreLaunchUI {"backend.skipPreLaunchUI", false},
|
||||
.showPipelineCompilation {"backend.showPipelineCompilation", false},
|
||||
@@ -212,6 +218,28 @@ UserSettings& getSettings() {
|
||||
return g_userSettings;
|
||||
}
|
||||
|
||||
std::filesystem::path tphd_content_path() {
|
||||
#if DUSK_TPHD
|
||||
const std::string& hdPath = g_userSettings.backend.hdContentPath;
|
||||
if (!hdPath.empty()) {
|
||||
return hdPath;
|
||||
}
|
||||
|
||||
if (!ConfigPath.empty()) {
|
||||
std::error_code ec;
|
||||
auto localPath = ConfigPath / "tphd" / "content";
|
||||
if (std::filesystem::is_directory(localPath, ec)) {
|
||||
return localPath;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return {};
|
||||
}
|
||||
|
||||
bool tphd_active() {
|
||||
return !tphd_content_path().empty();
|
||||
}
|
||||
|
||||
void registerSettings() {
|
||||
// Video
|
||||
Register(g_userSettings.video.enableFullscreen);
|
||||
@@ -343,6 +371,9 @@ void registerSettings() {
|
||||
|
||||
Register(g_userSettings.backend.isoPath);
|
||||
Register(g_userSettings.backend.isoVerification);
|
||||
#if DUSK_TPHD
|
||||
Register(g_userSettings.backend.hdContentPath);
|
||||
#endif
|
||||
Register(g_userSettings.backend.graphicsBackend);
|
||||
Register(g_userSettings.backend.skipPreLaunchUI);
|
||||
Register(g_userSettings.backend.showPipelineCompilation);
|
||||
|
||||
@@ -0,0 +1,691 @@
|
||||
/*
|
||||
* Ported from decaf-emu/addrlib (https://github.com/decaf-emu/addrlib),
|
||||
* src/r600/r600addrlib.{cpp,h} and src/core/addrlib.cpp.
|
||||
*
|
||||
* Original AMD copyright header:
|
||||
*
|
||||
* Copyright (C) 2014 Advanced Micro Devices, Inc.
|
||||
* All Rights Reserved.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining
|
||||
* a copy of this software and associated documentation files (the
|
||||
* "Software"), to deal in the Software without restriction, including
|
||||
* without limitation the rights to use, copy, modify, merge, publish,
|
||||
* distribute, sub license, and/or sell copies of the Software, and to
|
||||
* permit persons to whom the Software is furnished to do so, subject to
|
||||
* the following conditions:
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
* NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS, AUTHORS
|
||||
* AND/OR ITS SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* The above copyright notice and this permission notice (including the
|
||||
* next paragraph) shall be included in all copies or substantial portions
|
||||
* of the Software.
|
||||
*
|
||||
* --------------------------------------------------------------------------
|
||||
*
|
||||
* This is a minimal extraction of decaf-emu's R600AddrLib hardcoded for
|
||||
* the Wii-U R700-class GPU (mPipes=2, mBanks=4, group/swap/split sizes).
|
||||
* The R600 class hierarchy is collapsed to free functions; only the surface
|
||||
* address paths needed for GTX texture deswizzling are kept.
|
||||
*/
|
||||
|
||||
#include "AddrLib.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <bit>
|
||||
|
||||
namespace dusk::tphd::addrlib {
|
||||
|
||||
// ---- Wii-U R700 hardware constants ----------------------------------------
|
||||
// Match decaf's R600AddrLib state after DecodeGbRegs for the Wii-U register
|
||||
// configuration: pipes=2, banks=4, group=256B, row=2KB, swap=256B, split=2KB.
|
||||
static constexpr u32 kPipes = 2;
|
||||
static constexpr u32 kBanks = 4;
|
||||
static constexpr u32 kPipeInterleaveBytes = 256;
|
||||
static constexpr u32 kRowSize = 2048;
|
||||
static constexpr u32 kSwapSize = 256;
|
||||
static constexpr u32 kSplitSize = 2048;
|
||||
// Wii-U does not enable the optimal bank-swap heuristic.
|
||||
static constexpr bool kOptimalBankSwap = false;
|
||||
|
||||
// ---- Decaf addrcommon.h constants -----------------------------------------
|
||||
static constexpr u32 kMicroTileWidth = 8;
|
||||
static constexpr u32 kMicroTileHeight = 8;
|
||||
static constexpr u32 kMicroTilePixels = kMicroTileWidth * kMicroTileHeight;
|
||||
static constexpr u32 kThickTileThickness = 4;
|
||||
|
||||
static constexpr u32 BITS_TO_BYTES(u32 v) { return (v + 7) / 8; }
|
||||
static constexpr u32 _BIT(u32 v, u32 b) { return (v >> b) & 1; }
|
||||
|
||||
static u32 Log2(u32 v) {
|
||||
u32 r = 0;
|
||||
while (v > 1) { v >>= 1; ++r; }
|
||||
return r;
|
||||
}
|
||||
|
||||
static constexpr bool IsPow2(u32 v) { return v != 0 && (v & (v - 1)) == 0; }
|
||||
|
||||
|
||||
static constexpr u32 NextPow2(u32 v) {
|
||||
return v <= 1 ? 1u : std::bit_ceil(v);
|
||||
}
|
||||
static constexpr u32 PowTwoAlign(u32 v, u32 align) {
|
||||
return (v + align - 1) & ~(align - 1);
|
||||
}
|
||||
|
||||
// ---- Tile-mode classification ---------------------------------------------
|
||||
|
||||
static u32 ComputeSurfaceThickness(TileMode tm) {
|
||||
switch (tm) {
|
||||
case TileMode::Tiled1DThick:
|
||||
case TileMode::Tiled2DThick:
|
||||
case TileMode::Tiled2BThick:
|
||||
case TileMode::Tiled3DThick:
|
||||
case TileMode::Tiled3BThick:
|
||||
return 4u;
|
||||
default:
|
||||
return 1u;
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsThickMacroTiled(TileMode tm) {
|
||||
switch (tm) {
|
||||
case TileMode::Tiled2DThick:
|
||||
case TileMode::Tiled2BThick:
|
||||
case TileMode::Tiled3DThick:
|
||||
case TileMode::Tiled3BThick:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static bool IsBankSwappedTileMode(TileMode tm) {
|
||||
switch (tm) {
|
||||
case TileMode::Tiled2BThin1:
|
||||
case TileMode::Tiled2BThin2:
|
||||
case TileMode::Tiled2BThin4:
|
||||
case TileMode::Tiled2BThick:
|
||||
case TileMode::Tiled3BThin1:
|
||||
case TileMode::Tiled3BThick:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// AddrTileType: 0=Displayable, 1=NonDisplayable, 2=DepthSampleOrder, 3=Thick.
|
||||
// Wii-U GTX color textures empirically use the Displayable (bpp-switched)
|
||||
// microtile layout, depth surfaces use the simple x/y-interleave pattern
|
||||
// that AMD calls NonDisplayable. (Same convention as Cemu's port.)
|
||||
static u32 GetTileType(bool isDepth) {
|
||||
return isDepth ? 1u /* NonDisplayable */ : 0u /* Displayable */;
|
||||
}
|
||||
|
||||
static u32 ComputeSurfaceRotationFromTileMode(TileMode tm) {
|
||||
switch (tm) {
|
||||
case TileMode::Tiled2DThin1:
|
||||
case TileMode::Tiled2DThin2:
|
||||
case TileMode::Tiled2DThin4:
|
||||
case TileMode::Tiled2DThick:
|
||||
case TileMode::Tiled2BThin1:
|
||||
case TileMode::Tiled2BThin2:
|
||||
case TileMode::Tiled2BThin4:
|
||||
case TileMode::Tiled2BThick:
|
||||
return kPipes * ((kBanks >> 1) - 1);
|
||||
case TileMode::Tiled3DThin1:
|
||||
case TileMode::Tiled3DThick:
|
||||
case TileMode::Tiled3BThin1:
|
||||
case TileMode::Tiled3BThick:
|
||||
return (kPipes >= 4) ? ((kPipes >> 1) - 1) : 1;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static u32 ComputeMacroTileAspectRatio(TileMode tm) {
|
||||
switch (tm) {
|
||||
case TileMode::Tiled2BThin1:
|
||||
case TileMode::Tiled3DThin1:
|
||||
case TileMode::Tiled3BThin1:
|
||||
return 1;
|
||||
case TileMode::Tiled2DThin2:
|
||||
case TileMode::Tiled2BThin2:
|
||||
return 2;
|
||||
case TileMode::Tiled2DThin4:
|
||||
case TileMode::Tiled2BThin4:
|
||||
return 4;
|
||||
default:
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
// ---- Pixel-index-within-microtile -----------------------------------------
|
||||
|
||||
static u32 ComputePixelIndexWithinMicroTile(u32 x, u32 y, u32 z, u32 bpp,
|
||||
TileMode tm, u32 tileType) {
|
||||
u32 b0 = 0, b1 = 0, b2 = 0, b3 = 0, b4 = 0, b5 = 0, b6 = 0, b7 = 0, b8 = 0;
|
||||
const u32 x0 = _BIT(x, 0), x1 = _BIT(x, 1), x2 = _BIT(x, 2);
|
||||
const u32 y0 = _BIT(y, 0), y1 = _BIT(y, 1), y2 = _BIT(y, 2);
|
||||
const u32 z0 = _BIT(z, 0), z1 = _BIT(z, 1), z2 = _BIT(z, 2);
|
||||
const u32 thickness = ComputeSurfaceThickness(tm);
|
||||
|
||||
if (tileType == 3 /* Thick */) {
|
||||
b0 = x0; b1 = y0; b2 = z0; b3 = x1;
|
||||
b4 = y1; b5 = z1; b6 = x2; b7 = y2;
|
||||
} else if (tileType == 1 /* NonDisplayable */) {
|
||||
b0 = x0; b1 = y0; b2 = x1;
|
||||
b3 = y1; b4 = x2; b5 = y2;
|
||||
} else {
|
||||
switch (bpp) {
|
||||
case 8:
|
||||
b0 = x0; b1 = x1; b2 = x2; b3 = y1; b4 = y0; b5 = y2; break;
|
||||
case 16:
|
||||
b0 = x0; b1 = x1; b2 = x2; b3 = y0; b4 = y1; b5 = y2; break;
|
||||
case 64:
|
||||
b0 = x0; b1 = y0; b2 = x1; b3 = x2; b4 = y1; b5 = y2; break;
|
||||
case 128:
|
||||
b0 = y0; b1 = x0; b2 = x1; b3 = x2; b4 = y1; b5 = y2; break;
|
||||
case 32:
|
||||
case 96:
|
||||
default:
|
||||
b0 = x0; b1 = x1; b2 = y0; b3 = x2; b4 = y1; b5 = y2; break;
|
||||
}
|
||||
}
|
||||
if (tileType != 3 && thickness > 1) {
|
||||
b6 = z0; b7 = z1;
|
||||
}
|
||||
if (thickness == 8) {
|
||||
b8 = z2;
|
||||
}
|
||||
return (b0) | (b1 << 1) | (b2 << 2) | (b3 << 3) | (b4 << 4) |
|
||||
(b5 << 5) | (b6 << 6) | (b7 << 7) | (b8 << 8);
|
||||
}
|
||||
|
||||
// ---- Pipe / Bank from coord (no rotation) ---------------------------------
|
||||
// Hardcoded for Wii-U: pipes=2, banks=4.
|
||||
|
||||
static u32 ComputePipeFromCoordWoRotation(u32 x, u32 y) {
|
||||
return (_BIT(y, 3) ^ _BIT(x, 3)) & 1;
|
||||
}
|
||||
|
||||
static u32 ComputeBankFromCoordWoRotation(u32 x, u32 y) {
|
||||
const u32 ty = y / kPipes;
|
||||
const u32 ty4 = _BIT(ty, 4);
|
||||
const u32 ty3 = _BIT(ty, 3);
|
||||
const u32 x3 = _BIT(x, 3);
|
||||
const u32 x4 = _BIT(x, 4);
|
||||
u32 b0 = (ty4 ^ x3);
|
||||
if (kOptimalBankSwap && kPipes == 8) {
|
||||
b0 ^= _BIT(x, 5);
|
||||
}
|
||||
const u32 b1 = (ty3 ^ x4);
|
||||
return b0 | (b1 << 1);
|
||||
}
|
||||
|
||||
// ---- Bank-swapped width ---------------------------------------------------
|
||||
|
||||
static u32 ComputeSurfaceBankSwappedWidth(TileMode tm, u32 bpp, u32 numSamples,
|
||||
u32 pitch) {
|
||||
if (!IsBankSwappedTileMode(tm)) return 0;
|
||||
|
||||
u32 slicesPerTile = 1;
|
||||
const u32 bytesPerSample = 8 * bpp;
|
||||
const u32 samplesPerTile = bytesPerSample ? (kSplitSize / bytesPerSample) : 0;
|
||||
if (samplesPerTile != 0) {
|
||||
slicesPerTile = std::max<u32>(1u, numSamples / samplesPerTile);
|
||||
}
|
||||
if (IsThickMacroTiled(tm)) {
|
||||
numSamples = 4;
|
||||
}
|
||||
const u32 bytesPerTileSlice = numSamples * bytesPerSample / slicesPerTile;
|
||||
const u32 factor = ComputeMacroTileAspectRatio(tm);
|
||||
const u32 swapTiles = std::max<u32>(1u, (kSwapSize >> 1) / bpp);
|
||||
const u32 swapWidth = swapTiles * 8 * kBanks;
|
||||
const u32 heightBytes = numSamples * factor * kPipes * bpp / slicesPerTile;
|
||||
const u32 swapMax = kPipes * kBanks * kRowSize / heightBytes;
|
||||
const u32 swapMin = kPipeInterleaveBytes * 8 * kBanks / bytesPerTileSlice;
|
||||
|
||||
u32 bankSwapWidth = std::min(swapMax, std::max(swapMin, swapWidth));
|
||||
while (bankSwapWidth >= 2 * pitch) {
|
||||
bankSwapWidth >>= 1;
|
||||
}
|
||||
return bankSwapWidth;
|
||||
}
|
||||
|
||||
// ---- Surface-address from coord -------------------------------------------
|
||||
|
||||
static u64 ComputeSurfaceAddrFromCoordMicroTiled(u32 x, u32 y, u32 slice,
|
||||
u32 bpp, u32 pitch, u32 height,
|
||||
TileMode tm, bool isDepth) {
|
||||
const u64 microTileThickness = (tm == TileMode::Tiled1DThick) ? 4u : 1u;
|
||||
const u64 microTileBytes =
|
||||
BITS_TO_BYTES(static_cast<u32>(kMicroTilePixels * microTileThickness * bpp));
|
||||
const u64 microTilesPerRow = pitch / kMicroTileWidth;
|
||||
const u64 microTileIndexX = x / kMicroTileWidth;
|
||||
const u64 microTileIndexY = y / kMicroTileHeight;
|
||||
const u64 microTileIndexZ = slice / microTileThickness;
|
||||
|
||||
const u64 microTileOffset = microTileBytes *
|
||||
(microTileIndexX + microTileIndexY * microTilesPerRow);
|
||||
const u64 sliceBytes =
|
||||
BITS_TO_BYTES(static_cast<u32>(pitch * height * microTileThickness * bpp));
|
||||
const u64 sliceOffset = microTileIndexZ * sliceBytes;
|
||||
const u64 pixelIndex =
|
||||
ComputePixelIndexWithinMicroTile(x, y, slice, bpp, tm, GetTileType(isDepth));
|
||||
const u64 pixelOffset = (bpp * pixelIndex) / 8;
|
||||
|
||||
return pixelOffset + microTileOffset + sliceOffset;
|
||||
}
|
||||
|
||||
static u64 ComputeSurfaceAddrFromCoordMacroTiled(u32 x, u32 y, u32 slice, u32 sample,
|
||||
u32 bpp, u32 pitch, u32 height,
|
||||
u32 numSamples, TileMode tm,
|
||||
bool isDepth, u32 pipeSwizzle,
|
||||
u32 bankSwizzle) {
|
||||
const u64 numPipes = kPipes;
|
||||
const u64 numBanks = kBanks;
|
||||
const u64 numGroupBits = Log2(kPipeInterleaveBytes);
|
||||
const u64 numPipeBits = Log2(kPipes);
|
||||
const u64 numBankBits = Log2(kBanks);
|
||||
|
||||
const u64 microTileThickness = ComputeSurfaceThickness(tm);
|
||||
const u64 microTileBits = kMicroTilePixels * microTileThickness * bpp * numSamples;
|
||||
const u64 microTileBytes = microTileBits / 8;
|
||||
|
||||
const u64 pixelIndex =
|
||||
ComputePixelIndexWithinMicroTile(x, y, slice, bpp, tm, GetTileType(isDepth));
|
||||
|
||||
u64 sampleOffset, pixelOffset;
|
||||
if (isDepth) {
|
||||
sampleOffset = bpp * sample;
|
||||
pixelOffset = numSamples * bpp * pixelIndex;
|
||||
} else {
|
||||
sampleOffset = sample * (microTileBits / numSamples);
|
||||
pixelOffset = bpp * pixelIndex;
|
||||
}
|
||||
u64 elemOffset = pixelOffset + sampleOffset;
|
||||
|
||||
const u64 bytesPerSample = microTileBytes / numSamples;
|
||||
u64 sampleSlice = 0;
|
||||
u64 numSampleSplits = 1;
|
||||
if (numSamples > 1 && microTileBytes > kSplitSize) {
|
||||
const u64 samplesPerSlice = kSplitSize / bytesPerSample;
|
||||
numSampleSplits = numSamples / samplesPerSlice;
|
||||
numSamples = static_cast<u32>(samplesPerSlice);
|
||||
const u64 tileSliceBits = microTileBits / numSampleSplits;
|
||||
sampleSlice = elemOffset / tileSliceBits;
|
||||
elemOffset %= tileSliceBits;
|
||||
}
|
||||
elemOffset /= 8;
|
||||
|
||||
u64 pipe = ComputePipeFromCoordWoRotation(x, y);
|
||||
u64 bank = ComputeBankFromCoordWoRotation(x, y);
|
||||
u64 bankPipe = pipe + numPipes * bank;
|
||||
const u64 rotation = ComputeSurfaceRotationFromTileMode(tm);
|
||||
const u64 swizzle = pipeSwizzle + numPipes * bankSwizzle;
|
||||
u64 sliceIn = slice;
|
||||
if (IsThickMacroTiled(tm)) {
|
||||
sliceIn /= kThickTileThickness;
|
||||
}
|
||||
bankPipe ^= numPipes * sampleSlice * ((numBanks >> 1) + 1) ^ (swizzle + sliceIn * rotation);
|
||||
bankPipe %= numPipes * numBanks;
|
||||
pipe = bankPipe % numPipes;
|
||||
bank = bankPipe / numPipes;
|
||||
|
||||
const u64 sliceBytes =
|
||||
BITS_TO_BYTES(static_cast<u32>(pitch * height * microTileThickness * bpp * numSamples));
|
||||
const u64 sliceOffset = sliceBytes *
|
||||
((sampleSlice + numSampleSplits * slice) / microTileThickness);
|
||||
|
||||
u64 macroTilePitch = 8 * numBanks;
|
||||
u64 macroTileHeight = 8 * numPipes;
|
||||
switch (tm) {
|
||||
case TileMode::Tiled2DThin2:
|
||||
case TileMode::Tiled2BThin2:
|
||||
macroTilePitch /= 2;
|
||||
macroTileHeight *= 2;
|
||||
break;
|
||||
case TileMode::Tiled2DThin4:
|
||||
case TileMode::Tiled2BThin4:
|
||||
macroTilePitch /= 4;
|
||||
macroTileHeight *= 4;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
const u64 macroTilesPerRow = pitch / macroTilePitch;
|
||||
const u64 macroTileBytes =
|
||||
BITS_TO_BYTES(static_cast<u32>(numSamples * microTileThickness * bpp *
|
||||
macroTileHeight * macroTilePitch));
|
||||
const u64 macroTileIndexX = x / macroTilePitch;
|
||||
const u64 macroTileIndexY = y / macroTileHeight;
|
||||
const u64 macroTileOffset = macroTileBytes *
|
||||
(macroTileIndexX + macroTilesPerRow * macroTileIndexY);
|
||||
|
||||
if (IsBankSwappedTileMode(tm)) {
|
||||
static constexpr u32 bankSwapOrder[] = { 0, 1, 3, 2, 6, 7, 5, 4, 0, 0 };
|
||||
const u32 bankSwapWidth =
|
||||
ComputeSurfaceBankSwappedWidth(tm, bpp, numSamples, pitch);
|
||||
const u64 swapIndex = (bankSwapWidth != 0)
|
||||
? (macroTilePitch * macroTileIndexX / bankSwapWidth) : 0;
|
||||
bank ^= bankSwapOrder[swapIndex & (kBanks - 1)];
|
||||
}
|
||||
|
||||
const u64 groupMask = (1u << numGroupBits) - 1;
|
||||
const u64 totalOffset = elemOffset +
|
||||
((macroTileOffset + sliceOffset) >> (numBankBits + numPipeBits));
|
||||
const u64 offsetHigh = (totalOffset & ~groupMask) << (numBankBits + numPipeBits);
|
||||
const u64 offsetLow = totalOffset & groupMask;
|
||||
const u64 bankBits = bank << (numPipeBits + numGroupBits);
|
||||
const u64 pipeBits = pipe << numGroupBits;
|
||||
return bankBits | pipeBits | offsetLow | offsetHigh;
|
||||
}
|
||||
|
||||
// ---- High-level deswizzle -------------------------------------------------
|
||||
|
||||
std::vector<u8> deswizzle(const SurfaceDesc& desc, std::span<const u8> tiledBytes) {
|
||||
// For BCN formats addrlib operates on block coordinates; bpp is bits per
|
||||
// 4x4 block (e.g. 64 for BC1). Reduce width/height to block extents.
|
||||
const u32 blockWidth = desc.isBcn ? (desc.width + 3) / 4 : desc.width;
|
||||
const u32 blockHeight = desc.isBcn ? (desc.height + 3) / 4 : desc.height;
|
||||
|
||||
const u32 bytesPerElement = desc.bpp / 8;
|
||||
const u32 linearStride = blockWidth * bytesPerElement;
|
||||
std::vector<u8> linear(static_cast<size_t>(linearStride) * blockHeight, 0);
|
||||
|
||||
const u32 pipeSwizzle = (desc.swizzle >> 8) & 1;
|
||||
const u32 bankSwizzle = (desc.swizzle >> 9) & 3;
|
||||
|
||||
// Linear tile modes: trivial copy honoring pitch.
|
||||
if (desc.tileMode == TileMode::LinearGeneral ||
|
||||
desc.tileMode == TileMode::LinearAligned) {
|
||||
for (u32 y = 0; y < blockHeight; ++y) {
|
||||
const u32 srcOff = y * desc.pitch * bytesPerElement;
|
||||
if (srcOff + linearStride > tiledBytes.size()) break;
|
||||
std::memcpy(linear.data() + y * linearStride,
|
||||
tiledBytes.data() + srcOff, linearStride);
|
||||
}
|
||||
return linear;
|
||||
}
|
||||
|
||||
const bool microTiled =
|
||||
(desc.tileMode == TileMode::Tiled1DThin1 ||
|
||||
desc.tileMode == TileMode::Tiled1DThick);
|
||||
|
||||
for (u32 y = 0; y < blockHeight; ++y) {
|
||||
for (u32 x = 0; x < blockWidth; ++x) {
|
||||
u64 srcOff;
|
||||
if (microTiled) {
|
||||
srcOff = ComputeSurfaceAddrFromCoordMicroTiled(
|
||||
x, y, /*slice*/ 0, desc.bpp, desc.pitch, blockHeight,
|
||||
desc.tileMode, desc.isDepth);
|
||||
} else {
|
||||
srcOff = ComputeSurfaceAddrFromCoordMacroTiled(
|
||||
x, y, /*slice*/ 0, /*sample*/ 0, desc.bpp, desc.pitch,
|
||||
blockHeight, /*numSamples*/ 1, desc.tileMode, desc.isDepth,
|
||||
pipeSwizzle, bankSwizzle);
|
||||
}
|
||||
if (srcOff + bytesPerElement > tiledBytes.size()) continue;
|
||||
const u32 dstOff = (y * blockWidth + x) * bytesPerElement;
|
||||
std::memcpy(linear.data() + dstOff,
|
||||
tiledBytes.data() + srcOff, bytesPerElement);
|
||||
}
|
||||
}
|
||||
return linear;
|
||||
}
|
||||
|
||||
// R600AddrLib::ConvertToNonBankSwappedMode (r600addrlib.cpp:355)
|
||||
static TileMode ConvertToNonBankSwappedMode(TileMode tm) {
|
||||
switch (tm) {
|
||||
case TileMode::Tiled2BThin1: return TileMode::Tiled2DThin1;
|
||||
case TileMode::Tiled2BThin2: return TileMode::Tiled2DThin2;
|
||||
case TileMode::Tiled2BThin4: return TileMode::Tiled2DThin4;
|
||||
case TileMode::Tiled2BThick: return TileMode::Tiled2DThick;
|
||||
case TileMode::Tiled3BThin1: return TileMode::Tiled3DThin1;
|
||||
case TileMode::Tiled3BThick: return TileMode::Tiled3DThick;
|
||||
default: return tm;
|
||||
}
|
||||
}
|
||||
|
||||
// R600AddrLib::ComputeSurfaceMipLevelTileMode (r600addrlib.cpp:544).
|
||||
static TileMode ComputeSurfaceMipLevelTileMode(TileMode baseTileMode,
|
||||
u32 bpp,
|
||||
u32 level,
|
||||
u32 width,
|
||||
u32 height,
|
||||
u32 numSamples,
|
||||
bool noRecursive) {
|
||||
// ComputeSurfaceTileSlices == 1 for our case (numSamples=1, thin).
|
||||
// HwlDegradeThickTileMode is identity for thin tiles.
|
||||
TileMode tileMode = baseTileMode;
|
||||
|
||||
const u32 rotation = ComputeSurfaceRotationFromTileMode(tileMode);
|
||||
if ((rotation % kPipes) == 0) {
|
||||
switch (tileMode) {
|
||||
case TileMode::Tiled3DThin1: tileMode = TileMode::Tiled2DThin1; break;
|
||||
case TileMode::Tiled3DThick: tileMode = TileMode::Tiled2DThick; break;
|
||||
case TileMode::Tiled3BThin1: tileMode = TileMode::Tiled2BThin1; break;
|
||||
case TileMode::Tiled3BThick: tileMode = TileMode::Tiled2BThick; break;
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
if (noRecursive || level == 0) {
|
||||
return tileMode;
|
||||
}
|
||||
|
||||
if (bpp == 96 || bpp == 48 || bpp == 24) bpp /= 3;
|
||||
|
||||
width = NextPow2(width);
|
||||
height = NextPow2(height);
|
||||
|
||||
tileMode = ConvertToNonBankSwappedMode(tileMode);
|
||||
|
||||
const u32 thickness = ComputeSurfaceThickness(tileMode);
|
||||
const u32 microTileBytes = BITS_TO_BYTES(thickness * bpp * 64);
|
||||
const u32 widthAlignFactor = (microTileBytes <= kPipeInterleaveBytes)
|
||||
? (kPipeInterleaveBytes / microTileBytes) : 1u;
|
||||
|
||||
u32 macroTileWidth = 8 * kBanks;
|
||||
u32 macroTileHeight = 8 * kPipes;
|
||||
|
||||
switch (tileMode) {
|
||||
case TileMode::Tiled2DThin1:
|
||||
case TileMode::Tiled3DThin1:
|
||||
if (width < widthAlignFactor * macroTileWidth || height < macroTileHeight) {
|
||||
tileMode = TileMode::Tiled1DThin1;
|
||||
}
|
||||
break;
|
||||
case TileMode::Tiled2DThin2:
|
||||
macroTileWidth >>= 1; macroTileHeight *= 2;
|
||||
if (width < widthAlignFactor * macroTileWidth || height < macroTileHeight) {
|
||||
tileMode = TileMode::Tiled1DThin1;
|
||||
}
|
||||
break;
|
||||
case TileMode::Tiled2DThin4:
|
||||
macroTileWidth >>= 2; macroTileHeight *= 4;
|
||||
if (width < widthAlignFactor * macroTileWidth || height < macroTileHeight) {
|
||||
tileMode = TileMode::Tiled1DThin1;
|
||||
}
|
||||
break;
|
||||
case TileMode::Tiled2DThick:
|
||||
case TileMode::Tiled3DThick:
|
||||
if (width < widthAlignFactor * macroTileWidth || height < macroTileHeight) {
|
||||
tileMode = TileMode::Tiled1DThick;
|
||||
}
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
// numSlices < 4 collapse — our textures are all 2D (slices=1), so the
|
||||
// Thick→Thin demote always fires when we hit a thick mode.
|
||||
if (tileMode == TileMode::Tiled1DThick) tileMode = TileMode::Tiled1DThin1;
|
||||
else if (tileMode == TileMode::Tiled2DThick) tileMode = TileMode::Tiled2DThin1;
|
||||
else if (tileMode == TileMode::Tiled3DThick) tileMode = TileMode::Tiled3DThin1;
|
||||
|
||||
return ComputeSurfaceMipLevelTileMode(tileMode, bpp, level, width, height,
|
||||
numSamples, /*noRecursive*/ true);
|
||||
}
|
||||
|
||||
// R600AddrLib::ComputeSurfaceAlignmentsMicrotiled (r600addrlib.cpp:714).
|
||||
static void ComputeAlignmentsMicroTiled(TileMode tileMode, u32 bpp, u32 numSamples,
|
||||
u32& pitchAlign, u32& heightAlign) {
|
||||
if (bpp == 96 || bpp == 48 || bpp == 24) bpp /= 3;
|
||||
const u32 thickness = ComputeSurfaceThickness(tileMode);
|
||||
const u32 pitchAlignment = kPipeInterleaveBytes / bpp / numSamples / thickness;
|
||||
pitchAlign = std::max<u32>(8u, pitchAlignment);
|
||||
heightAlign = 8;
|
||||
// AdjustPitchAlignment is no-op without flags.display.
|
||||
}
|
||||
|
||||
// R600AddrLib::ComputeSurfaceAlignmentsMacrotiled (r600addrlib.cpp:805).
|
||||
static void ComputeAlignmentsMacroTiled(TileMode tileMode, u32 bpp, u32 numSamples,
|
||||
u32& pitchAlign, u32& heightAlign,
|
||||
u32& macroTileWidth, u32& macroTileHeight) {
|
||||
const u32 aspectRatio = (tileMode == TileMode::Tiled2DThin2 ||
|
||||
tileMode == TileMode::Tiled2BThin2) ? 2u
|
||||
: (tileMode == TileMode::Tiled2DThin4 ||
|
||||
tileMode == TileMode::Tiled2BThin4) ? 4u : 1u;
|
||||
const u32 thickness = ComputeSurfaceThickness(tileMode);
|
||||
if (bpp == 96 || bpp == 48 || bpp == 24) bpp /= 3;
|
||||
if (bpp == 3) bpp = 1;
|
||||
|
||||
macroTileWidth = 8 * kBanks / aspectRatio;
|
||||
macroTileHeight = aspectRatio * 8 * kPipes;
|
||||
pitchAlign = std::max<u32>(macroTileWidth,
|
||||
macroTileWidth * (kPipeInterleaveBytes / bpp / (8 * thickness) / numSamples));
|
||||
heightAlign = macroTileHeight;
|
||||
// IsDualBaseAlignNeeded is R6XX-only -> false here; baseAlign branch skipped.
|
||||
}
|
||||
|
||||
// AddrLib::PadDimensions (addrlib.cpp:433), simplified: no cube, no slice padding.
|
||||
static void PadDimensions(TileMode /*tm*/, u32& pitch, u32 pitchAlign,
|
||||
u32& height, u32 heightAlign, u32 padDims) {
|
||||
if (padDims == 0) padDims = 3;
|
||||
if (IsPow2(pitchAlign)) {
|
||||
pitch = PowTwoAlign(pitch, pitchAlign);
|
||||
} else {
|
||||
pitch = ((pitch + pitchAlign - 1) / pitchAlign) * pitchAlign;
|
||||
}
|
||||
if (padDims > 1) {
|
||||
height = PowTwoAlign(height, heightAlign);
|
||||
}
|
||||
}
|
||||
|
||||
// R600AddrLib::ComputeSurfaceInfoMicroTiled (r600addrlib.cpp:969).
|
||||
static void ComputeSurfaceInfoMicroTiled(u32 width, u32 height, u32 numSamples, u32 bpp,
|
||||
TileMode tileMode, u32 mipLevel, SurfaceInfoOut& out) {
|
||||
u32 pitch = width;
|
||||
u32 h = height;
|
||||
if (mipLevel) {
|
||||
pitch = NextPow2(pitch);
|
||||
h = NextPow2(h);
|
||||
// numSlices < 4 / thick collapse: no thick at this point for our flow.
|
||||
}
|
||||
u32 pitchAlign = 0, heightAlign = 0;
|
||||
ComputeAlignmentsMicroTiled(tileMode, bpp, numSamples, pitchAlign, heightAlign);
|
||||
PadDimensions(tileMode, pitch, pitchAlign, h, heightAlign, /*padDims*/ 0);
|
||||
out.pitch = pitch;
|
||||
out.height = height;
|
||||
out.heightAligned = h;
|
||||
out.tileMode = tileMode;
|
||||
}
|
||||
|
||||
// R600AddrLib::ComputeSurfaceInfoMacroTiled (r600addrlib.cpp:1198).
|
||||
static void ComputeSurfaceInfoMacroTiled(u32 width, u32 height, u32 numSamples, u32 bpp,
|
||||
TileMode tileMode, TileMode baseTileMode,
|
||||
u32 mipLevel, SurfaceInfoOut& out) {
|
||||
u32 pitch = width;
|
||||
u32 h = height;
|
||||
if (mipLevel) {
|
||||
pitch = NextPow2(pitch);
|
||||
h = NextPow2(h);
|
||||
}
|
||||
u32 pitchAlignBase = 0, heightAlignBase = 0, mwBase = 0, mhBase = 0;
|
||||
if (tileMode != baseTileMode && mipLevel != 0 &&
|
||||
IsThickMacroTiled(baseTileMode) && !IsThickMacroTiled(tileMode)) {
|
||||
ComputeAlignmentsMacroTiled(baseTileMode, bpp, numSamples,
|
||||
pitchAlignBase, heightAlignBase, mwBase, mhBase);
|
||||
const u32 pitchAlignFactor = std::max<u32>(1u, (kPipeInterleaveBytes >> 3) / bpp);
|
||||
if (pitch < (pitchAlignBase * pitchAlignFactor) || h < heightAlignBase) {
|
||||
ComputeSurfaceInfoMicroTiled(width, height, numSamples, bpp,
|
||||
TileMode::Tiled1DThin1, mipLevel, out);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
u32 pitchAlign = 0, heightAlign = 0, macroWidth = 0, macroHeight = 0;
|
||||
ComputeAlignmentsMacroTiled(tileMode, bpp, numSamples,
|
||||
pitchAlign, heightAlign, macroWidth, macroHeight);
|
||||
const u32 bankSwappedWidth = ComputeSurfaceBankSwappedWidth(tileMode, bpp, numSamples, pitch);
|
||||
pitchAlign = std::max(pitchAlign, bankSwappedWidth);
|
||||
// IsDualPitchAlignNeeded is R6XX-only -> false here.
|
||||
PadDimensions(tileMode, pitch, pitchAlign, h, heightAlign, /*padDims*/ 0);
|
||||
out.pitch = pitch;
|
||||
out.height = height;
|
||||
out.heightAligned = h;
|
||||
out.tileMode = tileMode;
|
||||
}
|
||||
|
||||
void computeSurfaceInfo(const SurfaceInfoIn& in, SurfaceInfoOut& out) {
|
||||
// AddrLib::ComputeMipLevel + R600AddrLib::HwlComputeMipLevel: align BCN
|
||||
// base dims to 4 pixels; for mipLevel>0, reduce dims and NextPow2 them.
|
||||
u32 width = in.width;
|
||||
u32 height = in.height;
|
||||
if (in.isBcn && in.mipLevel == 0) {
|
||||
width = PowTwoAlign(width, 4u);
|
||||
height = PowTwoAlign(height, 4u);
|
||||
}
|
||||
if (in.mipLevel > 0) {
|
||||
width = std::max(1u, width >> in.mipLevel);
|
||||
height = std::max(1u, height >> in.mipLevel);
|
||||
width = NextPow2(width);
|
||||
height = NextPow2(height);
|
||||
}
|
||||
|
||||
if (in.isBcn) {
|
||||
width = (width + 3) / 4;
|
||||
height = (height + 3) / 4;
|
||||
}
|
||||
|
||||
const u32 numSamples = 1;
|
||||
const TileMode demoted = ComputeSurfaceMipLevelTileMode(in.tileMode, in.bpp,
|
||||
in.mipLevel, width, height,
|
||||
numSamples, /*noRecursive*/ false);
|
||||
out.width = width;
|
||||
out.height = height;
|
||||
out.tileMode = demoted;
|
||||
|
||||
switch (demoted) {
|
||||
case TileMode::LinearGeneral:
|
||||
case TileMode::LinearAligned: {
|
||||
// ComputeSurfaceInfoLinear
|
||||
const u32 pa = std::max<u32>(64u, kPipeInterleaveBytes / in.bpp / numSamples);
|
||||
u32 pitch = width, h = height;
|
||||
if (in.mipLevel) { pitch = NextPow2(pitch); h = NextPow2(h); }
|
||||
PadDimensions(demoted, pitch, pa, h, 1u, /*padDims*/ 0);
|
||||
out.pitch = pitch; out.heightAligned = h;
|
||||
break;
|
||||
}
|
||||
case TileMode::Tiled1DThin1:
|
||||
case TileMode::Tiled1DThick:
|
||||
ComputeSurfaceInfoMicroTiled(width, height, numSamples, in.bpp,
|
||||
demoted, in.mipLevel, out);
|
||||
break;
|
||||
default:
|
||||
ComputeSurfaceInfoMacroTiled(width, height, numSamples, in.bpp,
|
||||
demoted, in.tileMode, in.mipLevel, out);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace dusk::tphd::addrlib
|
||||
@@ -0,0 +1,78 @@
|
||||
// Ported from decaf-emu/addrlib (https://github.com/decaf-emu/addrlib),
|
||||
// which is itself derived from AMD's address library.
|
||||
// Copyright (c) 2014 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
// Licensed under the AMD MIT-style license; see the AMD copyright header in
|
||||
// AddrLib.cpp.
|
||||
//
|
||||
// Minimal R600/R700 surface-address port sufficient for deswizzling Wii-U
|
||||
// GTX textures at load time. Hardcoded for Wii-U HW configuration:
|
||||
// pipes = 2, banks = 4, pipe interleave = 256B,
|
||||
// row size = 2KB, sample split = 2KB, swap size = 256B.
|
||||
|
||||
#ifndef DUSK_TPHD_ADDRLIB_HPP
|
||||
#define DUSK_TPHD_ADDRLIB_HPP
|
||||
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
#include <dolphin/types.h>
|
||||
|
||||
namespace dusk::tphd::addrlib {
|
||||
|
||||
enum class TileMode : u32 {
|
||||
LinearGeneral = 0,
|
||||
LinearAligned = 1,
|
||||
Tiled1DThin1 = 2,
|
||||
Tiled1DThick = 3,
|
||||
Tiled2DThin1 = 4,
|
||||
Tiled2DThin2 = 5,
|
||||
Tiled2DThin4 = 6,
|
||||
Tiled2DThick = 7,
|
||||
Tiled2BThin1 = 8,
|
||||
Tiled2BThin2 = 9,
|
||||
Tiled2BThin4 = 10,
|
||||
Tiled2BThick = 11,
|
||||
Tiled3DThin1 = 12,
|
||||
Tiled3DThick = 13,
|
||||
Tiled3BThin1 = 14,
|
||||
Tiled3BThick = 15,
|
||||
};
|
||||
|
||||
struct SurfaceDesc {
|
||||
u32 width; // pixels (or BCN blocks)
|
||||
u32 height; // pixels (or BCN blocks)
|
||||
u32 pitch; // pixels (or BCN blocks)
|
||||
u32 bpp; // bits per pixel (or per 4x4 BCN block, e.g. 64 for BC1)
|
||||
TileMode tileMode;
|
||||
u32 swizzle; // GTX swizzle field; pipe = (>>8)&1, bank = (>>9)&3
|
||||
bool isBcn;
|
||||
bool isDepth;
|
||||
};
|
||||
|
||||
// Deswizzle a single surface mip level into a row-major linear buffer.
|
||||
std::vector<u8> deswizzle(const SurfaceDesc& desc, std::span<const u8> tiledBytes);
|
||||
|
||||
struct SurfaceInfoIn {
|
||||
u32 width; // pixels at mip 0 (caller supplies surface base dims)
|
||||
u32 height; // pixels at mip 0
|
||||
u32 bpp; // bits per pixel (e.g. 32 for RGBA8). For BCN, bits per
|
||||
// 4x4 block (64 for BC1, 128 for BC3/5).
|
||||
u32 mipLevel; // 0 = base, 1..N = mip
|
||||
TileMode tileMode;
|
||||
bool isBcn;
|
||||
};
|
||||
|
||||
struct SurfaceInfoOut {
|
||||
u32 width; // possibly NextPow2'd / block-converted dim used for
|
||||
// the address computation (BCN blocks if isBcn)
|
||||
u32 height; // similar
|
||||
u32 pitch; // aligned pitch used by deswizzle (block units if BCN)
|
||||
u32 heightAligned;
|
||||
TileMode tileMode; // possibly demoted (2D→1D for small mips)
|
||||
};
|
||||
|
||||
void computeSurfaceInfo(const SurfaceInfoIn& in, SurfaceInfoOut& out);
|
||||
|
||||
} // namespace dusk::tphd::addrlib
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,89 @@
|
||||
#include "GtxParser.hpp"
|
||||
|
||||
#include <cstring>
|
||||
|
||||
#include "dusk/endian.h"
|
||||
|
||||
namespace dusk::tphd {
|
||||
|
||||
namespace {
|
||||
|
||||
constexpr u32 kBlockTypeEOF = 0x01;
|
||||
constexpr u32 kBlockTypeSurface = 0x0B;
|
||||
constexpr u32 kBlockTypeImage = 0x0C;
|
||||
constexpr u32 kBlockTypeMipChain = 0x0D;
|
||||
|
||||
}
|
||||
|
||||
std::vector<GtxSurface> parseGtx(std::span<const u8> gtx) {
|
||||
std::vector<GtxSurface> out;
|
||||
|
||||
if (gtx.size() < sizeof(Gfx2Header) ||
|
||||
std::memcmp(gtx.data(), "Gfx2", 4) != 0) {
|
||||
return out;
|
||||
}
|
||||
const auto* fileHdr = reinterpret_cast<const Gfx2Header*>(gtx.data());
|
||||
const u32 headerSize = fileHdr->headerSize;
|
||||
if (headerSize > gtx.size()) {
|
||||
return out;
|
||||
}
|
||||
|
||||
GtxSurface* current = nullptr;
|
||||
size_t off = headerSize;
|
||||
|
||||
while (off + sizeof(Gfx2BlockHeader) <= gtx.size()) {
|
||||
const auto* blk = reinterpret_cast<const Gfx2BlockHeader*>(gtx.data() + off);
|
||||
if (std::memcmp(blk->magic, "BLK{", 4) != 0) {
|
||||
break;
|
||||
}
|
||||
const u32 blockHdrSize = blk->headerSize;
|
||||
const u32 blockType = blk->blockType;
|
||||
const u32 blockDataSz = blk->blockDataSize;
|
||||
|
||||
if (blockHdrSize < sizeof(Gfx2BlockHeader) ||
|
||||
off + blockHdrSize + blockDataSz > gtx.size()) {
|
||||
break;
|
||||
}
|
||||
const u8* body = gtx.data() + off + blockHdrSize;
|
||||
|
||||
switch (blockType) {
|
||||
case kBlockTypeSurface: {
|
||||
if (blockDataSz < sizeof(Gx2SurfaceBody)) break;
|
||||
const auto* sb = reinterpret_cast<const Gx2SurfaceBody*>(body);
|
||||
GtxSurface s{};
|
||||
s.format = sb->format;
|
||||
s.width = sb->width;
|
||||
s.height = sb->height;
|
||||
s.depth = sb->depth;
|
||||
s.mipCount = sb->mipCount;
|
||||
s.aa = sb->aa;
|
||||
s.use = sb->use;
|
||||
s.imgSize = sb->imgSize;
|
||||
s.mipSize = sb->mipSize;
|
||||
s.tileMode = sb->tileMode;
|
||||
s.swizzle = sb->swizzle;
|
||||
s.pitch = sb->pitch;
|
||||
for (u32 i = 0; i < 13; ++i) {
|
||||
s.mipOffsets[i] = sb->mipOffsets[i];
|
||||
}
|
||||
out.push_back(s);
|
||||
current = &out.back();
|
||||
break;
|
||||
}
|
||||
case kBlockTypeImage:
|
||||
if (current) current->baseData = gtx.subspan(off + blockHdrSize, blockDataSz);
|
||||
break;
|
||||
case kBlockTypeMipChain:
|
||||
if (current) current->mipData = gtx.subspan(off + blockHdrSize, blockDataSz);
|
||||
break;
|
||||
case kBlockTypeEOF:
|
||||
return out;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
off += blockHdrSize + blockDataSz;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
#ifndef DUSK_TPHD_GTX_PARSER_HPP
|
||||
#define DUSK_TPHD_GTX_PARSER_HPP
|
||||
|
||||
#include <array>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <vector>
|
||||
|
||||
#include <dolphin/types.h>
|
||||
|
||||
#include "dusk/endian.h"
|
||||
|
||||
namespace dusk::tphd {
|
||||
|
||||
// On-disk GX2 file header. Followed by a stream of BLK{ blocks.
|
||||
struct Gfx2Header {
|
||||
/* 0x00 */ char magic[4]; // "Gfx2"
|
||||
/* 0x04 */ BE(u32) headerSize;
|
||||
};
|
||||
|
||||
// Common 0x20-byte header on every BLK{ block.
|
||||
struct Gfx2BlockHeader {
|
||||
/* 0x00 */ char magic[4]; // "BLK{"
|
||||
/* 0x04 */ BE(u32) headerSize;
|
||||
/* 0x08 */ BE(u32) versionMajor;
|
||||
/* 0x0C */ BE(u32) versionMinor;
|
||||
/* 0x10 */ BE(u32) blockType;
|
||||
/* 0x14 */ BE(u32) blockDataSize;
|
||||
/* 0x18 */ BE(u32) ident;
|
||||
/* 0x1C */ BE(u32) flags;
|
||||
};
|
||||
static_assert(sizeof(Gfx2BlockHeader) == 0x20);
|
||||
|
||||
// On-disk surface-info block body (the GX2 surface descriptor layout).
|
||||
struct Gx2SurfaceBody {
|
||||
/* 0x00 */ BE(u32) dim;
|
||||
/* 0x04 */ BE(u32) width;
|
||||
/* 0x08 */ BE(u32) height;
|
||||
/* 0x0C */ BE(u32) depth;
|
||||
/* 0x10 */ BE(u32) mipCount;
|
||||
/* 0x14 */ BE(u32) format;
|
||||
/* 0x18 */ BE(u32) aa;
|
||||
/* 0x1C */ BE(u32) use;
|
||||
/* 0x20 */ BE(u32) imgSize;
|
||||
/* 0x24 */ BE(u32) imgPtr;
|
||||
/* 0x28 */ BE(u32) mipSize;
|
||||
/* 0x2C */ BE(u32) mipPtr;
|
||||
/* 0x30 */ BE(u32) tileMode;
|
||||
/* 0x34 */ BE(u32) swizzle;
|
||||
/* 0x38 */ BE(u32) alignment;
|
||||
/* 0x3C */ BE(u32) pitch;
|
||||
/* 0x40 */ BE(u32) mipOffsets[13];
|
||||
};
|
||||
static_assert(sizeof(Gx2SurfaceBody) == 0x74);
|
||||
|
||||
struct GtxSurface {
|
||||
u32 width;
|
||||
u32 height;
|
||||
u32 depth;
|
||||
u32 mipCount;
|
||||
u32 format; // GX2 surface format code (0x31 BC1, 0x1A RGBA8, ...)
|
||||
u32 aa;
|
||||
u32 use;
|
||||
u32 tileMode;
|
||||
u32 swizzle;
|
||||
u32 pitch;
|
||||
u32 imgSize; // base level size (bytes)
|
||||
u32 mipSize; // mip chain size (bytes, levels 1..N-1)
|
||||
std::array<u32, 13> mipOffsets;
|
||||
|
||||
std::span<const u8> baseData; // into the owning GTX buffer
|
||||
std::span<const u8> mipData; // into the owning GTX buffer
|
||||
};
|
||||
|
||||
std::vector<GtxSurface> parseGtx(std::span<const u8> gtxBytes);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,39 @@
|
||||
#ifndef DUSK_TPHD_HD_ASSET_LAYER_HPP
|
||||
#define DUSK_TPHD_HD_ASSET_LAYER_HPP
|
||||
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <dolphin/types.h>
|
||||
|
||||
namespace dusk::tphd {
|
||||
|
||||
// Configure the base directory for HD asset overrides. `contentPath` should
|
||||
// point at a Wii-U `content/` directory (the parent of `res/`). Empty path
|
||||
// disables HD overrides.
|
||||
void set_hd_content_path(std::filesystem::path contentPath);
|
||||
|
||||
// Returns a pointer to cached HD archive bytes for packed sub-archives that
|
||||
// are mounted from an already-loaded RARC rather than through the DVD layer.
|
||||
// Caller must not outlive the next setHdContentPath() call.
|
||||
std::optional<std::vector<u8>*> try_load_hd_archive(std::string_view gcPath);
|
||||
|
||||
// Called after JKRMemArchive has loaded an overlaid DVD archive into its final
|
||||
// heap address so HD texture replacements can be registered against the
|
||||
// pointers the game will actually use.
|
||||
void register_mounted_hd_archive(s32 entryNum, void* arcBytes, size_t arcSize);
|
||||
|
||||
// Called after JKRArchive copies a resource (BTI item icon, BMD/BDL item
|
||||
// model, etc.) into caller-owned memory. pp
|
||||
void register_copied_hd_resource(s32 entryNum, std::string_view resourceName, void* buffer,
|
||||
size_t resourceSize);
|
||||
|
||||
// Returns bytes remaining in a registered HD archive range that contains ptr.
|
||||
// Used for debug heap accounting because some HD buffers are not JKR-owned.
|
||||
std::optional<size_t> find_registered_hd_archive_remaining(const void* ptr);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,135 @@
|
||||
#include "LosTable.hpp"
|
||||
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#include "aurora/lib/logging.hpp"
|
||||
#include "d/actor/d_a_player.h"
|
||||
#include "dusk/endian.h"
|
||||
|
||||
static aurora::Module LosLog("dusk::tphd::los");
|
||||
|
||||
namespace dusk::tphd {
|
||||
|
||||
namespace {
|
||||
|
||||
struct LosHeader {
|
||||
/* 0x00 */ BE(u32) count;
|
||||
/* 0x04 */ BE(u32) unk04;
|
||||
/* 0x08 */ BE(u32) unk08;
|
||||
};
|
||||
|
||||
struct LosEntry {
|
||||
/* 0x00 */ BE(u32) roomNo;
|
||||
/* 0x04 */ BE(u32) id1;
|
||||
/* 0x08 */ BE(u32) id2;
|
||||
/* 0x0C */ BE(u32) id3;
|
||||
/* 0x10 */ BE(f32) x;
|
||||
/* 0x14 */ BE(f32) y;
|
||||
/* 0x18 */ BE(f32) z;
|
||||
/* 0x1C */ BE(s16) unk1C;
|
||||
/* 0x1E */ BE(s16) angleY;
|
||||
};
|
||||
|
||||
static_assert(sizeof(LosHeader) == 0x0C);
|
||||
static_assert(sizeof(LosEntry) == 0x20);
|
||||
|
||||
std::vector<u8> g_data;
|
||||
u32 g_count = 0;
|
||||
|
||||
const LosEntry* entries() {
|
||||
return reinterpret_cast<const LosEntry*>(g_data.data() + sizeof(LosHeader));
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void load_los_table(const std::filesystem::path& contentPath) {
|
||||
g_data.clear();
|
||||
g_count = 0;
|
||||
if (contentPath.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const std::filesystem::path losPath = contentPath / "los.bin";
|
||||
std::ifstream in(losPath, std::ios::binary);
|
||||
if (!in) {
|
||||
LosLog.info("no los.bin at {}", losPath.string());
|
||||
return;
|
||||
}
|
||||
|
||||
std::vector<u8> data((std::istreambuf_iterator<char>(in)),
|
||||
std::istreambuf_iterator<char>());
|
||||
if (data.size() < sizeof(LosHeader)) {
|
||||
LosLog.warn("los.bin too small: {} bytes", data.size());
|
||||
return;
|
||||
}
|
||||
|
||||
u32 count = reinterpret_cast<const LosHeader*>(data.data())->count;
|
||||
if (sizeof(LosHeader) + size_t(count) * sizeof(LosEntry) > data.size()) {
|
||||
LosLog.warn("los.bin truncated: count={} size={}", count, data.size());
|
||||
return;
|
||||
}
|
||||
|
||||
g_data = std::move(data);
|
||||
g_count = count;
|
||||
LosLog.info("loaded los.bin: {} room transforms from {}", count, losPath.string());
|
||||
}
|
||||
|
||||
// Mirrors HD FUN_02ababbc:
|
||||
bool los_get_room_trans(int roomNo, f32* o_x, f32* o_y, f32* o_z, s16* o_angle) {
|
||||
if (g_count == 0 || roomNo < 0 || u32(roomNo) >= g_count) {
|
||||
return false;
|
||||
}
|
||||
const LosEntry& src = entries()[roomNo];
|
||||
*o_x = src.x;
|
||||
*o_y = src.y;
|
||||
*o_z = src.z;
|
||||
*o_angle = src.angleY;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool los_loaded() {
|
||||
return g_count != 0;
|
||||
}
|
||||
|
||||
int los_room_count() {
|
||||
return int(g_count);
|
||||
}
|
||||
|
||||
int los_next_floor(int roomNo) {
|
||||
if (g_count == 0 || roomNo < 0 || u32(roomNo) >= g_count) {
|
||||
return -1;
|
||||
}
|
||||
return s32(u32(entries()[roomNo].id1));
|
||||
}
|
||||
|
||||
int los_prev_floor(int roomNo) {
|
||||
if (g_count == 0 || roomNo < 0 || u32(roomNo) >= g_count) {
|
||||
return -1;
|
||||
}
|
||||
return s32(u32(entries()[roomNo].id2));
|
||||
}
|
||||
|
||||
int los_floor_index(int roomNo) {
|
||||
if (g_count == 0 || roomNo < 0 || u32(roomNo) >= g_count) {
|
||||
return 0;
|
||||
}
|
||||
return s32(u32(entries()[roomNo].id3));
|
||||
}
|
||||
|
||||
// D_SB11 (Cave of Shadows, HD): true when the los table is loaded and we are in D_SB11.
|
||||
// Mirrors HD's `g_dComIfG_gameInfo.field4_0x1e448 != 0` gate (set once in phase_1 for D_SB11).
|
||||
bool is_los_active() {
|
||||
return tphd_active() &&
|
||||
los_loaded() &&
|
||||
std::strcmp(dComIfGp_getStartStageName(), "D_SB11") == 0;
|
||||
}
|
||||
|
||||
void set_los_next_stage() {
|
||||
dComIfGp_setNextStage("D_SB11", 0, 19, -1, 0.0f, 0, 1, 0, 0, 1, 0);
|
||||
g_dComIfG_gameInfo.info.getRestart().setLastSceneInfo(20.0f, 0, 0);
|
||||
dComIfGs_setTurnRestart(dComIfGs_getTurnRestartPos(), 0, 0, daPy_py_c::setParamData(0, 1, 0xCA, 0));
|
||||
dComIfGs_setLife(dComIfGs_getMaxLife());
|
||||
}
|
||||
|
||||
} // namespace dusk::tphd
|
||||
@@ -0,0 +1,32 @@
|
||||
#ifndef DUSK_TPHD_LOS_TABLE_HPP
|
||||
#define DUSK_TPHD_LOS_TABLE_HPP
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
#include <dolphin/types.h>
|
||||
|
||||
namespace dusk::tphd {
|
||||
|
||||
// Loads `<contentPath>/los.bin` — the TP HD per-room transform table
|
||||
void load_los_table(const std::filesystem::path& contentPath);
|
||||
|
||||
// HD room map transform (mirrors HD `getMapTrans`/FUN_02905328 ) which
|
||||
// fills world X/Y/Z translation and Y-rotation for `roomNo` from los.bin.
|
||||
bool los_get_room_trans(int roomNo, f32* o_x, f32* o_y, f32* o_z, s16* o_angle);
|
||||
|
||||
bool los_loaded();
|
||||
|
||||
// Number of room entries in the los table
|
||||
int los_room_count();
|
||||
|
||||
int los_next_floor(int roomNo);
|
||||
int los_prev_floor(int roomNo);
|
||||
|
||||
int los_floor_index(int roomNo);
|
||||
|
||||
bool is_los_active();
|
||||
void set_los_next_stage();
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,120 @@
|
||||
#include "TphdPack.hpp"
|
||||
|
||||
#include <zlib.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
#include "dusk/endian.h"
|
||||
#include "dusk/logging.h"
|
||||
|
||||
static aurora::Module TphdLog("dusk::tphd");
|
||||
|
||||
namespace dusk::tphd {
|
||||
|
||||
namespace {
|
||||
|
||||
std::optional<std::vector<u8>> readFile(const std::filesystem::path& path) {
|
||||
std::FILE* f = std::fopen(path.string().c_str(), "rb");
|
||||
if (!f) return std::nullopt;
|
||||
std::fseek(f, 0, SEEK_END);
|
||||
long len = std::ftell(f);
|
||||
std::fseek(f, 0, SEEK_SET);
|
||||
if (len < 0) { std::fclose(f); return std::nullopt; }
|
||||
std::vector<u8> buf(static_cast<size_t>(len));
|
||||
size_t got = std::fread(buf.data(), 1, buf.size(), f);
|
||||
std::fclose(f);
|
||||
if (got != buf.size()) return std::nullopt;
|
||||
return buf;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
std::optional<std::vector<u8>> decompressGzip(std::span<const u8> in) {
|
||||
if (in.size() < 18) return std::nullopt;
|
||||
if (in[0] != 0x1F || in[1] != 0x8B) return std::nullopt;
|
||||
|
||||
u32 isize;
|
||||
std::memcpy(&isize, in.data() + in.size() - 4, sizeof(isize));
|
||||
std::vector<u8> out(isize);
|
||||
|
||||
z_stream strm{};
|
||||
strm.next_in = const_cast<Bytef*>(in.data());
|
||||
strm.avail_in = static_cast<uInt>(in.size());
|
||||
strm.next_out = out.data();
|
||||
strm.avail_out = static_cast<uInt>(out.size());
|
||||
|
||||
if (inflateInit2(&strm, 15 + 16) != Z_OK) return std::nullopt;
|
||||
int rc = inflate(&strm, Z_FINISH);
|
||||
inflateEnd(&strm);
|
||||
if (rc != Z_STREAM_END) return std::nullopt;
|
||||
return out;
|
||||
}
|
||||
|
||||
std::vector<TmpkEntry> parseTmpk(std::span<const u8> in) {
|
||||
std::vector<TmpkEntry> out;
|
||||
if (in.size() < sizeof(TmpkRawHeader)) return out;
|
||||
|
||||
const auto* hdr = reinterpret_cast<const TmpkRawHeader*>(in.data());
|
||||
if (std::memcmp(hdr->magic, "TMPK", 4) != 0) return out;
|
||||
|
||||
const u32 count = hdr->count;
|
||||
if (in.size() < sizeof(TmpkRawHeader) + count * sizeof(TmpkRawEntry)) return out;
|
||||
|
||||
const auto* entries = reinterpret_cast<const TmpkRawEntry*>(
|
||||
in.data() + sizeof(TmpkRawHeader));
|
||||
|
||||
out.reserve(count);
|
||||
for (u32 i = 0; i < count; ++i) {
|
||||
const u32 nameOff = entries[i].nameOff;
|
||||
const u32 dataOff = entries[i].dataOff;
|
||||
const u32 dataSize = entries[i].dataSize;
|
||||
const u32 flags = entries[i].flags;
|
||||
|
||||
if (nameOff >= in.size() || dataOff + dataSize > in.size()) continue;
|
||||
|
||||
const char* nameStart = reinterpret_cast<const char*>(in.data() + nameOff);
|
||||
size_t maxLen = in.size() - nameOff;
|
||||
const void* nul = std::memchr(nameStart, 0, maxLen);
|
||||
size_t nameLen = nul ? static_cast<size_t>(static_cast<const char*>(nul) - nameStart)
|
||||
: maxLen;
|
||||
|
||||
out.push_back({
|
||||
std::string_view(nameStart, nameLen),
|
||||
in.subspan(dataOff, dataSize),
|
||||
flags,
|
||||
});
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
std::optional<TphdPack> TphdPack::loadFromMemory(std::span<const u8> gzipBytes) {
|
||||
auto inflated = decompressGzip(gzipBytes);
|
||||
if (!inflated) return std::nullopt;
|
||||
|
||||
TphdPack p;
|
||||
p.m_buffer = std::move(*inflated);
|
||||
p.m_entries = parseTmpk(std::span<const u8>(p.m_buffer.data(), p.m_buffer.size()));
|
||||
if (p.m_entries.empty() && !p.m_buffer.empty()) {
|
||||
TphdLog.warn("TMPK parse yielded 0 entries (buffer size {})", p.m_buffer.size());
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
std::optional<TphdPack> TphdPack::loadFromFile(const std::filesystem::path& path) {
|
||||
auto raw = readFile(path);
|
||||
if (!raw) {
|
||||
TphdLog.error("Failed to read {}", path.string());
|
||||
return std::nullopt;
|
||||
}
|
||||
return loadFromMemory(*raw);
|
||||
}
|
||||
|
||||
const TmpkEntry* TphdPack::find(std::string_view name) const {
|
||||
for (const auto& e : m_entries) {
|
||||
if (e.name == name) return &e;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
#ifndef DUSK_TPHD_TPHD_PACK_HPP
|
||||
#define DUSK_TPHD_TPHD_PACK_HPP
|
||||
|
||||
#include <filesystem>
|
||||
#include <optional>
|
||||
#include <span>
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
#include <dolphin/types.h>
|
||||
|
||||
#include "dusk/endian.h"
|
||||
|
||||
namespace dusk::tphd {
|
||||
|
||||
// On-disk TMPK layout.
|
||||
struct TmpkRawHeader {
|
||||
/* 0x00 */ char magic[4]; // "TMPK"
|
||||
/* 0x04 */ BE(u32) count;
|
||||
/* 0x08 */ u8 pad[8];
|
||||
};
|
||||
static_assert(sizeof(TmpkRawHeader) == 0x10);
|
||||
|
||||
struct TmpkRawEntry {
|
||||
/* 0x00 */ BE(u32) nameOff;
|
||||
/* 0x04 */ BE(u32) dataOff;
|
||||
/* 0x08 */ BE(u32) dataSize;
|
||||
/* 0x0C */ BE(u32) flags;
|
||||
};
|
||||
static_assert(sizeof(TmpkRawEntry) == 0x10);
|
||||
|
||||
// Parsed TMPK entry: a view into the inflated pack buffer.
|
||||
struct TmpkEntry {
|
||||
std::string_view name;
|
||||
std::span<const u8> data;
|
||||
u32 flags;
|
||||
};
|
||||
|
||||
class TphdPack {
|
||||
public:
|
||||
static std::optional<TphdPack> loadFromFile(const std::filesystem::path& path);
|
||||
static std::optional<TphdPack> loadFromMemory(std::span<const u8> gzipBytes);
|
||||
|
||||
const std::vector<TmpkEntry>& entries() const { return m_entries; }
|
||||
const TmpkEntry* find(std::string_view name) const;
|
||||
|
||||
private:
|
||||
TphdPack() = default;
|
||||
|
||||
std::vector<u8> m_buffer;
|
||||
std::vector<TmpkEntry> m_entries;
|
||||
};
|
||||
|
||||
std::optional<std::vector<u8>> decompressGzip(std::span<const u8> in);
|
||||
std::vector<TmpkEntry> parseTmpk(std::span<const u8> in);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -3,9 +3,7 @@
|
||||
#include "aurora/rmlui.hpp"
|
||||
#include "ui.hpp"
|
||||
|
||||
#include "Z2AudioLib/Z2SeMgr.h"
|
||||
#include "m_Do/m_Do_audio.h"
|
||||
#include <imgui.h>
|
||||
|
||||
namespace dusk::ui {
|
||||
namespace {
|
||||
@@ -30,19 +28,19 @@ Document::Document(const Rml::String& source, bool passive)
|
||||
return;
|
||||
}
|
||||
const auto cmd = map_nav_event(event);
|
||||
if (cmd != NavCommand::Menu && !visible()) {
|
||||
if (cmd != NavCommand::Menu && (!visible() || !active())) {
|
||||
event.StopImmediatePropagation();
|
||||
}
|
||||
},
|
||||
true);
|
||||
const auto blockUnlessVisible = [this](Rml::Event& event) {
|
||||
if (!visible()) {
|
||||
const auto blockUnlessActive = [this](Rml::Event& event) {
|
||||
if (!visible() || !active()) {
|
||||
event.StopImmediatePropagation();
|
||||
}
|
||||
};
|
||||
listen(Rml::EventId::Mouseover, blockUnlessVisible, true);
|
||||
listen(Rml::EventId::Click, blockUnlessVisible, true);
|
||||
listen(Rml::EventId::Scroll, blockUnlessVisible, true);
|
||||
listen(Rml::EventId::Mouseover, blockUnlessActive, true);
|
||||
listen(Rml::EventId::Click, blockUnlessActive, true);
|
||||
listen(Rml::EventId::Scroll, blockUnlessActive, true);
|
||||
|
||||
listen(Rml::EventId::Keydown, [this](Rml::Event& event) {
|
||||
if (mPassive) {
|
||||
@@ -124,9 +122,16 @@ bool Document::visible() const {
|
||||
return *mDocument->GetProperty(Rml::PropertyId::Visibility) == Rml::Style::Visibility::Visible;
|
||||
}
|
||||
|
||||
bool Document::active() const {
|
||||
return !mClosed && !mPendingClose;
|
||||
}
|
||||
|
||||
bool Document::handle_nav_event(Rml::Event& event) {
|
||||
if (!active()) {
|
||||
return false;
|
||||
}
|
||||
const auto cmd = map_nav_event(event);
|
||||
if (cmd == NavCommand::None) {
|
||||
if (cmd == NavCommand::None || (cmd != NavCommand::Menu && !visible())) {
|
||||
return false;
|
||||
}
|
||||
return handle_nav_command(event, cmd);
|
||||
|
||||
@@ -18,6 +18,7 @@ public:
|
||||
virtual void update();
|
||||
virtual bool focus();
|
||||
virtual bool visible() const;
|
||||
virtual bool active() const;
|
||||
|
||||
void listen(Rml::Element* element, Rml::EventId event, ScopedEventListener::Callback callback,
|
||||
bool capture = false);
|
||||
@@ -41,12 +42,11 @@ public:
|
||||
push_document(std::move(document));
|
||||
hide(false);
|
||||
}
|
||||
void pop() {
|
||||
void pop(bool show = true) {
|
||||
hide(true);
|
||||
show_top_document();
|
||||
focus_top_document(show);
|
||||
}
|
||||
|
||||
bool pending_close() const { return mPendingClose; }
|
||||
bool closed() const { return mClosed; }
|
||||
|
||||
bool handle_nav_event(Rml::Event& event);
|
||||
|
||||
@@ -503,6 +503,20 @@ void file_dialog_callback(void*, const char* path, const char* error) {
|
||||
begin_disc_verification(path);
|
||||
}
|
||||
|
||||
void folder_dialog_callback(void*, const char* path, const char* error) {
|
||||
auto& state = prelaunch_state();
|
||||
if (error != nullptr) {
|
||||
return;
|
||||
}
|
||||
if (path == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
state.configuredHdContentPath = path;
|
||||
getSettings().backend.hdContentPath.setValue(path);
|
||||
config::Save();
|
||||
}
|
||||
|
||||
PrelaunchState sPrelaunchState;
|
||||
|
||||
} // namespace
|
||||
@@ -638,6 +652,8 @@ void ensure_initialized() noexcept {
|
||||
state.activeDiscPath = state.configuredDiscPath;
|
||||
state.configuredDiscValidation =
|
||||
verification_from_config(getSettings().backend.isoVerification.getValue());
|
||||
state.configuredHdContentPath = getSettings().backend.hdContentPath;
|
||||
state.activeHdContentPath = state.configuredHdContentPath;
|
||||
state.initialLanguage = getSettings().game.language;
|
||||
state.initialGraphicsBackend = getSettings().backend.graphicsBackend;
|
||||
state.initialCardFileType = getSettings().backend.cardFileType;
|
||||
@@ -652,11 +668,19 @@ void open_iso_picker() noexcept {
|
||||
kDiscFileFilters.data(), kDiscFileFilters.size(), nullptr, false);
|
||||
}
|
||||
|
||||
void open_folder_picker() noexcept {
|
||||
ensure_initialized();
|
||||
ShowFolderSelect(&folder_dialog_callback, nullptr, aurora::window::get_sdl_window(), nullptr);
|
||||
}
|
||||
|
||||
bool is_restart_pending() noexcept {
|
||||
const auto& state = prelaunch_state();
|
||||
if (!state.activeDiscPath.empty() && state.configuredDiscPath != state.activeDiscPath) {
|
||||
return true;
|
||||
}
|
||||
if (state.configuredHdContentPath != state.activeHdContentPath) {
|
||||
return true;
|
||||
}
|
||||
if (data::is_data_path_restart_pending()) {
|
||||
return true;
|
||||
}
|
||||
@@ -715,7 +739,7 @@ Prelaunch::Prelaunch() : Document(kDocumentSource), mRoot(mDocument->GetElementB
|
||||
}
|
||||
|
||||
IsGameLaunched = true;
|
||||
hide(true);
|
||||
pop(false);
|
||||
});
|
||||
apply_intro_animation(mMenuButtons.back()->root(), "delay-1");
|
||||
|
||||
|
||||
@@ -47,6 +47,8 @@ struct PrelaunchState {
|
||||
iso::ValidationError configuredDiscValidation = iso::ValidationError::Unknown;
|
||||
std::string activeDiscPath;
|
||||
iso::DiscInfo activeDiscInfo{};
|
||||
std::string configuredHdContentPath;
|
||||
std::string activeHdContentPath;
|
||||
GameLanguage initialLanguage = GameLanguage::English;
|
||||
std::string initialGraphicsBackend;
|
||||
int initialCardFileType = 0;
|
||||
@@ -60,6 +62,7 @@ PrelaunchState& prelaunch_state() noexcept;
|
||||
void ensure_initialized() noexcept;
|
||||
void refresh_configured_disc_state() noexcept;
|
||||
void open_iso_picker() noexcept;
|
||||
void open_folder_picker() noexcept;
|
||||
bool is_restart_pending() noexcept;
|
||||
void try_push_verification_modal(Document& host);
|
||||
|
||||
|
||||
@@ -59,6 +59,22 @@ constexpr std::array kLanguageNames = {
|
||||
"Italian",
|
||||
};
|
||||
|
||||
constexpr std::array kLanguageNamesUS = {
|
||||
"American English",
|
||||
"German",
|
||||
"Canadian French",
|
||||
"Latin American Spanish",
|
||||
"Italian",
|
||||
};
|
||||
|
||||
constexpr std::array kLanguageNamesEU = {
|
||||
"British English",
|
||||
"German",
|
||||
"European French",
|
||||
"European Spanish",
|
||||
"Italian",
|
||||
};
|
||||
|
||||
constexpr std::array kCardFileTypes = {
|
||||
"Card Image",
|
||||
"GCI Folder",
|
||||
@@ -580,6 +596,38 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
pane.add_rml("Set the disc image that Dusklight uses to launch the game.<br/><br/>"
|
||||
"Changes require a restart.");
|
||||
});
|
||||
|
||||
leftPane.register_control(
|
||||
leftPane
|
||||
.add_select_button({
|
||||
.key = "TPHD Content Folder",
|
||||
.getValue =
|
||||
[] {
|
||||
const auto& path = prelaunch_state().configuredHdContentPath;
|
||||
std::string display;
|
||||
if (path.empty()) {
|
||||
display = "(none)";
|
||||
} else {
|
||||
display = std::filesystem::path(path).string();
|
||||
if (display.empty()) {
|
||||
display = path;
|
||||
}
|
||||
}
|
||||
return display;
|
||||
},
|
||||
.isModified =
|
||||
[] {
|
||||
const auto& state = prelaunch_state();
|
||||
const auto& active = state.activeHdContentPath;
|
||||
return !active.empty() && state.configuredHdContentPath != active;
|
||||
},
|
||||
})
|
||||
.on_pressed([] { open_folder_picker(); }),
|
||||
rightPane, [](Pane& pane) {
|
||||
pane.add_rml("Set the directory that Dusk loads eligible TPHD content from."
|
||||
"<br/><br/>Changes require a restart.");
|
||||
});
|
||||
|
||||
#if DUSK_CAN_CHANGE_DATA_FOLDER
|
||||
leftPane.register_control(
|
||||
leftPane.add_select_button({
|
||||
@@ -625,21 +673,31 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
#endif
|
||||
leftPane.register_control(
|
||||
leftPane.add_select_button({
|
||||
.key = "Language",
|
||||
.key = dusk::tphd_active() ? "Language (HD)" : "Language",
|
||||
.getValue =
|
||||
[] {
|
||||
const auto& state = prelaunch_state();
|
||||
if (!state.configuredDiscCanLaunch || !state.configuredDiscInfo.isPal) {
|
||||
if (!state.configuredDiscCanLaunch) {
|
||||
return kLanguageNames[0];
|
||||
}
|
||||
|
||||
const u8 idx = static_cast<u8>(getSettings().game.language.getValue());
|
||||
|
||||
if (dusk::tphd_active()) {
|
||||
if (state.configuredDiscInfo.isPal) {
|
||||
return kLanguageNamesEU[idx];
|
||||
} else {
|
||||
return kLanguageNamesUS[idx];
|
||||
}
|
||||
}
|
||||
|
||||
return kLanguageNames[idx];
|
||||
},
|
||||
.isDisabled =
|
||||
[] {
|
||||
const auto& state = prelaunch_state();
|
||||
return !state.configuredDiscCanLaunch ||
|
||||
!state.configuredDiscInfo.isPal;
|
||||
(!state.configuredDiscInfo.isPal && !dusk::tphd_active());
|
||||
},
|
||||
.isModified =
|
||||
[] {
|
||||
@@ -648,9 +706,20 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
|
||||
},
|
||||
}),
|
||||
rightPane, [](Pane& pane) {
|
||||
for (int i = 0; i < kLanguageNames.size(); i++) {
|
||||
auto* languageNames = &kLanguageNames;
|
||||
auto& state = prelaunch_state();
|
||||
|
||||
if (dusk::tphd_active()) {
|
||||
if (state.configuredDiscInfo.isPal) {
|
||||
languageNames = &kLanguageNamesEU;
|
||||
} else {
|
||||
languageNames = &kLanguageNamesUS;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < languageNames->size(); i++) {
|
||||
pane.add_button({
|
||||
.text = kLanguageNames[i],
|
||||
.text = languageNames->data()[i],
|
||||
.isSelected =
|
||||
[i] {
|
||||
return getSettings().game.language.getValue() ==
|
||||
|
||||
@@ -156,9 +156,8 @@ bool player_attention_locked() noexcept {
|
||||
return player != nullptr && (player->checkAttentionLock() || player->checkEnemyAttentionLock());
|
||||
}
|
||||
|
||||
bool touch_aim_capture_active() noexcept {
|
||||
auto* player = daAlink_getAlinkActorClass();
|
||||
return player != nullptr && player->checkTouchAimCaptureContext() && dCamera_c::isAimActive();
|
||||
bool hawkeye_active() noexcept {
|
||||
return dCamera_c::isAimActive() && dComIfGp_checkPlayerStatus0(0, 0x200000);
|
||||
}
|
||||
|
||||
bool item_wheel_active() noexcept {
|
||||
@@ -179,7 +178,7 @@ enum class StickOutput {
|
||||
};
|
||||
|
||||
StickOutput stick_output_mode() noexcept {
|
||||
if (fishing_controls_active()) {
|
||||
if (fishing_controls_active() || hawkeye_active()) {
|
||||
return StickOutput::CStick;
|
||||
}
|
||||
return StickOutput::MainStick;
|
||||
@@ -697,8 +696,8 @@ void TouchControls::sync_touch_state() noexcept {
|
||||
}
|
||||
|
||||
sync_l_lock_state();
|
||||
const bool aimActive = touch_aim_capture_active();
|
||||
if (aimActive && mMoveTouch.active) {
|
||||
const bool aimActive = dCamera_c::isAimActive();
|
||||
if (aimActive && !hawkeye_active() && mMoveTouch.active) {
|
||||
if (!mCameraTouch.active) {
|
||||
mCameraTouch = mMoveTouch;
|
||||
mCameraTouch.start = mMoveTouch.current;
|
||||
@@ -1213,7 +1212,26 @@ void TouchControls::handle_touch_down(Rml::Event& event) noexcept {
|
||||
}
|
||||
|
||||
const auto id = touch_event_id(event);
|
||||
if (touch_aim_capture_active()) {
|
||||
const auto dimensions = context->GetDimensions();
|
||||
const float top = mSafeInsets.top + kAnalogZoneTopDp * touch_dp_scale();
|
||||
const float bottom = static_cast<float>(dimensions.y) - mSafeInsets.bottom -
|
||||
kAnalogZoneBottomDp * touch_dp_scale();
|
||||
const auto width = static_cast<float>(dimensions.x);
|
||||
const bool inAnalogZone = position.y >= top && position.y <= bottom;
|
||||
const bool inLeftZone = position.x < width * kLeftZoneWidth;
|
||||
if (dCamera_c::isAimActive()) {
|
||||
if (hawkeye_active() && inAnalogZone && inLeftZone) {
|
||||
if (!mMoveTouch.active) {
|
||||
mMoveTouch = {
|
||||
.id = id,
|
||||
.start = position,
|
||||
.current = position,
|
||||
.active = true,
|
||||
};
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (!mCameraTouch.active) {
|
||||
mCameraTouch = {
|
||||
.id = id,
|
||||
@@ -1225,16 +1243,11 @@ void TouchControls::handle_touch_down(Rml::Event& event) noexcept {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto dimensions = context->GetDimensions();
|
||||
const float top = mSafeInsets.top + kAnalogZoneTopDp * touch_dp_scale();
|
||||
const float bottom = static_cast<float>(dimensions.y) - mSafeInsets.bottom -
|
||||
kAnalogZoneBottomDp * touch_dp_scale();
|
||||
if (position.y < top || position.y > bottom) {
|
||||
if (!inAnalogZone) {
|
||||
return;
|
||||
}
|
||||
|
||||
const auto width = static_cast<float>(dimensions.x);
|
||||
if (!mMoveTouch.active && position.x < width * kLeftZoneWidth) {
|
||||
if (!mMoveTouch.active && inLeftZone) {
|
||||
mMoveTouch = {
|
||||
.id = id,
|
||||
.start = position,
|
||||
|
||||
+9
-5
@@ -195,9 +195,13 @@ Document& push_document(std::unique_ptr<Document> doc, bool show, bool passive)
|
||||
return ret;
|
||||
}
|
||||
|
||||
void show_top_document() noexcept {
|
||||
void focus_top_document(bool show) noexcept {
|
||||
if (auto* doc = top_document()) {
|
||||
doc->show();
|
||||
if (show) {
|
||||
doc->show();
|
||||
} else {
|
||||
doc->focus();
|
||||
}
|
||||
}
|
||||
input::sync_input_block();
|
||||
}
|
||||
@@ -210,13 +214,13 @@ bool any_document_visible() noexcept {
|
||||
bool is_prelaunch_open() noexcept {
|
||||
return std::any_of(sDocumentStack.begin(), sDocumentStack.end(), [](const auto& doc) {
|
||||
const auto* prelaunch = dynamic_cast<const Prelaunch*>(doc.get());
|
||||
return prelaunch != nullptr && !prelaunch->pending_close() && !prelaunch->closed();
|
||||
return prelaunch != nullptr && prelaunch->active();
|
||||
});
|
||||
}
|
||||
|
||||
Document* top_document() noexcept {
|
||||
for (auto& doc : std::views::reverse(sDocumentStack)) {
|
||||
if (!doc->closed() && !doc->pending_close()) {
|
||||
if (doc->active()) {
|
||||
return doc.get();
|
||||
}
|
||||
}
|
||||
@@ -259,7 +263,7 @@ void update() noexcept {
|
||||
context->GetFocusElement() == context->GetRootElement()))
|
||||
{
|
||||
for (auto& doc : std::views::reverse(sDocumentStack)) {
|
||||
if (!doc->closed() && !doc->pending_close() && doc->focus()) {
|
||||
if (doc->active() && doc->focus()) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -74,7 +74,7 @@ void update() noexcept;
|
||||
|
||||
Document& push_document(
|
||||
std::unique_ptr<Document> doc, bool show = true, bool passive = false) noexcept;
|
||||
void show_top_document() noexcept;
|
||||
void focus_top_document(bool show) noexcept;
|
||||
bool any_document_visible() noexcept;
|
||||
bool is_prelaunch_open() noexcept;
|
||||
Document* top_document() noexcept;
|
||||
|
||||
@@ -730,7 +730,10 @@ u8 var_r30 = fopAcM::HeapAdjustEntry;
|
||||
#endif
|
||||
|
||||
u32 size = i_size & 0xFFFFFF;
|
||||
#if TARGET_PC
|
||||
#if DUSK_TPHD
|
||||
// With TP-HD asset overlays, individual BMDs can be 5-10x their GC originals.
|
||||
size *= 8;
|
||||
#elif TARGET_PC
|
||||
size *= 2;
|
||||
#endif
|
||||
bool result = fopAcM_entrySolidHeap_(i_actor, i_heapCallback, size);
|
||||
|
||||
@@ -2225,6 +2225,13 @@ void mDoExt_invJntPacket::draw() {
|
||||
JUT_ASSERT(5011, shapePkt != NULL);
|
||||
shapePkt->getShape()->loadPreDrawSetting();
|
||||
|
||||
#if DUSK_TPHD
|
||||
{
|
||||
const auto* offs = sp18->getMaterial()->getPEBlock()->getPolygonOffset();
|
||||
GX2SetPolygonOffset(offs->mFrontOffset, offs->mFrontScale, offs->mBackOffset, offs->mBackScale, offs->mClamp);
|
||||
}
|
||||
#endif
|
||||
|
||||
do {
|
||||
if (!shapePkt->getShape()->checkFlag(1)) {
|
||||
if (shapePkt->getDisplayListObj() != NULL) {
|
||||
|
||||
@@ -813,6 +813,18 @@ int mDoMch_Create() {
|
||||
gameHeapSize += 0x200000;
|
||||
gameHeapSize += 0x100000;
|
||||
dynamicLinkHeapSize = 0x180000;
|
||||
#if DUSK_TPHD
|
||||
// HD assets ship much larger archives/actors (CMPR texture injection
|
||||
// pushes stage BMDs past 8 MB and Link's Kmdl past 5 MB). Parent arena is
|
||||
// 1 GB on PC, distribute generously across every heap that holds model
|
||||
// or animation data at runtime.
|
||||
if (dusk::tphd_active()) {
|
||||
archiveHeapSize += 0x08000000; // +128 MB (large RARCs)
|
||||
gameHeapSize += 0x10000000; // +256 MB (parent of per-actor heaps like "Alink original")
|
||||
j2dHeapSize += 0x01000000; // +16 MB (UI textures)
|
||||
dynamicLinkHeapSize += 0x01000000; // +16 MB
|
||||
}
|
||||
#endif
|
||||
|
||||
#if !DEBUG
|
||||
// Fakematch because the heap sizes differ between debug and retail.
|
||||
@@ -860,9 +872,11 @@ int mDoMch_Create() {
|
||||
#if DEBUG
|
||||
dynamicLinkHeapSize *= 2;
|
||||
#endif
|
||||
archiveHeapSize *= 2;
|
||||
j2dHeapSize *= 2;
|
||||
gameHeapSize *= 20; // NOTE: increased from 2 to 20 to try to solve heap alloc crashes. maybe do a better fix later
|
||||
if (!dusk::tphd_active()) {
|
||||
archiveHeapSize *= 2;
|
||||
j2dHeapSize *= 2;
|
||||
gameHeapSize *= 20; // NOTE: increased from 2 to 20 to try to solve heap alloc crashes. maybe do a better fix later
|
||||
}
|
||||
#endif
|
||||
|
||||
JFWSystem::setSysHeapSize(arenaSize);
|
||||
|
||||
+27
-13
@@ -90,6 +90,7 @@
|
||||
#include "dusk/io.hpp"
|
||||
#include "dusk/version.hpp"
|
||||
#include "dusk/discord_presence.hpp"
|
||||
#include "dusk/tphd/HdAssetLayer.hpp"
|
||||
#include "tracy/Tracy.hpp"
|
||||
#include "f_pc/f_pc_draw.h"
|
||||
#include "tracy/Tracy.hpp"
|
||||
@@ -334,11 +335,21 @@ void main01(void) {
|
||||
mDoAud_Execute();
|
||||
}
|
||||
|
||||
aurora_end_frame();
|
||||
|
||||
FrameMark;
|
||||
|
||||
#ifdef DUSK_DISCORD
|
||||
dusk::discord::run_callbacks();
|
||||
dusk::discord::update_presence();
|
||||
#endif
|
||||
|
||||
static Limiter main_loop_limiter;
|
||||
static double last_fps_setting = 0.0;
|
||||
static Limiter::duration_t target_ns = 0;
|
||||
|
||||
if (dusk::getSettings().game.enableFrameInterpolation.getValue() == dusk::FrameInterpMode::Capped && !dusk::getTransientSettings().skipFrameRateLimit) {
|
||||
ZoneScopedN("Frame limiter");
|
||||
double current_fps = dusk::getSettings().video.maxFrameRate.getValue();
|
||||
if (current_fps != last_fps_setting) {
|
||||
last_fps_setting = current_fps;
|
||||
@@ -350,16 +361,6 @@ void main01(void) {
|
||||
} else {
|
||||
main_loop_limiter.Reset();
|
||||
}
|
||||
|
||||
aurora_end_frame();
|
||||
|
||||
|
||||
FrameMark;
|
||||
|
||||
#ifdef DUSK_DISCORD
|
||||
dusk::discord::run_callbacks();
|
||||
dusk::discord::update_presence();
|
||||
#endif
|
||||
} while (dusk::IsRunning);
|
||||
|
||||
exit:;
|
||||
@@ -483,9 +484,9 @@ u8 OSGetLanguage() {
|
||||
}
|
||||
|
||||
static void LanguageInit() {
|
||||
// Keep language at 0 (English) if not on a PAL disc.
|
||||
// Keep language at 0 (English) if not on a PAL disc and if TPHD is unloaded.
|
||||
// Doubt this matters, but avoid funky shit.
|
||||
if (!dusk::version::isRegionPal()) {
|
||||
if (!dusk::version::isRegionPal() && !dusk::tphd_active()) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -609,7 +610,11 @@ int game_main(int argc, char* argv[]) {
|
||||
config.desiredBackend = ResolveDesiredBackend(parsed_arg_options);
|
||||
config.logCallback = &aurora_log_callback;
|
||||
config.logLevel = startupLogLevel;
|
||||
config.mem1Size = 256 * 1024 * 1024;
|
||||
if (dusk::tphd_active()) {
|
||||
config.mem1Size = 512 * 1024 * 1024;
|
||||
} else {
|
||||
config.mem1Size = 256 * 1024 * 1024;
|
||||
}
|
||||
config.mem2Size = 24 * 1024 * 1024;
|
||||
config.allowJoystickBackgroundEvents = dusk::getSettings().game.allowBackgroundInput;
|
||||
config.pauseOnFocusLost = dusk::getSettings().game.pauseOnFocusLost;
|
||||
@@ -762,6 +767,15 @@ int game_main(int argc, char* argv[]) {
|
||||
dusk::IsGameLaunched = true;
|
||||
}
|
||||
|
||||
#if DUSK_TPHD
|
||||
{
|
||||
const auto hdPath = dusk::tphd_content_path();
|
||||
if (!hdPath.empty()) {
|
||||
dusk::tphd::set_hd_content_path(hdPath);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if DUSK_ENABLE_SENTRY_NATIVE
|
||||
if (dusk::crash_reporting::get_consent() == dusk::crash_reporting::Consent::Unknown) {
|
||||
dusk::ui::push_document(std::make_unique<dusk::ui::CrashReportWindow>());
|
||||
|
||||
Reference in New Issue
Block a user