Compare commits

...

66 Commits

Author SHA1 Message Date
SuperDude88 529a61001a RPX Loader
This is mostly a mess and should not be included in its current state, pushing it so I don't forget/lose it on my machine. Only changes Link's l_sightDL as a (messy) example since the other cases probably need further code changes.

Does not currently support multiple RPX versions/regions. Handling of SD/HD switching should be fleshed out more before integrating this fully imo.
2026-06-25 23:09:28 -04:00
Lurs d23a5c6fd1 Merge remote-tracking branch 'origin/main' into tphd 2026-06-17 19:17:52 +02:00
MelonSpeedruns ea034bf884 Add warp out sound to CoS when withdrawing to match TPHD 2026-06-14 12:28:08 -04:00
Lurs 2b266048c6 Add temple of time reflections via GX2 stencil. Temporarily point to my own aurora fork before stencil PR is merged. 2026-06-12 08:21:57 +02:00
TakaRikka c99241a662 fix withdraw functionality 2026-06-11 23:07:28 -07:00
TakaRikka 7f503c9d8f fix los lift 2026-06-11 22:29:36 -07:00
TakaRikka 776ee9b978 partially fix los exit portals 2026-06-11 21:55:58 -07:00
TakaRikka f0c2544d53 force load as wolf 2026-06-11 18:43:29 -07:00
TakaRikka cda5a17c2d disable los transforming 2026-06-11 18:27:28 -07:00
TakaRikka 645d64a73a fix los bgm 2026-06-11 13:21:57 -07:00
MelonSpeedruns 849edf4a58 fix title logo for SD & import hd particles & fix minimap crash 2026-06-11 15:22:07 -04:00
MelonSpeedruns 1d1ece9cb2 fix file select music not playing 2026-06-11 14:34:18 -04:00
MelonSpeedruns cb85470214 HD minigame icons + map files loading 2026-06-11 13:56:10 -04:00
MelonSpeedruns 273c58d927 HD title logo for pal regions 2026-06-11 13:55:46 -04:00
TakaRikka 6692eff3a3 partially working colossal wallet 2026-06-11 03:10:45 -07:00
TakaRikka 43817ea4e5 fix los fairy 2026-06-11 02:07:44 -07:00
TakaRikka 55ceab9b2d fix los wolfos 2026-06-10 23:58:09 -07:00
TakaRikka 7f2dc7902c add los table loading 2026-06-09 23:50:47 -07:00
TakaRikka e345323f0a add los swpush variant 2026-06-09 03:28:40 -07:00
TakaRikka 3d5b55ad33 fix build 2026-06-09 01:24:40 -07:00
TakaRikka 8182f6123b Merge branch 'main' of https://github.com/TwilitRealm/dusklight into tphd 2026-06-09 01:23:46 -07:00
TakaRikka 4d63aa3aad add cos shutter walls 2026-06-05 18:07:14 -07:00
MelonSpeedruns 17d9dad1d9 fixed vessel of light tears visuals 2026-06-03 18:29:59 -04:00
MelonSpeedruns dc798a931c re-add TPHD content path option in pre-launch 2026-06-03 16:45:57 -04:00
MelonSpeedruns 55a81adfad swap language names in the prelaunch menu to match the loaded ISO region 2026-06-01 12:58:14 -04:00
Lurs a2ddd3b580 change register_copied_hd_bti to register_copied_hd_resource to load BMDs as well for weapom textures 2026-05-31 09:31:37 +02:00
SuperDude88 b99ad37541 Remaining GX2SetPolygonOffset Uses
Port over the remaining uses of this from HD
2026-05-30 19:34:49 -04:00
Luke Street b6b71a32c7 Replace textures from mounted JKRArchives 2026-05-30 16:13:14 -06:00
Luke Street 458ffb17c2 Load from data/tphd/content if exists 2026-05-30 15:38:33 -06:00
Luke Street 7c17b1f5f7 Move GX2SetPolygonOffset to the right place 2026-05-30 13:40:11 -06:00
MelonSpeedruns e1d0f99fc3 language support 2026-05-30 15:19:22 -04:00
Luke Street 228d4d2bd1 Update aurora & DVD overlay API 2026-05-30 13:17:16 -06:00
Luke Street a50a8b21e1 Stop using std::format 2026-05-30 09:00:12 -06:00
Luke Street fd1a9ebd4e Unslopify a few more things 2026-05-30 08:57:14 -06:00
Lurs f73f28b4c6 added computeSurfaceInfo from decaf for NextPow2 padded mips in GTX 2026-05-30 15:53:45 +02:00
Luke Street f6d4eba130 Update aurora 2026-05-29 21:23:26 -06:00
Luke Street 20885959b7 Merge branch 'main' into tphd 2026-05-29 21:23:18 -06:00
Luke Street ae11304c66 Use DVD overlay system & runtime Aurora texture replacements 2026-05-29 21:18:04 -06:00
Luke Street bd8b3aafeb Skip unknown treasure types in dTres_c::addData 2026-05-29 00:24:54 -06:00
Luke Street 9c001114f7 Increase string capacity in dDlst_TimerScrnDraw_c 2026-05-29 00:24:35 -06:00
Luke Street 34c55700a2 CMake: Use zlib from aurora 2026-05-29 00:23:58 -06:00
Luke Street a99c8096d5 Merge branch 'refs/heads/main' into depth-bias-poc-hack 2026-05-28 22:41:45 -06:00
MelonSpeedruns 0b93dd9698 Merge remote-tracking branch 'origin/main' into depth-bias-poc-hack 2026-05-27 15:59:54 -04:00
Lurs be771e1a83 Merge branch 'depth-bias-poc-hack' of https://github.com/TwilitRealm/dusk into depth-bias-poc-hack 2026-05-27 17:28:33 +02:00
Lurs e0de71b5b4 Take widthAlignFactor into account for alignment in mipLevelDesc to fix wrong mip level 2 and above 2026-05-27 17:28:00 +02:00
MelonSpeedruns 010a4b5094 Fix fish book crash 2026-05-25 15:43:17 -04:00
MelonSpeedruns a71bd56058 Merge branch 'tphd' into depth-bias-poc-hack 2026-05-25 14:43:25 -04:00
MelonSpeedruns 63a86a456f update aurora 2026-05-25 14:37:44 -04:00
MelonSpeedruns 6304866b38 Merge remote-tracking branch 'origin/main' into tphd
# Conflicts:
#	extern/aurora
2026-05-25 14:37:26 -04:00
Lurs 54dbf20480 Fix mipmapping of BC1 textures. Update aurora. 2026-05-24 21:36:38 +02:00
MelonSpeedruns f11d4b14d9 have modified tears of light count use tphd_active function 2026-05-23 16:03:45 -04:00
SuperDude88 31298f24ba Broken Attempt at Depth Bias
Pushing so I can ask the smarter people questions
2026-05-22 13:26:39 -04:00
SuperDude88 8ae35dc9ea Add Missing BE
- Checking the values in the debugger reminded me that these need to be swapped
2026-05-21 00:21:34 -04:00
SuperDude88 9abb6bafd1 MAT4 Loading
- Properly load all MAT4 data

New fields/inlines/structs are based on what HD does. Still looking for ways to clean things up, particularly getMatInitData.
2026-05-20 23:47:24 -04:00
MelonSpeedruns 81c0c6f4d3 Merge remote-tracking branch 'origin/main' into tphd
# Conflicts:
#	extern/aurora
2026-05-19 15:49:56 -04:00
Lurs 41fe3a85a2 add Tracy zones 2026-05-18 17:31:07 +02:00
Lurs 307f626c57 fix crash when transforming into wolf 2026-05-18 17:30:03 +02:00
Lurs cd0b8b3172 fix mimapping (hopefully). update aurora 2026-05-17 09:15:53 +02:00
Lurs 8e55961e3c Merge remote-tracking branch 'origin/main' into tphd 2026-05-17 09:12:15 +02:00
MelonSpeedruns fd204062f7 Merge remote-tracking branch 'origin/main' into tphd
# Conflicts:
#	extern/aurora
2026-05-15 12:35:59 -04:00
MelonSpeedruns 89b8debe51 Merge remote-tracking branch 'origin/main' into tphd
# Conflicts:
#	CMakeLists.txt
#	extern/aurora
#	src/dusk/ui/prelaunch.cpp
#	src/dusk/ui/settings.cpp
2026-05-14 09:15:35 -04:00
MelonSpeedruns c498bf8fb8 Merge remote-tracking branch 'origin/main' into tphd
# Conflicts:
#	CMakeLists.txt
#	src/dusk/file_select.cpp
2026-05-10 14:08:25 -04:00
MelonSpeedruns 290f592098 update aurora 2026-05-10 13:51:51 -04:00
Irastris 9a80f3a08a Re-add settings options and other misc changes 2026-05-08 19:50:31 -04:00
MelonSpeedruns 41e128c582 MelonSpeedruns' squashed commits
* Fix RB channels + Remove mipmaps for now

* Remove loading most Layout files from a TPHD dump

* Fixes the main map crashing

* added folder picker to pre-launch options

* reduced tears of light needed count to 12 instead of 16
2026-05-08 19:50:31 -04:00
Lurs aa23ae244f Lurs' squashed commits
* first tphd wip

* fix CMakeLists.txt after rebase

* fix mipmapping (I hope) thanks to decaf-emu. Skipped a few textures in favor of GC assets and added new HD asset file formats

* added third hook into dusk for second JKRMemArchive constructor (e.g. for sign textures). skip texture load for textures with imageoffset = 0 to get STG.arc loaded instead. And small refactorings/rebasings. added a few parameters in logging
2026-05-08 19:43:48 -04:00
88 changed files with 4338 additions and 133 deletions
+1 -1
View File
@@ -1,3 +1,3 @@
[submodule "extern/aurora"] [submodule "extern/aurora"]
path = extern/aurora path = extern/aurora
url = https://github.com/encounter/aurora.git url = https://github.com/Lurs/aurora.git
+2 -2
View File
@@ -363,7 +363,7 @@ set(DUSK_COPYRIGHT "Copyright (C) Twilit Realm contributors")
source_group("dolzel" FILES ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${REL_FILES}) source_group("dolzel" FILES ${DOLZEL_FILES} ${Z2AUDIOLIB_FILES} ${REL_FILES})
source_group("dusklight" FILES ${DUSK_FILES} ${DUSK_HTTP_BACKEND_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 set(GAME_INCLUDE_DIRS
include include
@@ -378,7 +378,7 @@ set(GAME_INCLUDE_DIRS
find_package(Threads REQUIRED) 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 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 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) if (DUSK_ENABLE_SENTRY_NATIVE)
list(APPEND GAME_LIBS sentry) list(APPEND GAME_LIBS sentry)
+1 -1
+10
View File
@@ -1546,6 +1546,16 @@ set(DUSK_FILES
src/dusk/discord_presence.cpp src/dusk/discord_presence.cpp
src/dusk/version.cpp src/dusk/version.cpp
src/dusk/action_bindings.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 set(DUSK_HTTP_BACKEND_FILES
+4
View File
@@ -158,6 +158,10 @@ enum Z2Scene {
/* 0x4E */ Z2SCENE_GROTTO_ROCK_2, /* 0x4E */ Z2SCENE_GROTTO_ROCK_2,
/* 0x4F */ Z2SCENE_GROTTO_POND, /* 0x4F */ Z2SCENE_GROTTO_POND,
/* 0x50 */ Z2SCENE_FARON_WOODS_CAVE, /* 0x50 */ Z2SCENE_FARON_WOODS_CAVE,
#if TARGET_PC
/* 0x51 */ Z2SCENE_CAVE_OF_SHADOWS,
#endif
}; };
#endif /* Z2SCENEMGR_H */ #endif /* Z2SCENEMGR_H */
+2
View File
@@ -4560,6 +4560,8 @@ public:
void onIronBallChainInterpCallback(); void onIronBallChainInterpCallback();
f32 mLosStickValue;
static const int IRON_BALL_CHAIN_COUNT = 102; static const int IRON_BALL_CHAIN_COUNT = 102;
cXyz mIBChainInterpPrevPos[IRON_BALL_CHAIN_COUNT]; cXyz mIBChainInterpPrevPos[IRON_BALL_CHAIN_COUNT];
cXyz mIBChainInterpCurrPos[IRON_BALL_CHAIN_COUNT]; cXyz mIBChainInterpCurrPos[IRON_BALL_CHAIN_COUNT];
+9 -1
View File
@@ -18,16 +18,24 @@ public:
TGXTexObj& getTexObj() { return mTexObj; } TGXTexObj& getTexObj() { return mTexObj; }
cXyz* getQuad() { return mQuad; } 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; /* 0x010 */ TGXTexObj mTexObj;
/* 0x030 */ u8 mModelCount; /* 0x030 */ u8 mModelCount;
/* 0x034 */ J3DModel* mModels[0x40]; /* 0x034 */ J3DModel* mModels[0x40];
/* 0x134 */ cXyz mQuad[4]; /* 0x134 */ cXyz mQuad[DUSK_IF_ELSE(MAX_QUADS*4, 4)];
/* 0x164 */ cXyz mMinVal; /* 0x164 */ cXyz mMinVal;
/* 0x170 */ cXyz mMaxVal; /* 0x170 */ cXyz mMaxVal;
/* 0x17C */ cXyz mViewScale; /* 0x17C */ cXyz mViewScale;
#if TARGET_PC #if TARGET_PC
bool mbReset = false; bool mbReset = false;
bool mbHadEntry = false; bool mbHadEntry = false;
cXyz mQuadBoxMin[MAX_QUADS];
cXyz mQuadBoxMax[MAX_QUADS];
int mQuadCount = 1;
#endif #endif
}; };
+4 -4
View File
@@ -142,12 +142,12 @@ namespace daObjSwpush {
int Mthd_Execute(); int Mthd_Execute();
int Mthd_Draw(); int Mthd_Draw();
static s16 const M_bmd[3]; static s16 const M_bmd[DUSK_IF_ELSE(4, 3)];
static s16 const M_dzb[3]; static s16 const M_dzb[DUSK_IF_ELSE(4, 3)];
static u32 const M_heap_size[3]; static u32 const M_heap_size[DUSK_IF_ELSE(4, 3)];
static Hio_c::Attr_c const M_attr[5]; static Hio_c::Attr_c const M_attr[5];
static u8 const M_op_vtx[4]; 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; /* 0x568 */ request_of_phase_process_class mPhase;
/* 0x570 */ dBgWSv* mpBgW; /* 0x570 */ dBgWSv* mpBgW;
+4
View File
@@ -400,4 +400,8 @@ BOOL isBottleItem(u8 item_no);
u8 check_itemno(int i_itemNo); u8 check_itemno(int i_itemNo);
BOOL isInsect(u8 i_itemNo); BOOL isInsect(u8 i_itemNo);
#if TARGET_PC
void item_func_WALLET_LV4();
#endif
#endif /* D_D_ITEM_H */ #endif /* D_D_ITEM_H */
+7
View File
@@ -350,4 +350,11 @@ enum {
/* 0xFF */ dItemNo_NONE_e, /* 0xFF */ dItemNo_NONE_e,
}; };
#if TARGET_PC
// HD item mappings
enum {
dItemNo_WALLET_LV4_e = 0xDA,
};
#endif
#endif /* D_D_ITEM_DATA_H */ #endif /* D_D_ITEM_DATA_H */
+1 -1
View File
@@ -57,7 +57,7 @@ public:
return &mpTypeGroupData[i_typeGroupNo]; return &mpTypeGroupData[i_typeGroupNo];
} }
/* 0x0 */ fmpTresTypeGroupDataList_c mpTypeGroupData[17]; /* 0x0 */ fmpTresTypeGroupDataList_c mpTypeGroupData[DUSK_IF_ELSE(35, 17)];
}; };
class dMenu_Fmap_data_c { class dMenu_Fmap_data_c {
+11 -2
View File
@@ -172,6 +172,15 @@ public:
int event041(mesg_flow_node_event*, fopAc_ac_c*); int event041(mesg_flow_node_event*, fopAc_ac_c*);
int event042(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**); void initWord(fopAc_ac_c*, const char*, u8, int, fopAc_ac_c**);
#if DEBUG #if DEBUG
@@ -185,8 +194,8 @@ public:
void setMsg(u32 msg) { mMsg = msg; } void setMsg(u32 msg) { mMsg = msg; }
bool checkEndFlow() { return (u32)field_0x26 == 1; } bool checkEndFlow() { return (u32)field_0x26 == 1; }
static queryFunc mQueryList[53]; static queryFunc mQueryList[DUSK_IF_ELSE(55, 53)];
static eventFunc mEventList[43]; static eventFunc mEventList[DUSK_IF_ELSE(46, 43)];
private: private:
/* 0x04 */ u8* mFlow_p; /* 0x04 */ u8* mFlow_p;
+5
View File
@@ -1416,6 +1416,11 @@ dStage_KeepDoorInfo* dStage_GetKeepDoorInfo();
dStage_KeepDoorInfo* dStage_GetRoomKeepDoorInfo(); dStage_KeepDoorInfo* dStage_GetRoomKeepDoorInfo();
void dStage_dt_c_fieldMapLoader(void* i_data, dStage_dt_c* i_stage); 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 #if DEBUG
void dStage_DebugDisp(); void dStage_DebugDisp();
#endif #endif
+7
View File
@@ -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); 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 } // namespace dusk
+44
View File
@@ -602,6 +602,50 @@ static const auto gameRegions = std::to_array({
MapEntry("Grotto 5", "D_SB09", { MapEntry("Grotto 5", "D_SB09", {
{4, {0, 1}}, {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", { RegionEntry("Misc", {
MapEntry("Title Screen / King Bulblin 1", "F_SP102", { MapEntry("Title Screen / King Bulblin 1", "F_SP102", {
+7
View File
@@ -1,6 +1,7 @@
#pragma once #pragma once
#include <array> #include <array>
#include <filesystem>
#include "dusk/config_var.hpp" #include "dusk/config_var.hpp"
#include "dusk/ui/controls.hpp" #include "dusk/ui/controls.hpp"
@@ -273,6 +274,9 @@ struct UserSettings {
struct { struct {
ConfigVar<std::string> isoPath; ConfigVar<std::string> isoPath;
ConfigVar<DiscVerificationState> isoVerification; ConfigVar<DiscVerificationState> isoVerification;
#if DUSK_TPHD
ConfigVar<std::string> hdContentPath;
#endif
ConfigVar<std::string> graphicsBackend; ConfigVar<std::string> graphicsBackend;
ConfigVar<bool> skipPreLaunchUI; ConfigVar<bool> skipPreLaunchUI;
ConfigVar<bool> showPipelineCompilation; ConfigVar<bool> showPipelineCompilation;
@@ -295,6 +299,9 @@ struct UserSettings {
UserSettings& getSettings(); UserSettings& getSettings();
std::filesystem::path tphd_content_path();
bool tphd_active();
void registerSettings(); void registerSettings();
// Transient settings // Transient settings
@@ -1761,6 +1761,16 @@ public:
virtual ~J3DIndBlockNull() {} 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 * @ingroup jsystem-j3d
* *
@@ -1793,6 +1803,10 @@ public:
virtual void setDither(u8 const*) {} virtual void setDither(u8 const*) {}
virtual void setDither(u8) {} virtual void setDither(u8) {}
virtual u8 getDither() const { return 0; } 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 u32 getFogOffset() const { return 0; }
virtual void setFogOffset(u32) {} virtual void setFogOffset(u32) {}
virtual ~J3DPEBlock() {} virtual ~J3DPEBlock() {}
@@ -1956,12 +1970,25 @@ public:
virtual void setFogOffset(u32 fogOffset) { mFogOffset = fogOffset; } virtual void setFogOffset(u32 fogOffset) { mFogOffset = fogOffset; }
virtual ~J3DPEBlockFull() {} virtual ~J3DPEBlockFull() {}
#ifdef DUSK_TPHD
virtual void setPolygonOffset(const PolygonOffset& offset) {
mPolygonOffset = offset;
}
virtual PolygonOffset* getPolygonOffset() {
return &mPolygonOffset;
}
#endif
/* 0x04 */ J3DFog mFog; /* 0x04 */ J3DFog mFog;
/* 0x30 */ J3DAlphaComp mAlphaComp; /* 0x30 */ J3DAlphaComp mAlphaComp;
/* 0x34 */ J3DBlend mBlend; /* 0x34 */ J3DBlend mBlend;
/* 0x38 */ J3DZMode mZMode; /* 0x38 */ J3DZMode mZMode;
/* 0x3A */ u8 mZCompLoc; /* 0x3A */ u8 mZCompLoc;
/* 0x3B */ u8 mDither; /* 0x3B */ u8 mDither;
#ifdef DUSK_TPHD
PolygonOffset mPolygonOffset;
#endif
/* 0x3C */ u32 mFogOffset; /* 0x3C */ u32 mFogOffset;
}; // Size: 0x40 }; // Size: 0x40
@@ -46,6 +46,13 @@ struct J3DMaterialInitData {
/* 0x14A */ BE(u16) mNBTScaleIdx; /* 0x14A */ BE(u16) mNBTScaleIdx;
}; // size 0x14C }; // size 0x14C
#ifdef DUSK_TPHD
struct J3DMaterialInitData_MAT4 : public J3DMaterialInitData {
/* 0x14C */ BE(u16) mPolygonOffsetIdx;
}; // size 0x14E
#endif
/** /**
* @ingroup jsystem-j3d * @ingroup jsystem-j3d
* *
@@ -143,10 +150,29 @@ public:
J3DNBTScale newNBTScale(int) const; J3DNBTScale newNBTScale(int) const;
u16 getMaterialID(int idx) const { return mpMaterialID[idx]; } 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; } 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; /* 0x00 */ u16 mMaterialNum;
#if DUSK_TPHD
/* 0x04 */ void* mpMaterialInitData;
#else
/* 0x04 */ J3DMaterialInitData* mpMaterialInitData; /* 0x04 */ J3DMaterialInitData* mpMaterialInitData;
#endif
/* 0x08 */ BE(u16)* mpMaterialID; /* 0x08 */ BE(u16)* mpMaterialID;
/* 0x0C */ J3DIndInitData* mpIndInitData; /* 0x0C */ J3DIndInitData* mpIndInitData;
/* 0x10 */ GXColor* mpMatColor; /* 0x10 */ GXColor* mpMatColor;
@@ -175,6 +201,9 @@ public:
/* 0x6C */ u8* mpZCompLoc; /* 0x6C */ u8* mpZCompLoc;
/* 0x70 */ u8* mpDither; /* 0x70 */ u8* mpDither;
/* 0x74 */ J3DNBTScaleInfo* mpNBTScaleInfo; /* 0x74 */ J3DNBTScaleInfo* mpNBTScaleInfo;
#ifdef DUSK_TPHD
PolygonOffset* mpPolygonOffsets;
#endif
/* 0x78 */ J3DDisplayListInit* mpDisplayListInit; /* 0x78 */ J3DDisplayListInit* mpDisplayListInit;
/* 0x7C */ J3DPatchingInfo* mpPatchingInfo; /* 0x7C */ J3DPatchingInfo* mpPatchingInfo;
/* 0x80 */ J3DCurrentMtxInfo* mpCurrentMtxInfo; /* 0x80 */ J3DCurrentMtxInfo* mpCurrentMtxInfo;
@@ -169,6 +169,12 @@ struct J3DMaterialBlock_v21 : public J3DModelBlock {
/* 0x74 */ OFFSET_PTR_V0 mpNBTScaleInfo; /* 0x74 */ OFFSET_PTR_V0 mpNBTScaleInfo;
}; };
#ifdef DUSK_TPHD
struct J3DMaterialBlock_MAT4 : public J3DMaterialBlock {
/* 0x84 */ OFFSET_PTR_V0 mpPolygonOffsets;
};
#endif
/** /**
* @ingroup jsystem-j3d * @ingroup jsystem-j3d
* *
@@ -7,6 +7,9 @@
#include "JSystem/J3DGraphBase/J3DMaterial.h" #include "JSystem/J3DGraphBase/J3DMaterial.h"
#include "JSystem/JMath/JMath.h" #include "JSystem/JMath/JMath.h"
#include "m_Do/m_Do_mtx.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) { void J3DMtxCalcJ3DSysInitBasic::init(Vec const& scale, Mtx const& mtx) {
J3DSys::mCurrentS = scale; J3DSys::mCurrentS = scale;
@@ -178,7 +181,23 @@ void J3DJoint::entryIn() {
matPacket->setMaterialAnmID(mesh->getMaterialAnm()); matPacket->setMaterialAnmID(mesh->getMaterialAnm());
matPacket->setShapePacket(shapePacket); matPacket->setShapePacket(shapePacket);
bool isDrawModeOpaTexEdge = mesh->isDrawModeOpaTexEdge() == FALSE; 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)); u8 r24 = matPacket->entry(j3dSys.getDrawBuffer(isDrawModeOpaTexEdge));
#endif
if (r24) { if (r24) {
j3dSys.setMatPacket(matPacket); j3dSys.setMatPacket(matPacket);
J3DDrawBuffer::entryNum++; J3DDrawBuffer::entryNum++;
@@ -230,6 +230,13 @@ void J3DMatPacket::draw() {
#endif #endif
packet->getShape()->loadPreDrawSetting(); 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) { while (packet != NULL) {
if (packet->getDisplayListObj() != NULL) { if (packet->getDisplayListObj() != NULL) {
packet->getDisplayListObj()->callDL(); packet->getDisplayListObj()->callDL();
@@ -12,6 +12,9 @@
#include "dusk/logging.h" #include "dusk/logging.h"
J3DMaterialFactory::J3DMaterialFactory(J3DMaterialBlock const& i_block) { 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; mMaterialNum = i_block.mMaterialNum;
mpMaterialInitData = JSUConvertOffsetToPtr<J3DMaterialInitData>(&i_block, i_block.mpMaterialInitData); mpMaterialInitData = JSUConvertOffsetToPtr<J3DMaterialInitData>(&i_block, i_block.mpMaterialInitData);
mpMaterialID = JSUConvertOffsetToPtr<BE(u16)>(&i_block, i_block.mpMaterialID); 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); mpZCompLoc = JSUConvertOffsetToPtr<u8>(&i_block, i_block.mpZCompLoc);
mpDither = JSUConvertOffsetToPtr<u8>(&i_block, i_block.mpDither); mpDither = JSUConvertOffsetToPtr<u8>(&i_block, i_block.mpDither);
mpNBTScaleInfo = JSUConvertOffsetToPtr<J3DNBTScaleInfo>(&i_block, i_block.mpNBTScaleInfo); 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; mpDisplayListInit = NULL;
mpPatchingInfo = NULL; mpPatchingInfo = NULL;
mpCurrentMtxInfo = NULL; mpCurrentMtxInfo = NULL;
@@ -74,7 +82,11 @@ u16 J3DMaterialFactory::countUniqueMaterials() {
} }
u32 J3DMaterialFactory::countTexGens(int i_idx) const { 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]]; J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
if (mtl_init_data->mTexGenNumIdx != 0xff) { if (mtl_init_data->mTexGenNumIdx != 0xff) {
return mpTexGenNum[mtl_init_data->mTexGenNumIdx]; return mpTexGenNum[mtl_init_data->mTexGenNumIdx];
} }
@@ -82,7 +94,11 @@ u32 J3DMaterialFactory::countTexGens(int i_idx) const {
} }
u32 J3DMaterialFactory::countStages(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]]; J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
u32 count1 = 0; u32 count1 = 0;
u32 count2 = 0; u32 count2 = 0;
if (mtl_init_data->mTevStageNumIdx != 0xff) { 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->setZMode(newZMode(i_idx));
i_material->mPEBlock->setZCompLoc(newZCompLoc(i_idx)); i_material->mPEBlock->setZCompLoc(newZCompLoc(i_idx));
i_material->mPEBlock->setDither(newDither(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)); i_material->mTevBlock->setTevStageNum(newTevStageNum(i_idx));
for (u8 i = 0; i < tex_num; i++) { for (u8 i = 0; i < tex_num; i++) {
i_material->mTevBlock->setTexNo(i, newTexNo(i_idx, 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)); i_material->mTevBlock->setTevOrder(i, newTevOrder(i_idx, i));
} }
for (u8 i = 0; i < tev_stage_num_max; 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]]; J3DMaterialInitData* material_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
i_material->mTevBlock->setTevStage(i, newTevStage(i_idx, i)); i_material->mTevBlock->setTevStage(i, newTevStage(i_idx, i));
if (material_init_data->mTevSwapModeIdx[i] != 0xffff) { if (material_init_data->mTevSwapModeIdx[i] != 0xffff) {
i_material->mTevBlock->getTevStage(i)->setTexSel( i_material->mTevBlock->getTevStage(i)->setTexSel(
@@ -200,7 +223,11 @@ J3DMaterial* J3DMaterialFactory::createNormalMaterial(J3DMaterial* i_material, i
for (u8 i = 0; i < 8; i++) { for (u8 i = 0; i < 8; i++) {
i_material->mTexGenBlock->setTexMtx(i, newTexMtx(i_idx, 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++) { for (u8 i = 0; i < tev_stage_num_max; i++) {
if (material_init_data->mTevKColorSel[i] != 0xff) { if (material_init_data->mTevKColorSel[i] != 0xff) {
i_material->mTevBlock->setTevKColorSel(i, material_init_data->mTevKColorSel[i]); 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)); i_material->mTevBlock->setTevColor(i, newTevColor(i_idx, i));
} }
for (u8 i = 0; i < tev_stage_num; 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]]; J3DMaterialInitData* material_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
i_material->mTevBlock->setTevStage(i, newTevStage(i_idx, i)); i_material->mTevBlock->setTevStage(i, newTevStage(i_idx, i));
if (material_init_data->mTevSwapModeIdx[i] != 0xffff) { if (material_init_data->mTevSwapModeIdx[i] != 0xffff) {
i_material->mTevBlock->getTevStage(i)->setTexSel( i_material->mTevBlock->getTevStage(i)->setTexSel(
@@ -282,7 +313,11 @@ J3DMaterial* J3DMaterialFactory::createPatchedMaterial(J3DMaterial* i_material,
mpTevSwapModeInfo[material_init_data->mTevSwapModeIdx[i]].mRasSel); 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++) { for (u8 i = 0; i < tev_stage_num; i++) {
if (init_data->mTevKColorSel[i] != 0xff) { if (init_data->mTevKColorSel[i] != 0xff) {
i_material->mTevBlock->setTevKColorSel(i, init_data->mTevKColorSel[i]); 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::calcSizeTevBlock((u16)tev_stage_num_max);
size += J3DMaterial::calcSizeIndBlock(ind_flag); size += J3DMaterial::calcSizeIndBlock(ind_flag);
size += J3DMaterial::calcSizePEBlock(pe_flag, getMaterialMode(i_idx)); 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]]; J3DMaterialInitData* init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
for (u32 i = 0; i < 8; i++) { for (u32 i = 0; i < 8; i++) {
if (init_data->mTexMtxIdx[i] != 0xffff) { if (init_data->mTexMtxIdx[i] != 0xffff) {
size += sizeof(J3DTexMtx); size += sizeof(J3DTexMtx);
@@ -444,7 +483,11 @@ u32 J3DMaterialFactory::calcSizePatchedMaterial(J3DMaterial* i_material, int i_i
size += sizeof(J3DTevBlockPatched); size += sizeof(J3DTevBlockPatched);
size += J3DMaterial::calcSizeIndBlock(ind_flag); size += J3DMaterial::calcSizeIndBlock(ind_flag);
size += J3DMaterial::calcSizePEBlock(0x10000000, getMaterialMode(i_idx)); size += J3DMaterial::calcSizePEBlock(0x10000000, getMaterialMode(i_idx));
#ifdef DUSK_TPHD
J3DMaterialInitData* init_data = getMatInitData(i_idx);
#else
J3DMaterialInitData* init_data = &mpMaterialInitData[mpMaterialID[i_idx]]; J3DMaterialInitData* init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
for (u32 i = 0; i < 8; i++) { for (u32 i = 0; i < 8; i++) {
if (init_data->mTexMtxIdx[i] != 0xffff) { if (init_data->mTexMtxIdx[i] != 0xffff) {
size += sizeof(J3DTexMtx); size += sizeof(J3DTexMtx);
@@ -474,7 +517,11 @@ J3DGXColor J3DMaterialFactory::newMatColor(int i_idx, int i_no) const {
#else #else
J3DGXColor dflt = GXColor{0xff, 0xff, 0xff, 0xff}; J3DGXColor dflt = GXColor{0xff, 0xff, 0xff, 0xff};
#endif #endif
#ifdef DUSK_TPHD
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
#else
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]]; J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
if (mtl_init_data->mMatColorIdx[i_no] != 0xffff) { if (mtl_init_data->mMatColorIdx[i_no] != 0xffff) {
return (GXColor) mpMatColor[mtl_init_data->mMatColorIdx[i_no]]; return (GXColor) mpMatColor[mtl_init_data->mMatColorIdx[i_no]];
} else { } else {
@@ -483,7 +530,11 @@ J3DGXColor J3DMaterialFactory::newMatColor(int i_idx, int i_no) const {
} }
const u8 J3DMaterialFactory::newColorChanNum(int i_idx) 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]]; J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
if (mtl_init_data->mColorChanNumIdx != 0xff) { if (mtl_init_data->mColorChanNumIdx != 0xff) {
return mpColorChanNum[mtl_init_data->mColorChanNumIdx]; return mpColorChanNum[mtl_init_data->mColorChanNumIdx];
} else { } else {
@@ -493,7 +544,11 @@ const u8 J3DMaterialFactory::newColorChanNum(int i_idx) const {
J3DColorChan J3DMaterialFactory::newColorChan(int i_idx, int i_no) const { J3DColorChan J3DMaterialFactory::newColorChan(int i_idx, int i_no) const {
u32 r29 = 0; u32 r29 = 0;
#ifdef DUSK_TPHD
J3DMaterialInitData* init_data = getMatInitData(i_idx);
#else
J3DMaterialInitData* init_data = &mpMaterialInitData[mpMaterialID[i_idx]]; J3DMaterialInitData* init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
if (init_data->mColorChanIdx[i_no] != 0xffff) { if (init_data->mColorChanIdx[i_no] != 0xffff) {
return J3DColorChan(mpColorChanInfo[init_data->mColorChanIdx[i_no]]); return J3DColorChan(mpColorChanInfo[init_data->mColorChanIdx[i_no]]);
} else { } else {
@@ -507,7 +562,11 @@ J3DGXColor J3DMaterialFactory::newAmbColor(int i_idx, int i_no) const {
#else #else
J3DGXColor dflt = GXColor{0x32, 0x32, 0x32, 0x32}; J3DGXColor dflt = GXColor{0x32, 0x32, 0x32, 0x32};
#endif #endif
#ifdef DUSK_TPHD
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
#else
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]]; J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
if (mtl_init_data->mAmbColorIdx[i_no] != 0xffff) { if (mtl_init_data->mAmbColorIdx[i_no] != 0xffff) {
return (GXColor) mpAmbColor[mtl_init_data->mAmbColorIdx[i_no]]; return (GXColor) mpAmbColor[mtl_init_data->mAmbColorIdx[i_no]];
} else { } else {
@@ -517,7 +576,11 @@ J3DGXColor J3DMaterialFactory::newAmbColor(int i_idx, int i_no) const {
u32 J3DMaterialFactory::newTexGenNum(int i_idx) const { u32 J3DMaterialFactory::newTexGenNum(int i_idx) const {
u32 r30 = 0; u32 r30 = 0;
#ifdef DUSK_TPHD
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
#else
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]]; J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
if (mtl_init_data->mTexGenNumIdx != 0xff) { if (mtl_init_data->mTexGenNumIdx != 0xff) {
return mpTexGenNum[mtl_init_data->mTexGenNumIdx]; return mpTexGenNum[mtl_init_data->mTexGenNumIdx];
} else { } else {
@@ -526,7 +589,11 @@ u32 J3DMaterialFactory::newTexGenNum(int i_idx) const {
} }
J3DTexCoord J3DMaterialFactory::newTexCoord(int i_idx, int i_no) 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]]; J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
if (mtl_init_data->mTexCoordIdx[i_no] != 0xffff) { if (mtl_init_data->mTexCoordIdx[i_no] != 0xffff) {
return J3DTexCoord(mpTexCoordInfo[mtl_init_data->mTexCoordIdx[i_no]]); return J3DTexCoord(mpTexCoordInfo[mtl_init_data->mTexCoordIdx[i_no]]);
} else { } 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* J3DMaterialFactory::newTexMtx(int i_idx, int i_no) const {
J3DTexMtx* tex_mtx = NULL; J3DTexMtx* tex_mtx = NULL;
#ifdef DUSK_TPHD
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
#else
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]]; J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
if (mtl_init_data->mTexMtxIdx[i_no] != 0xffff) { if (mtl_init_data->mTexMtxIdx[i_no] != 0xffff) {
#if TARGET_LITTLE_ENDIAN #if TARGET_LITTLE_ENDIAN
auto tex_mtx_info = mpTexMtxInfo[mtl_init_data->mTexMtxIdx[i_no]]; 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 { u8 J3DMaterialFactory::newCullMode(int i_idx) const {
u32 r30 = 0; u32 r30 = 0;
#ifdef DUSK_TPHD
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
#else
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]]; J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
if (mtl_init_data->mCullModeIdx != 0xff) { if (mtl_init_data->mCullModeIdx != 0xff) {
return mpCullMode[mtl_init_data->mCullModeIdx]; return mpCullMode[mtl_init_data->mCullModeIdx];
} else { } else {
@@ -567,7 +642,11 @@ u8 J3DMaterialFactory::newCullMode(int i_idx) const {
} }
u16 J3DMaterialFactory::newTexNo(int i_idx, int i_no) 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]]; J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
if (mtl_init_data->mTexNoIdx[i_no] != 0xffff) { if (mtl_init_data->mTexNoIdx[i_no] != 0xffff) {
return mpTexNo[mtl_init_data->mTexNoIdx[i_no]]; return mpTexNo[mtl_init_data->mTexNoIdx[i_no]];
} else { } 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 { 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]]; J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
if (mtl_init_data->mTevOrderIdx[i_no] != 0xffff) { if (mtl_init_data->mTevOrderIdx[i_no] != 0xffff) {
return J3DTevOrder(mpTevOrderInfo[mtl_init_data->mTevOrderIdx[i_no]]); return J3DTevOrder(mpTevOrderInfo[mtl_init_data->mTevOrderIdx[i_no]]);
} else { } 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 { J3DGXColorS10 J3DMaterialFactory::newTevColor(int i_idx, int i_no) const {
GXColorS10 _dflt = {0, 0, 0, 0}; GXColorS10 _dflt = {0, 0, 0, 0};
J3DGXColorS10 dflt = _dflt; J3DGXColorS10 dflt = _dflt;
#ifdef DUSK_TPHD
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
#else
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]]; J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
if (mtl_init_data->mTevColorIdx[i_no] != 0xffff) { if (mtl_init_data->mTevColorIdx[i_no] != 0xffff) {
return (GXColorS10) mpTevColor[mtl_init_data->mTevColorIdx[i_no]]; return (GXColorS10) mpTevColor[mtl_init_data->mTevColorIdx[i_no]];
} else { } else {
@@ -601,7 +688,11 @@ J3DGXColor J3DMaterialFactory::newTevKColor(int i_idx, int i_no) const {
#else #else
J3DGXColor dflt = GXColor{0xff, 0xff, 0xff, 0xff}; J3DGXColor dflt = GXColor{0xff, 0xff, 0xff, 0xff};
#endif #endif
#ifdef DUSK_TPHD
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
#else
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]]; J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
if (mtl_init_data->mTevKColorIdx[i_no] != 0xffff) { if (mtl_init_data->mTevKColorIdx[i_no] != 0xffff) {
return (GXColor) mpTevKColor[mtl_init_data->mTevKColorIdx[i_no]]; return (GXColor) mpTevKColor[mtl_init_data->mTevKColorIdx[i_no]];
} else { } else {
@@ -610,7 +701,11 @@ J3DGXColor J3DMaterialFactory::newTevKColor(int i_idx, int i_no) const {
} }
const u8 J3DMaterialFactory::newTevStageNum(int i_idx) 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]]; J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
if (mtl_init_data->mTevStageNumIdx != 0xff) { if (mtl_init_data->mTevStageNumIdx != 0xff) {
return mpTevStageNum[mtl_init_data->mTevStageNumIdx]; return mpTevStageNum[mtl_init_data->mTevStageNumIdx];
} else { } else {
@@ -619,7 +714,11 @@ const u8 J3DMaterialFactory::newTevStageNum(int i_idx) const {
} }
J3DTevStage J3DMaterialFactory::newTevStage(int i_idx, int i_no) 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]]; J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
if (mtl_init_data->mTevStageIdx[i_no] != 0xffff) { if (mtl_init_data->mTevStageIdx[i_no] != 0xffff) {
return J3DTevStage(mpTevStageInfo[mtl_init_data->mTevStageIdx[i_no]]); return J3DTevStage(mpTevStageInfo[mtl_init_data->mTevStageIdx[i_no]]);
} else { } 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 { 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]]; J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
if (mtl_init_data->mTevSwapModeTableIdx[i_no] != 0xffff) { if (mtl_init_data->mTevSwapModeTableIdx[i_no] != 0xffff) {
return J3DTevSwapModeTable(mpTevSwapModeTableInfo[mtl_init_data->mTevSwapModeTableIdx[i_no]]); return J3DTevSwapModeTable(mpTevSwapModeTableInfo[mtl_init_data->mTevSwapModeTableIdx[i_no]]);
} else { } else {
@@ -689,7 +792,11 @@ J3DIndTexCoordScale J3DMaterialFactory::newIndTexCoordScale(int i_idx, int i_no)
J3DFog J3DMaterialFactory::newFog(int i_idx) const { J3DFog J3DMaterialFactory::newFog(int i_idx) const {
J3DFog fog; J3DFog fog;
#ifdef DUSK_TPHD
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
#else
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]]; J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
if (mtl_init_data->mFogIdx != 0xffff) { if (mtl_init_data->mFogIdx != 0xffff) {
#if TARGET_LITTLE_ENDIAN #if TARGET_LITTLE_ENDIAN
J3DFogInfo fogInfo = mpFogInfo[mtl_init_data->mFogIdx]; 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 { 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]]; J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
if (mtl_init_data->mAlphaCompIdx != 0xffff) { if (mtl_init_data->mAlphaCompIdx != 0xffff) {
return J3DAlphaComp(mpAlphaCompInfo[mtl_init_data->mAlphaCompIdx]); return J3DAlphaComp(mpAlphaCompInfo[mtl_init_data->mAlphaCompIdx]);
} else { } else {
@@ -718,7 +829,11 @@ J3DAlphaComp J3DMaterialFactory::newAlphaComp(int i_idx) const {
} }
J3DBlend J3DMaterialFactory::newBlend(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]]; J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
if (mtl_init_data->mBlendIdx != 0xffff) { if (mtl_init_data->mBlendIdx != 0xffff) {
return J3DBlend(mpBlendInfo[mtl_init_data->mBlendIdx]); return J3DBlend(mpBlendInfo[mtl_init_data->mBlendIdx]);
} else { } else {
@@ -728,7 +843,11 @@ J3DBlend J3DMaterialFactory::newBlend(int i_idx) const {
J3DZMode J3DMaterialFactory::newZMode(int i_idx) const { J3DZMode J3DMaterialFactory::newZMode(int i_idx) const {
u32 r29 = 0; u32 r29 = 0;
#ifdef DUSK_TPHD
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
#else
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]]; J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
if (mtl_init_data->mZModeIdx != 0xff) { if (mtl_init_data->mZModeIdx != 0xff) {
return J3DZMode(mpZModeInfo[mtl_init_data->mZModeIdx]); return J3DZMode(mpZModeInfo[mtl_init_data->mZModeIdx]);
} else { } else {
@@ -737,7 +856,11 @@ J3DZMode J3DMaterialFactory::newZMode(int i_idx) const {
} }
const u8 J3DMaterialFactory::newZCompLoc(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]]; J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
if (mtl_init_data->mZCompLocIdx != 0xff){ if (mtl_init_data->mZCompLocIdx != 0xff){
return mpZCompLoc[mtl_init_data->mZCompLocIdx]; return mpZCompLoc[mtl_init_data->mZCompLocIdx];
} else { } else {
@@ -746,7 +869,11 @@ const u8 J3DMaterialFactory::newZCompLoc(int i_idx) const {
} }
const u8 J3DMaterialFactory::newDither(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]]; J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
if (mtl_init_data->mDitherIdx != 0xff){ if (mtl_init_data->mDitherIdx != 0xff){
return mpDither[mtl_init_data->mDitherIdx]; return mpDither[mtl_init_data->mDitherIdx];
} else { } 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 J3DMaterialFactory::newNBTScale(int i_idx) const {
J3DNBTScale dflt(j3dDefaultNBTScaleInfo); J3DNBTScale dflt(j3dDefaultNBTScaleInfo);
#ifdef DUSK_TPHD
J3DMaterialInitData* mtl_init_data = getMatInitData(i_idx);
#else
J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]]; J3DMaterialInitData* mtl_init_data = &mpMaterialInitData[mpMaterialID[i_idx]];
#endif
if (mtl_init_data->mNBTScaleIdx != 0xffff) { if (mtl_init_data->mNBTScaleIdx != 0xffff) {
return J3DNBTScale(mpNBTScaleInfo[mtl_init_data->mNBTScaleIdx]); return J3DNBTScale(mpNBTScaleInfo[mtl_init_data->mNBTScaleIdx]);
} else { } else {
@@ -103,6 +103,9 @@ J3DModelData* J3DModelLoader::load(void const* i_data, u32 i_flags) {
readJoint((J3DJointBlock*)block); readJoint((J3DJointBlock*)block);
break; break;
case 'MAT3': case 'MAT3':
#if DUSK_TPHD
case 'MAT4':
#endif
readMaterial((J3DMaterialBlock*)block, (s32)i_flags); readMaterial((J3DMaterialBlock*)block, (s32)i_flags);
break; break;
case 'MAT2': case 'MAT2':
@@ -147,6 +150,9 @@ J3DMaterialTable* J3DModelLoader::loadMaterialTable(void const* i_data) {
for (u32 block_no = 0; block_no < data->mBlockNum; block_no++) { for (u32 block_no = 0; block_no < data->mBlockNum; block_no++) {
switch (block->mBlockType) { switch (block->mBlockType) {
case 'MAT3': case 'MAT3':
#if DUSK_TPHD
case 'MAT4':
#endif
readMaterialTable((J3DMaterialBlock*)block, flags); readMaterialTable((J3DMaterialBlock*)block, flags);
break; break;
case 'MAT2': case 'MAT2':
@@ -212,6 +218,9 @@ J3DModelData* J3DModelLoader::loadBinaryDisplayList(void const* i_data, u32 i_fl
modifyMaterial(i_flags); modifyMaterial(i_flags);
break; break;
case 'MAT3': case 'MAT3':
#if DUSK_TPHD
case 'MAT4':
#endif
flags = 0x50100000; flags = 0x50100000;
flags |= (i_flags & 0x3000000); flags |= (i_flags & 0x3000000);
mpMaterialBlock = (J3DMaterialBlock*)block; mpMaterialBlock = (J3DMaterialBlock*)block;
@@ -308,8 +317,22 @@ static GXVtxAttrFmtList getFmt(GXVtxAttrFmtList* i_fmtList, GXAttr i_attr) {
return *i_fmtList; 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!"); OSPanic(__FILE__, __LINE__, "Unable to find vertex attribute format!");
#endif
} }
#endif #endif
@@ -16,7 +16,7 @@ u16 J3DModelLoader::countMaterialNum(const void* stream) {
const J3DModelBlock* block = header->mBlocks; const J3DModelBlock* block = header->mBlocks;
for (int i = 0; i < header->mBlockNum; i++) 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; const J3DMaterialBlock* materialBlock = (const J3DMaterialBlock*)block;
return materialBlock->mMaterialNum; return materialBlock->mMaterialNum;
} }
@@ -45,6 +45,7 @@ u32 J3DModelLoader::calcLoadSize(void const* stream, u32 flags_) {
size += calcSizeJoint((const J3DJointBlock*)nextBlock); size += calcSizeJoint((const J3DJointBlock*)nextBlock);
break; break;
case 'MAT3': case 'MAT3':
case 'MAT4':
size += calcSizeMaterial((const J3DMaterialBlock*)nextBlock, flags); size += calcSizeMaterial((const J3DMaterialBlock*)nextBlock, flags);
break; break;
case 'SHP1': case 'SHP1':
@@ -86,6 +87,7 @@ u32 J3DModelLoader::calcLoadMaterialTableSize(const void* stream) {
for (u32 i = 0; i < header->mBlockNum; i++) { for (u32 i = 0; i < header->mBlockNum; i++) {
switch (nextBlock->mBlockType) { switch (nextBlock->mBlockType) {
case 'MAT3': case 'MAT3':
case 'MAT4':
size += calcSizeMaterialTable((const J3DMaterialBlock*)nextBlock, flags); size += calcSizeMaterialTable((const J3DMaterialBlock*)nextBlock, flags);
break; break;
case 'TEX1': case 'TEX1':
@@ -135,7 +137,8 @@ u32 J3DModelLoader::calcLoadBinaryDisplayListSize(const void* stream, u32 flags)
case 'MDL3': case 'MDL3':
size += calcSizeMaterialDL((const J3DMaterialDLBlock*)nextBlock, flags); size += calcSizeMaterialDL((const J3DMaterialDLBlock*)nextBlock, flags);
break; break;
case 'MAT3': { case 'MAT3':
case 'MAT4': {
u32 flags2 = (J3DMLF_21 | J3DMLF_Material_PE_Full | J3DMLF_Material_Color_LightOn); u32 flags2 = (J3DMLF_21 | J3DMLF_Material_PE_Full | J3DMLF_Material_Color_LightOn);
flags2 |= (u32)flags & (J3DMLF_Material_UseIndirect | J3DMLF_26); flags2 |= (u32)flags & (J3DMLF_Material_UseIndirect | J3DMLF_26);
mpMaterialBlock = (const J3DMaterialBlock*)nextBlock; mpMaterialBlock = (const J3DMaterialBlock*)nextBlock;
@@ -9,6 +9,24 @@
#include "JSystem/JKernel/JKRMemArchive.h" #include "JSystem/JKernel/JKRMemArchive.h"
#include "JSystem/JUtility/JUTAssert.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) { JKRArchive* JKRArchive::check_mount_already(s32 entryNum, JKRHeap* heap) {
if (heap == NULL) { if (heap == NULL) {
heap = JKRGetCurrentHeap(); heap = JKRGetCurrentHeap();
@@ -196,6 +214,9 @@ u32 JKRArchive::readResource(void* buffer, u32 bufferSize, u32 type, const char*
if (fileEntry) { if (fileEntry) {
u32 resourceSize; u32 resourceSize;
fetchResource(buffer, bufferSize, fileEntry, &resourceSize); fetchResource(buffer, bufferSize, fileEntry, &resourceSize);
#if DUSK_TPHD
register_copied_hd_resource(this, fileEntry, buffer, resourceSize);
#endif
return resourceSize; return resourceSize;
} }
@@ -214,6 +235,9 @@ u32 JKRArchive::readResource(void* buffer, u32 bufferSize, const char* path) {
if (fileEntry) { if (fileEntry) {
u32 resourceSize; u32 resourceSize;
fetchResource(buffer, bufferSize, fileEntry, &resourceSize); fetchResource(buffer, bufferSize, fileEntry, &resourceSize);
#if DUSK_TPHD
register_copied_hd_resource(this, fileEntry, buffer, resourceSize);
#endif
return resourceSize; return resourceSize;
} }
@@ -226,6 +250,9 @@ u32 JKRArchive::readIdxResource(void* buffer, u32 bufferSize, u32 index) {
if (fileEntry) { if (fileEntry) {
u32 resourceSize; u32 resourceSize;
fetchResource(buffer, bufferSize, fileEntry, &resourceSize); fetchResource(buffer, bufferSize, fileEntry, &resourceSize);
#if DUSK_TPHD
register_copied_hd_resource(this, fileEntry, buffer, resourceSize);
#endif
return resourceSize; return resourceSize;
} }
@@ -238,6 +265,9 @@ u32 JKRArchive::readResource(void* buffer, u32 bufferSize, u16 id) {
if (fileEntry) { if (fileEntry) {
u32 resourceSize; u32 resourceSize;
fetchResource(buffer, bufferSize, fileEntry, &resourceSize); fetchResource(buffer, bufferSize, fileEntry, &resourceSize);
#if DUSK_TPHD
register_copied_hd_resource(this, fileEntry, buffer, resourceSize);
#endif
return resourceSize; return resourceSize;
} }
@@ -10,6 +10,10 @@
#include <stdint.h> #include <stdint.h>
#include "os_report.h" #include "os_report.h"
#if DUSK_TPHD
#include "dusk/tphd/HdAssetLayer.hpp"
#endif
JKRMemArchive::JKRMemArchive(s32 entryNum, JKRArchive::EMountDirection mountDirection) JKRMemArchive::JKRMemArchive(s32 entryNum, JKRArchive::EMountDirection mountDirection)
: JKRArchive(entryNum, MOUNT_MEM) { : JKRArchive(entryNum, MOUNT_MEM) {
mIsMounted = false; mIsMounted = false;
@@ -67,8 +71,13 @@ bool JKRMemArchive::open(s32 entryNum, JKRArchive::EMountDirection mountDirectio
mIsOpen = false; mIsOpen = false;
mMountDirection = mountDirection; mMountDirection = mountDirection;
#ifdef TARGET_PC
u32 loadedSize = 0;
#endif
if (mMountDirection == JKRArchive::MOUNT_DIRECTION_HEAD) { if (mMountDirection == JKRArchive::MOUNT_DIRECTION_HEAD) {
#ifndef TARGET_PC
u32 loadedSize; u32 loadedSize;
#endif
mArcHeader = (SArcHeader *)JKRDvdToMainRam( mArcHeader = (SArcHeader *)JKRDvdToMainRam(
entryNum, NULL, EXPAND_SWITCH_UNKNOWN1, 0, mHeap, JKRDvdRipper::ALLOC_DIRECTION_FORWARD, entryNum, NULL, EXPAND_SWITCH_UNKNOWN1, 0, mHeap, JKRDvdRipper::ALLOC_DIRECTION_FORWARD,
0, (int *)&mCompression, &loadedSize); 0, (int *)&mCompression, &loadedSize);
@@ -77,7 +86,9 @@ bool JKRMemArchive::open(s32 entryNum, JKRArchive::EMountDirection mountDirectio
} }
} }
else { else {
#ifndef TARGET_PC
u32 loadedSize; u32 loadedSize;
#endif
mArcHeader = (SArcHeader *)JKRDvdToMainRam( mArcHeader = (SArcHeader *)JKRDvdToMainRam(
entryNum, NULL, EXPAND_SWITCH_UNKNOWN1, 0, mHeap, entryNum, NULL, EXPAND_SWITCH_UNKNOWN1, 0, mHeap,
JKRDvdRipper::ALLOC_DIRECTION_BACKWARD, 0, (int *)&mCompression, &loadedSize); JKRDvdRipper::ALLOC_DIRECTION_BACKWARD, 0, (int *)&mCompression, &loadedSize);
@@ -90,6 +101,9 @@ bool JKRMemArchive::open(s32 entryNum, JKRArchive::EMountDirection mountDirectio
mMountMode = UNKNOWN_MOUNT_MODE; mMountMode = UNKNOWN_MOUNT_MODE;
} }
else { else {
#if DUSK_TPHD
dusk::tphd::register_mounted_hd_archive(entryNum, mArcHeader, loadedSize);
#endif
JUT_ASSERT(438, mArcHeader->signature == 'RARC'); JUT_ASSERT(438, mArcHeader->signature == 'RARC');
mArcInfoBlock = (SArcDataInfo *)((u8 *)mArcHeader + mArcHeader->header_length); mArcInfoBlock = (SArcDataInfo *)((u8 *)mArcHeader + mArcHeader->header_length);
mNodes = (SDIDirEntry *)((u8 *)&mArcInfoBlock->num_nodes + mArcInfoBlock->node_offset); mNodes = (SDIDirEntry *)((u8 *)&mArcInfoBlock->num_nodes + mArcInfoBlock->node_offset);
+3
View File
@@ -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_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_SB02", "D_SB03", "D_SB04", "D_SB05", "D_SB06", "D_SB07", "D_SB08", "D_SB09",
"D_SB10", "D_SB10",
#if TARGET_PC
"D_SB11",
#endif
}; };
#endif /* SPOTNAME_H */ #endif /* SPOTNAME_H */
+23 -1
View File
@@ -1603,13 +1603,35 @@ void Z2SceneMgr::setSceneName(char* spot, s32 room, s32 layer) {
bgm_wave1 = 0x45; bgm_wave1 = 0x45;
} }
break; 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) */ /*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]) 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) */ /* 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]) && !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; bgm_wave1 = 0x36;
if (spotNo == Z2SCENE_CASTLE_TOWN_SHOPS && room == 5) { if (spotNo == Z2SCENE_CASTLE_TOWN_SHOPS && room == 5) {
+6
View File
@@ -583,6 +583,12 @@ void Z2SeqMgr::bgmStreamPlay() {
} }
} }
#if TARGET_PC
if (dusk::tphd_active()) {
return;
}
#endif
#if !PLATFORM_SHIELD #if !PLATFORM_SHIELD
else if (getStreamBgmID() == 0x2000000) { else if (getStreamBgmID() == 0x2000000) {
if (mStreamBgmHandle) { if (mStreamBgmHandle) {
+33 -31
View File
@@ -5,51 +5,53 @@
#include "d/dolzel.h" // IWYU pragma: keep #include "d/dolzel.h" // IWYU pragma: keep
#include "d/actor/d_a_alink.h"
#include "JSystem/J2DGraph/J2DAnmLoader.h" #include "JSystem/J2DGraph/J2DAnmLoader.h"
#include "JSystem/J3DGraphBase/J3DDrawBuffer.h"
#include "JSystem/J3DGraphBase/J3DMaterial.h" #include "JSystem/J3DGraphBase/J3DMaterial.h"
#include "JSystem/J3DGraphLoader/J3DAnmLoader.h" #include "JSystem/J3DGraphLoader/J3DAnmLoader.h"
#include "JSystem/J3DGraphBase/J3DDrawBuffer.h"
#include "JSystem/JHostIO/JORServer.h" #include "JSystem/JHostIO/JORServer.h"
#include "JSystem/JKernel/JKRExpHeap.h" #include "JSystem/JKernel/JKRExpHeap.h"
#include "SSystem/SComponent/c_math.h" #include "SSystem/SComponent/c_math.h"
#include "d/d_item.h" #include "d/actor/d_a_alink.h"
#include "d/d_meter2_draw.h" #include "d/actor/d_a_b_mgn.h"
#include "d/d_pane_class.h" #include "d/actor/d_a_canoe.h"
#include "d/d_demo.h" #include "d/actor/d_a_cow.h"
#include "d/actor/d_a_crod.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_mg_rod.h"
#include "d/actor/d_a_midna.h" #include "d/actor/d_a_midna.h"
#include "d/actor/d_a_mirror.h" #include "d/actor/d_a_mirror.h"
#include "d/actor/d_a_spinner.h" #include "d/actor/d_a_ni.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_npc_bou.h" #include "d/actor/d_a_npc_bou.h"
#include "d/actor/d_a_npc_kolin.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_mstop.h"
#include "d/actor/d_a_tag_mwait.h" #include "d/actor/d_a_tag_mwait.h"
#include "d/actor/d_a_canoe.h" #include "d/actor/d_a_tag_wljump.h"
#include "d/actor/d_a_ni.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 "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 #if TARGET_PC
#include "dusk/action_bindings.h" #include "dusk/action_bindings.h"
@@ -17452,7 +17454,7 @@ int daAlink_c::procCoMetamorphoseInit() {
mProcVar2.field_0x300c = shape_angle.x; mProcVar2.field_0x300c = shape_angle.x;
daMidna_c* midna = (daMidna_c*)getMidnaActor(); 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->changeOriginalDemo();
midna->changeDemoMode(daPy_demo_c::DEMO_UNK_15_e); midna->changeDemoMode(daPy_demo_c::DEMO_UNK_15_e);
+6
View File
@@ -737,6 +737,12 @@ void daAlink_c::setDemoData() {
} else { } else {
mDemo.setStick(1.0f); 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) { 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) {
+6
View File
@@ -3,6 +3,7 @@
#include "d/d_meter2.h" #include "d/d_meter2.h"
#include "d/d_meter2_draw.h" #include "d/d_meter2_draw.h"
#include "d/d_meter2_info.h" #include "d/d_meter2_info.h"
#include "dusk/tphd/LosTable.hpp"
void daAlink_c::handleWolfHowl() { void daAlink_c::handleWolfHowl() {
if (checkWolf()) { if (checkWolf()) {
@@ -71,6 +72,11 @@ void daAlink_c::handleQuickTransform() {
return; 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. // Check to see if Link has the ability to transform.
if (!dComIfGs_isEventBit(dSv_event_flag_c::M_077)) { if (!dComIfGs_isEventBit(dSv_event_flag_c::M_077)) {
return; return;
+5 -1
View File
@@ -452,4 +452,8 @@ daAlink_c::daAlink_c()
mFaceBtkHeap(0x400), mFaceBtkHeap(0x400),
mFaceBckHeap(0xC00), mFaceBckHeap(0xC00),
mAnmHeap9(0x800) mAnmHeap9(0x800)
{} {
#if TARGET_PC
mLosStickValue = -1.0f;
#endif
}
+11
View File
@@ -85,6 +85,17 @@ int daAlink_c::loadModelDVD() {
} }
cPhs_Reset(&mPhaseReq); cPhs_Reset(&mPhaseReq);
mpArcHeap->freeAll(); 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) { if (mProcID == PROC_METAMORPHOSE || mProcID == PROC_METAMORPHOSE_ONLY) {
setArcName(!checkWolf()); setArcName(!checkWolf());
+62 -2
View File
@@ -13,6 +13,7 @@
#include "d/d_bg_parts.h" #include "d/d_bg_parts.h"
#include "m_Do/m_Do_lib.h" #include "m_Do/m_Do_lib.h"
#include "d/d_demo.h" #include "d/d_demo.h"
#include "dusk/tphd/LosTable.hpp"
#include "JSystem/JKernel/JKRExpHeap.h" #include "JSystem/JKernel/JKRExpHeap.h"
#include "JSystem/JKernel/JKRSolidHeap.h" #include "JSystem/JKernel/JKRSolidHeap.h"
#include "JSystem/J3DGraphAnimator/J3DMaterialAnm.h" #include "JSystem/J3DGraphAnimator/J3DMaterialAnm.h"
@@ -297,6 +298,25 @@ int daBg_c::draw() {
dComIfGd_setListBG(); dComIfGd_setListBG();
mDoLib_clipper::changeFar(1000000.0f); 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; J3DModelData* modelData;
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
sp8 = 0; sp8 = 0;
@@ -325,8 +345,22 @@ int daBg_c::draw() {
for (u16 j = 0; j < modelData->getShapeNum(); j++) { for (u16 j = 0; j < modelData->getShapeNum(); j++) {
J3DShape* shape = modelData->getShapeNodePointer(j); J3DShape* shape = modelData->getShapeNodePointer(j);
if (mDoLib_clipper::clip(j3dSys.getViewMtx(), (Vec*)shape->getMin(), Vec* clipMin = (Vec*)shape->getMin();
(Vec*)shape->getMax())) { 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(); shape->hide();
} else { } else {
shape->show(); shape->show();
@@ -565,17 +599,43 @@ int daBg_c::create() {
} }
J3DModelData* modelData; 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 transX;
f32 transY; f32 transY;
s16 angle; s16 angle;
if (dComIfGp_getMapTrans(roomNo, &transX, &transY, &angle)) { if (dComIfGp_getMapTrans(roomNo, &transX, &transY, &angle)) {
#endif
daBg_Part* bgPart = mBgParts; daBg_Part* bgPart = mBgParts;
J3DModel* model; J3DModel* model;
for (int i = 0; i < 6; i++) { for (int i = 0; i < 6; i++) {
model = bgPart->model; model = bgPart->model;
if (model != NULL) { if (model != NULL) {
#if TARGET_PC
mDoMtx_stack_c::transS(transX, transVert, transY);
#else
mDoMtx_stack_c::transS(transX, 0.0f, transY); mDoMtx_stack_c::transS(transX, 0.0f, transY);
#endif
mDoMtx_stack_c::YrotM(angle); mDoMtx_stack_c::YrotM(angle);
model->setBaseTRMtx(mDoMtx_stack_c::get()); model->setBaseTRMtx(mDoMtx_stack_c::get());
+12
View File
@@ -144,7 +144,11 @@ bool daBgObj_c::spec_data_c::Set(void* i_ptr) {
default: default:
// Invalid data block type // Invalid data block type
OS_REPORT_ERROR("データブロックタイプが不正です<%d>\n", 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); JUT_ASSERT(527, FALSE);
#endif
} }
if (block_type == 0) { if (block_type == 0) {
@@ -185,7 +189,11 @@ bool daBgObj_c::spec_data_c::Set(void* i_ptr) {
default: default:
// Invalid data block type // Invalid data block type
OS_REPORT_ERROR("データブロックタイプが不正です<%d>\n", block_type); OS_REPORT_ERROR("データブロックタイプが不正です<%d>\n", block_type);
#if DUSK_TPHD
return 0;
#else
JUT_ASSERT(570, FALSE); JUT_ASSERT(570, FALSE);
#endif
} }
if (block_type == 0) { if (block_type == 0) {
@@ -226,8 +234,12 @@ bool daBgObj_c::spec_data_c::Set(void* i_ptr) {
default: default:
// "Data Block type invalid<%d>\n" // "Data Block type invalid<%d>\n"
OSReport_Error("データブロックタイプが不正です<%d>\n", block_type); OSReport_Error("データブロックタイプが不正です<%d>\n", block_type);
#if DUSK_TPHD
return 0;
#else
JUT_ASSERT(619, FALSE); JUT_ASSERT(619, FALSE);
break; break;
#endif
} }
if (block_type == 0) { if (block_type == 0) {
+4 -1
View File
@@ -403,7 +403,10 @@ void e_ai_class::e_ai_damage() {
if (m_timers[1] == 0) { if (m_timers[1] == 0) {
m_sound.startCreatureSound(Z2SE_EN_AI_FLASH, 0, -1); m_sound.startCreatureSound(Z2SE_EN_AI_FLASH, 0, -1);
mpEmitter = dComIfGp_particle_set(0x81ED, &current.pos, &tevStr, &shape_angle, NULL); mpEmitter = dComIfGp_particle_set(0x81ED, &current.pos, &tevStr, &shape_angle, NULL);
mpEmitter->becomeImmortalEmitter(); if (mpEmitter != NULL) {
mpEmitter->becomeImmortalEmitter();
}
m_timers[1] = 1000; m_timers[1] = 1000;
m_timers[2] = 56; m_timers[2] = 56;
} }
+11 -2
View File
@@ -13,6 +13,9 @@
#include "Z2AudioLib/Z2Instances.h" #include "Z2AudioLib/Z2Instances.h"
#include <cstring> #include <cstring>
#include "dusk/tphd/LosTable.hpp"
#include "dusk/tphd/TphdPack.hpp"
enum E_ww_RES_File_ID { enum E_ww_RES_File_ID {
/* BCK */ /* BCK */
/* 0x04 */ BCK_WW_APPEAR = 0x4, /* 0x04 */ BCK_WW_APPEAR = 0x4,
@@ -466,7 +469,7 @@ f32 daE_WW_c::checkCreateBg(cXyz i_vector) {
return -G_CM3D_F_INF; 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; cXyz temp_r1 = daPy_getPlayerActorClass()->current.pos;
temp_r1.y += 100.0f; temp_r1.y += 100.0f;
sp14 = i_vector; sp14 = i_vector;
@@ -666,8 +669,14 @@ void daE_WW_c::executeMaster() {
sp30.set(0.0f, 0.0f, 3000.0f); 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); 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); f32 temp_f31 = checkCreateBg(sp3C);
if (-G_CM3D_F_INF != temp_f31) { if (-G_CM3D_F_INF != temp_f31) {
sp3C.y = temp_f31; sp3C.y = temp_f31;
+14
View File
@@ -10,6 +10,7 @@
#include "d/actor/d_a_player.h" #include "d/actor/d_a_player.h"
#include "d/d_com_inf_game.h" #include "d/d_com_inf_game.h"
#include <cstring> #include <cstring>
#include <dusk/ui/settings.hpp>
static int daKytag04_Draw(kytag04_class* i_this) { static int daKytag04_Draw(kytag04_class* i_this) {
dScnKy_env_light_c* kankyo = dKy_getEnvlight(); 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; 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"); int phase_state = dComIfG_resLoad(&a_this->mPhase, "Kytag04");
if (phase_state == cPhs_COMPLEATE_e) { if (phase_state == cPhs_COMPLEATE_e) {
a_this->field_0x5b4 = (fopAcM_GetParam(i_this) >> 8) & 7; a_this->field_0x5b4 = (fopAcM_GetParam(i_this) >> 8) & 7;
a_this->mStageNo = (i_this->current.angle.z >> 8) & 0xFF; a_this->mStageNo = (i_this->current.angle.z >> 8) & 0xFF;
a_this->mExitID = fopAcM_GetParam(i_this) & 0xFF; a_this->mExitID = fopAcM_GetParam(i_this) & 0xFF;
a_this->mNeedDropNum = i_this->current.angle.z & 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_0x5b5 = fopAcM_GetParam(i_this) >> 0x10;
a_this->field_0x5b6 = fopAcM_GetParam(i_this) >> 0x18; a_this->field_0x5b6 = fopAcM_GetParam(i_this) >> 0x18;
+1
View File
@@ -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) { static void sparks_move(kytag10_class* i_this) {
camera_process_class* camera_p = dComIfGp_getCamera(0); camera_process_class* camera_p = dComIfGp_getCamera(0);
cXyz ratio_pos_1; cXyz ratio_pos_1;
+12 -4
View File
@@ -5,16 +5,17 @@
#include "d/dolzel_rel.h" // IWYU pragma: keep #include "d/dolzel_rel.h" // IWYU pragma: keep
#include "d/actor/d_a_midna.h"
#include "JSystem/J3DGraphLoader/J3DAnmLoader.h" #include "JSystem/J3DGraphLoader/J3DAnmLoader.h"
#include "d/d_meter2_info.h"
#include "d/actor/d_a_alink.h" #include "d/actor/d_a_alink.h"
#include "d/actor/d_a_kago.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_demo.h"
#include "d/d_meter2_info.h"
#include "d/d_msg_object.h" #include "d/d_msg_object.h"
#include "d/d_s_play.h" #include "d/d_s_play.h"
#include "d/d_debug_viewer.h"
#include "dusk/frame_interpolation.h" #include "dusk/frame_interpolation.h"
#include "dusk/tphd/LosTable.hpp"
static f32 dummy_lit_3777(int idx, u8 foo) { static f32 dummy_lit_3777(int idx, u8 foo) {
Vec dummy_vec = {0.0f, 0.0f, 0.0f}; Vec dummy_vec = {0.0f, 0.0f, 0.0f};
@@ -3308,7 +3309,14 @@ int daMidna_c::execute() {
} }
} }
onStateFlg0(FLG0_UNK_8000); 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)) { } else if (mMsgFlow.doFlow(this, NULL, 0)) {
int item_id; int item_id;
u16 event_id = mMsgFlow.getEventId(&item_id); u16 event_id = mMsgFlow.getEventId(&item_id);
+348
View File
@@ -15,6 +15,8 @@
#include "m_Do/m_Do_lib.h" #include "m_Do/m_Do_lib.h"
#if TARGET_PC #if TARGET_PC
#include "dusk/frame_interpolation.h" #include "dusk/frame_interpolation.h"
#include "dusk/settings.h"
#include <cstring>
#endif #endif
#ifndef __MWERKS__ #ifndef __MWERKS__
@@ -50,6 +52,32 @@ void dMirror_packet_c::calcMinMax() {
mMinVal.set(FLT_MAX, FLT_MAX, FLT_MAX); mMinVal.set(FLT_MAX, FLT_MAX, FLT_MAX);
mMaxVal.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; cXyz* quad = mQuad;
for (int i = 0; i < 4; i++, quad++) { for (int i = 0; i < 4; i++, quad++) {
f32 val = quad->x; f32 val = quad->x;
@@ -82,6 +110,7 @@ void dMirror_packet_c::calcMinMax() {
mMaxVal.z = val; mMaxVal.z = val;
} }
} }
#endif
} }
int dMirror_packet_c::entryModel(J3DModel* i_model) { int dMirror_packet_c::entryModel(J3DModel* i_model) {
@@ -103,6 +132,10 @@ int dMirror_packet_c::entryModel(J3DModel* i_model) {
return 1; 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, 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) { f32 param_4, f32 param_5, f32 param_6, f32 param_7) {
ZoneScoped; ZoneScoped;
@@ -131,11 +164,82 @@ void dMirror_packet_c::mirrorZdraw(f32* param_0, f32* param_1, f32 param_2, f32
GXLoadPosMtxImm(j3dSys.getViewMtx(), 0); GXLoadPosMtxImm(j3dSys.getViewMtx(), 0);
GXSetCurrentMtx(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); GXBegin(GX_QUADS, GX_VTXFMT0, 4);
for (int i = 0; i < 4; i++) { for (int i = 0; i < 4; i++) {
GXPosition3f32(mQuad[i].x, mQuad[i].y, mQuad[i].z); GXPosition3f32(mQuad[i].x, mQuad[i].y, mQuad[i].z);
} }
GXEnd(); GXEnd();
#endif
if (mViewScale.y > 0.0f) { if (mViewScale.y > 0.0f) {
GXSetZMode(GX_ENABLE, GX_ALWAYS, GX_ENABLE); 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() { void dMirror_packet_c::mainDraw() {
ZoneScoped; ZoneScoped;
j3dSys.reinitGX(); 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]; cXyz sp19C[5];
Mtx sp16C; Mtx sp16C;
@@ -456,6 +773,7 @@ void dMirror_packet_c::mainDraw() {
GXSetScissor(scissor[0], scissor[1], scissor[2], scissor[3]); GXSetScissor(scissor[0], scissor[1], scissor[2], scissor[3]);
mirrorZdraw(sp150, sp138, view->far_, var_f31, var_f30, var_f29, var_f28, var_f27); mirrorZdraw(sp150, sp138, view->far_, var_f31, var_f30, var_f29, var_f28, var_f27);
} }
#endif
} }
void dMirror_packet_c::draw() { void dMirror_packet_c::draw() {
@@ -536,6 +854,36 @@ int daMirror_c::create() {
mPacket.getViewScale().set(-1.0f, 1.0f, 1.0f); mPacket.getViewScale().set(-1.0f, 1.0f, 1.0f);
} else { } else {
if (type == 1) { 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; scale *= 10.0f;
mPacket.getViewScale().set(1.0, -1.0, 1.0); mPacket.getViewScale().set(1.0, -1.0, 1.0);
} else { } else {
+14 -2
View File
@@ -10,8 +10,11 @@
#include <cstring> #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}, {"", 0},
#if TARGET_PC
{"DEFAULT_GETITEM", 0},
#endif
}; };
static DUSK_CONST char* l_resNameList[2] = { static DUSK_CONST char* l_resNameList[2] = {
@@ -145,7 +148,7 @@ int daNpc_FairySeirei_c::Draw() {
int daNpc_FairySeirei_c::isDelete() { int daNpc_FairySeirei_c::isDelete() {
int ret = 0; int ret = 0;
if (daNpcT_chkEvtBit(0x1F9) == false) { if (IF_DUSK(mType != 4 &&) daNpcT_chkEvtBit(0x1F9) == false) {
ret = 1; ret = 1;
} }
return ret; return ret;
@@ -359,6 +362,15 @@ int daNpc_FairySeirei_c::talk(int param_0) {
} }
if (fopAcM_IsExecuting(mItemPartnerId)) { if (fopAcM_IsExecuting(mItemPartnerId)) {
mTalking = TRUE; mTalking = TRUE;
#if TARGET_PC
if (dusk::tphd_active() && getType() == 4) {
mEvtNo = 1;
field_0xe33 = true;
mSpeakEvent = true;
}
#endif
evtChange(); evtChange();
} }
} else { } else {
+50 -1
View File
@@ -14,6 +14,9 @@
#include "d/actor/d_a_obj_ystone.h" #include "d/actor/d_a_obj_ystone.h"
#include <cstring> #include <cstring>
#include "d/actor/d_a_alink.h"
#include "dusk/tphd/LosTable.hpp"
static DUSK_CONST char* l_arcName = "ef_Portal"; static DUSK_CONST char* l_arcName = "ef_Portal";
static char const* l_clearEvName[9] = { static char const* l_clearEvName[9] = {
@@ -101,7 +104,7 @@ int daObjBossWarp_c::Create() {
} }
mBossClearMapToolId = 0xff; 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); mBossWarpInEventId = dComIfGp_getEventManager().getEventIdx(this, "BOSS_WARPIN", 0xff);
mBossWarpInMapToolId = 0xff; mBossWarpInMapToolId = 0xff;
mAction = 3; mAction = 3;
@@ -217,6 +220,31 @@ BOOL daObjBossWarp_c::checkDistance() {
} }
int daObjBossWarp_c::execute() { 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) { if (dStage_stagInfo_GetSTType(dComIfGp_getStage()->getStagInfo()) != 3) {
u8 sw = getSwNo(); u8 sw = getSwNo();
if (sw == 0xff || fopAcM_isSwitch(this, sw)) { if (sw == 0xff || fopAcM_isSwitch(this, sw)) {
@@ -476,6 +504,14 @@ int daObjBossWarp_c::demoProc() {
disappear(0); disappear(0);
break; break;
case 3: // SCENE_CHG 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; int scene;
if (isFirst()) { if (isFirst()) {
scene = getSceneListNo(); scene = getSceneListNo();
@@ -536,6 +572,11 @@ int daObjBossWarp_c::demoProc() {
break; break;
case 6: // WALK_TARGET1 case 6: // WALK_TARGET1
dComIfGp_evmng_setGoal(&current.pos); dComIfGp_evmng_setGoal(&current.pos);
#if TARGET_PC
if (dusk::tphd::is_los_active()) {
daAlink_getAlinkActorClass()->mLosStickValue = 1.0f;
}
#endif
break; break;
case 7: // APPEAR_END case 7: // APPEAR_END
break; break;
@@ -573,6 +614,14 @@ int daObjBossWarp_c::demoProc() {
dComIfGp_evmng_cutEnd(mStaffId); dComIfGp_evmng_cutEnd(mStaffId);
break; break;
case 3: // SCENE_CHG case 3: // SCENE_CHG
#if TARGET_PC
if (dusk::tphd::is_los_active()) {
if (mCounter++ == 0) {
fopAcM_offDraw(this);
dComIfGp_event_remove();
}
}
#endif
break; break;
case 4: // STONE_FALL case 4: // STONE_FALL
if (ystone != NULL) { if (ystone != NULL) {
+11 -1
View File
@@ -26,6 +26,8 @@
daObjDrop_HIO_c l_HIO; daObjDrop_HIO_c l_HIO;
#endif #endif
#include <dusk/ui/settings.hpp>
static void* searchParentSub(void* pproc, void* pdata) { static void* searchParentSub(void* pproc, void* pdata) {
daObjDrop_c* pdrop = (daObjDrop_c*)pdata; daObjDrop_c* pdrop = (daObjDrop_c*)pdata;
fopAc_ac_c* pym = (fopAc_ac_c*)pproc; fopAc_ac_c* pym = (fopAc_ac_c*)pproc;
@@ -103,9 +105,17 @@ void daObjDrop_c::dropGet() {
dComIfGs_setLightDropNum(dComIfGp_getStartStageDarkArea(), num + 1); dComIfGs_setLightDropNum(dComIfGp_getStartStageDarkArea(), num + 1);
if (dComIfGp_getStartStageDarkArea() == 2 && 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) 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]); dComIfGs_onEventBit(dSv_event_flag_c::saveBitLabels[9]);
} }
+46 -21
View File
@@ -6,9 +6,10 @@
#include "d/dolzel_rel.h" // IWYU pragma: keep #include "d/dolzel_rel.h" // IWYU pragma: keep
#include "d/actor/d_a_obj_lv8Lift.h" #include "d/actor/d_a_obj_lv8Lift.h"
#include "d/d_bg_w.h"
#include "d/d_com_inf_game.h" #include "d/d_com_inf_game.h"
#include "d/d_path.h" #include "d/d_path.h"
#include "d/d_bg_w.h" #include "dusk/tphd/LosTable.hpp"
#if TARGET_PC #if TARGET_PC
#include "dusk/frame_interpolation.h" #include "dusk/frame_interpolation.h"
@@ -44,14 +45,14 @@ f32 const daL8Lift_c::mSpeed[16] = {
}; };
int daL8Lift_c::CreateHeap() { 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); JUT_ASSERT(190, modelData != NULL);
mpModel = mDoExt_J3DModel__create(modelData, 0, 0x11000284); mpModel = mDoExt_J3DModel__create(modelData, 0, 0x11000284);
if (!mpModel) { if (!mpModel) {
return 0; 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); 1, 0, 1.0f, 0, -1);
JUT_ASSERT(207, res == 1); JUT_ASSERT(207, res == 1);
@@ -63,9 +64,9 @@ static daL8Lift_HIO_c l_HIO;
int daL8Lift_c::create() { int daL8Lift_c::create() {
fopAcM_ct(this, daL8Lift_c); 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 (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; return cPhs_ERROR_e;
} }
@@ -92,8 +93,17 @@ int daL8Lift_c::create() {
if (mSwbit == 0xff) { if (mSwbit == 0xff) {
mBtk.setFrame(mBtk.getEndFrame() - 1.0f); 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(); init_modeWaitInit();
} else { } else {
mNoRideOffSwTimer = 0; mNoRideOffSwTimer = 0;
@@ -290,8 +300,15 @@ void daL8Lift_c::init_modeOnAnm() {
void daL8Lift_c::modeOnAnm() { void daL8Lift_c::modeOnAnm() {
if (mBtk.play() == 1) { if (mBtk.play() == 1) {
field_0x808 = 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(); init_modeMoveWait();
} }
} }
@@ -428,20 +445,28 @@ int daL8Lift_c::Draw() {
J3DMaterial* mpMatNode = modelData->getMaterialNodePointer(0); J3DMaterial* mpMatNode = modelData->getMaterialNodePointer(0);
dComIfGd_setListDarkBG(); dComIfGd_setListDarkBG();
if (mpMatNode->getTexGenBlock()->getTexMtx(1)) { #if TARGET_PC
J3DTexMtxInfo* texMtxInfo = &mpMatNode->getTexGenBlock()->getTexMtx(1)->getTexMtxInfo(); if (dusk::tphd::is_los_active()) {
if (texMtxInfo) { mDoExt_modelUpdateDL(mpModel);
Mtx mMtx58; } else
C_MTXLightOrtho(mMtx58, 100.0f, -100.0f, -100.0f, 100.0f, 1.0f, 1.0f, 0.0f, 0.0f); #endif
mDoMtx_stack_c::XrotS(0x4000); {
mDoMtx_stack_c::transM(-current.pos.x, -current.pos.y, -current.pos.z); if (mpMatNode->getTexGenBlock()->getTexMtx(1)) {
cMtx_concat(mMtx58, mDoMtx_stack_c::get(), texMtxInfo->mEffectMtx); 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(); dComIfGd_setList();
J3DGXColor* mColor = mpMatNode->getTevKColor(1); J3DGXColor* mColor = mpMatNode->getTevKColor(1);
@@ -453,7 +478,7 @@ int daL8Lift_c::Draw() {
} }
int daL8Lift_c::Delete() { int daL8Lift_c::Delete() {
dComIfG_resDelete(&mPhase, "L8Lift"); dComIfG_resDelete(&mPhase, DUSK_IF_ELSE(dusk::tphd::is_los_active() ? "L8LiftSt" : "L8Lift", "L8Lift"));
if (mLightSet) { if (mLightSet) {
dKy_plight_cut(&mLight); dKy_plight_cut(&mLight);
} }
+124 -8
View File
@@ -9,9 +9,19 @@
#include "SSystem/SComponent/c_math.h" #include "SSystem/SComponent/c_math.h"
#include "d/d_com_inf_game.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", "P_Rgate",
"SDGate", "SDGate",
#if TARGET_PC
"losGate1",
"SDGate",
"los_Maze",
"losGate5",
"losGate1",
"losGate2",
"losGate3",
"losGate4",
#endif
}; };
daSwShutter_HIO_c::daSwShutter_HIO_c() { daSwShutter_HIO_c::daSwShutter_HIO_c() {
@@ -36,7 +46,20 @@ void daSwShutter_c::setBaseMtx() {
mpModel->setBaseTRMtx(mDoMtx_stack_c::get()); 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() { int daSwShutter_c::CreateHeap() {
J3DModelData* modelData = J3DModelData* modelData =
@@ -50,7 +73,20 @@ int daSwShutter_c::CreateHeap() {
return 1; 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() { int daSwShutter_c::create() {
fopAcM_ct(this, daSwShutter_c); fopAcM_ct(this, daSwShutter_c);
@@ -74,9 +110,39 @@ int daSwShutter_c::create() {
field_0x5b0 = 0.0f; field_0x5b0 = 0.0f;
if (fopAcM_isSwitch(this, getSwBit())) { 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; current.pos.y += -450.0f;
init_modeMoveDownEnd(); init_modeMoveDownEnd();
#endif
} else { } else {
#if TARGET_PC
if (dusk::tphd_active() && getModelType() == 2) {
current.pos.y += -450.0f;
}
#endif
mShakeRot.x = 0; mShakeRot.x = 0;
mShakeRot.y = 0; mShakeRot.y = 0;
mShakeRot.z = 0; mShakeRot.z = 0;
@@ -142,10 +208,23 @@ void daSwShutter_c::init_modeMoveDownInit() {
mMaxAtten = l_HIO.mMaxAtten; mMaxAtten = l_HIO.mMaxAtten;
mMinAtten = l_HIO.mMinAtten; 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) { if (mModelType == TYPE_SUBDAN_e) {
dComIfGp_particle_set(0x8C73, &current.pos, &shape_angle, NULL); dComIfGp_particle_set(0x8C73, &current.pos, &shape_angle, NULL);
dComIfGp_particle_set(0x8C74, &current.pos, &shape_angle, NULL); dComIfGp_particle_set(0x8C74, &current.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, &current.pos, &shape_angle, NULL); dComIfGp_particle_set(0x8709, &current.pos, &shape_angle, NULL);
dComIfGp_particle_set(0x870A, &current.pos, &shape_angle, NULL); dComIfGp_particle_set(0x870A, &current.pos, &shape_angle, NULL);
} }
@@ -163,9 +242,16 @@ void daSwShutter_c::modeMoveDownInit() {
} }
void daSwShutter_c::init_modeMoveDown() { 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, &current.pos, &shape_angle, NULL); dComIfGp_particle_set(0x8C77, &current.pos, &shape_angle, NULL);
} else { } else {
dComIfGp_particle_set(0x870D, &current.pos, &shape_angle, NULL); dComIfGp_particle_set(0x870D, &current.pos, &shape_angle, NULL);
@@ -175,11 +261,41 @@ void daSwShutter_c::init_modeMoveDown() {
} }
void daSwShutter_c::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(&current.pos.y, home.pos.y - -370.0f, 1.0f, fopAcM_GetSpeedF(this), 1.0f);
break;
case 5:
target_dist = cLib_addCalc(&current.pos.y, home.pos.y - -450.0f, 1.0f, fopAcM_GetSpeedF(this), 1.0f);
break;
case 9:
target_dist = cLib_addCalc(&current.pos.y, home.pos.y - -740.0f, 1.0f, fopAcM_GetSpeedF(this), 1.0f);
break;
default:
target_dist = cLib_addCalc(&current.pos.y, home.pos.y + -450.0f, 1.0f, fopAcM_GetSpeedF(this), 1.0f);
break;
}
} else {
target_dist = cLib_addCalc(&current.pos.y, home.pos.y + -450.0f, 1.0f, fopAcM_GetSpeedF(this), 1.0f);
}
#else
f32 target_dist = f32 target_dist =
cLib_addCalc(&current.pos.y, home.pos.y + -450.0f, 1.0f, fopAcM_GetSpeedF(this), 1.0f); cLib_addCalc(&current.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, &current.pos, &shape_angle, NULL); mEmitterID0 = dComIfGp_particle_set(mEmitterID0, 0x8C75, &current.pos, &shape_angle, NULL);
mEmitterID1 = dComIfGp_particle_set(mEmitterID1, 0x8C76, &current.pos, &shape_angle, NULL); mEmitterID1 = dComIfGp_particle_set(mEmitterID1, 0x8C76, &current.pos, &shape_angle, NULL);
} else { } else {
+22 -4
View File
@@ -54,14 +54,27 @@ BOOL daObjSwpush::Act_c::solidHeapCB(fopAc_ac_c* a_this) {
return static_cast<daObjSwpush::Act_c*>(a_this)->create_heap(); 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", "Kbota_00",
"S_lv3bota", "S_lv3bota",
"S_lv6bota", "S_lv6bota",
#if TARGET_PC
"S_losbota",
#endif
}; };
bool daObjSwpush::Act_c::create_heap() { bool daObjSwpush::Act_c::create_heap() {
@@ -117,7 +130,12 @@ cPhs_Step daObjSwpush::Act_c::create_res_load() {
return cPhs_COMPLEATE_e; 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] = { daObjSwpush::Hio_c::Attr_c const daObjSwpush::Act_c::M_attr[5] = {
{ {
+32 -1
View File
@@ -371,11 +371,41 @@ JKRHeap* daPy_anmHeap_c::setAnimeHeap() {
#include "dusk/dvd_asset.hpp" #include "dusk/dvd_asset.hpp"
using GameVersion = dusk::version::GameVersion; using GameVersion = dusk::version::GameVersion;
static const u8* l_sightDL_get() { 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 u8 buf[0x89];
static bool _ = ( static bool _ = (
dusk::LoadDolAsset( dusk::LoadDolAsset(
buf, buf,
{ {
{GameVersion::GcnUsa, 0x803BA0C0}, {GameVersion::GcnUsa, 0x803BA0C0},
{GameVersion::GcnPal, 0x803BBDA0}, {GameVersion::GcnPal, 0x803BBDA0},
{GameVersion::GcnJpn, 0x803B4220} {GameVersion::GcnJpn, 0x803B4220}
@@ -385,6 +415,7 @@ static const u8* l_sightDL_get() {
true true
); );
return buf; return buf;
#endif
} }
#define l_sightDL (l_sightDL_get()) #define l_sightDL (l_sightDL_get())
#else #else
+15 -1
View File
@@ -126,6 +126,10 @@ int daSwc00_c::execute() {
case 1: case 1:
case 2: case 2:
case 7: case 7:
#if TARGET_PC
case 10: // HD Cave of Shadows region switch
case 11:
#endif
case 15: case 15:
if (sw2 != 0xff && !fopAcM_isSwitch(this, sw2)) { if (sw2 != 0xff && !fopAcM_isSwitch(this, sw2)) {
return 1; return 1;
@@ -179,7 +183,17 @@ int daSwc00_c::execute() {
field_0x584 = 1; field_0x584 = 1;
} }
break; 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 7:
case 8: case 8:
if (hitCheck(this)) { if (hitCheck(this)) {
+7 -7
View File
@@ -101,7 +101,7 @@ void daTit_HIO_c::genMessage(JORMContext* mctx) {
#endif #endif
int daTitle_c::CreateHeap() { 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); JUT_ASSERT(258, modelData);
mpModel = mDoExt_J3DModel__create(modelData, 0x80000, 0x11000285); mpModel = mDoExt_J3DModel__create(modelData, 0x80000, 0x11000285);
@@ -109,16 +109,16 @@ int daTitle_c::CreateHeap() {
return 0; 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); 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); 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); 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); JUT_ASSERT(297, res == 1);
return 1; return 1;
@@ -132,7 +132,7 @@ static procFunc daTitleProc[6] = {
int daTitle_c::create() { int daTitle_c::create() {
fopAcM_ct(this, daTitle_c); 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) { if (phase_state != cPhs_COMPLEATE_e) {
return phase_state; return phase_state;
} }
@@ -408,7 +408,7 @@ int daTitle_c::Draw() {
int daTitle_c::Delete() { int daTitle_c::Delete() {
mDoHIO_DELETE_CHILD(g_daTitHIO.id); 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(mTitle.Scr);
JKR_DELETE(field_0x600); JKR_DELETE(field_0x600);
+15
View File
@@ -25,8 +25,10 @@
#include "m_Do/m_Do_graphic.h" #include "m_Do/m_Do_graphic.h"
#include <cstdio> #include <cstdio>
#include <cstring> #include <cstring>
#include <dusk/ui/settings.hpp>
#include "dusk/string.hpp" #include "dusk/string.hpp"
#include "dusk/tphd/LosTable.hpp"
void dComIfG_play_c::ct() { void dComIfG_play_c::ct() {
mWindowNum = 0; mWindowNum = 0;
@@ -2573,7 +2575,14 @@ u8 dComIfG_getNowCalcRegion() {
bool dComIfGp_isLightDropMapVisible() { bool dComIfGp_isLightDropMapVisible() {
for (int i = 0; i < 3; i++) { 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) { if (dComIfGs_isLightDropGetFlag(i) != FALSE && dComIfGs_getLightDropNum(i) < 16) {
#endif
return true; return true;
} }
} }
@@ -2855,6 +2864,12 @@ BOOL dComIfGs_Wolf_Change_Check() {
is_wolf = true; 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)); 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 // Stage is Hyrule Field and Room is Eldin Gorge Entrance
+7
View File
@@ -1138,7 +1138,14 @@ void dDlst_shadowReal_c::draw() {
{ {
GXLoadTexMtxImm(mReceiverProjMtx, GX_TEXMTX0, GX_MTX3x4); GXLoadTexMtxImm(mReceiverProjMtx, GX_TEXMTX0, GX_MTX3x4);
} }
#ifdef DUSK_TPHD
GX2SetPolygonOffset(-10.0f, -10.0f, -10.0f, -10.0f, 0);
#endif
mShadowRealPoly.draw(); 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, static int psdRealCallBack(cBgS_ShdwDraw* param_0, cBgD_Vtx_t* param_1, int param_2,
+8 -1
View File
@@ -229,7 +229,7 @@ static void (*item_func_ptr[256])() = {
item_func_F_MAYFLY, item_func_F_MAYFLY,
item_func_noentry, item_func_noentry,
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, item_func_noentry,
item_func_noentry, item_func_noentry,
@@ -2187,4 +2187,11 @@ int addBombCount(u8 i_bombType, u8 i_addNum) {
return i_addNum; return i_addNum;
} }
#if TARGET_PC
// HD item functions
void item_func_WALLET_LV4() {
dComIfGs_setWalletSize(3);
}
#endif
u8* dEnemyItem_c::mData; u8* dEnemyItem_c::mData;
+4
View File
@@ -221,7 +221,11 @@ dItem_itemResource dItem_data::item_resource[] = {
{"O_gD_kagm", 0x0009, 0x000F, 0x0006, 0x000C,-0x0001, -0x1, -0x1, 0x0031, 0x50, 0x0000}, {"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},
{"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}, {"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}, {"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},
+2
View File
@@ -689,6 +689,8 @@ void dMenu_Collect2D_c::screenSet() {
field_0x184[0][3] = 0x199; field_0x184[0][3] = 0x199;
} else if (dComIfGs_getWalletSize() == BIG_WALLET) { } else if (dComIfGs_getWalletSize() == BIG_WALLET) {
field_0x184[0][3] = 0x19a; field_0x184[0][3] = 0x19a;
} if (dusk::tphd_active() && dComIfGs_getWalletSize() == 3) {
field_0x184[0][3] = 0x19c;
} else { } else {
field_0x184[0][3] = 0x19b; field_0x184[0][3] = 0x19b;
} }
+34 -6
View File
@@ -447,7 +447,7 @@ void dMeter2Draw_c::init() {
} }
field_0x61c = 0.0f; 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_0x62c[i] = 0.0f;
field_0x66c[i] = 0.0f; field_0x66c[i] = 0.0f;
} }
@@ -728,7 +728,8 @@ void dMeter2Draw_c::draw() {
if (field_0x756 >= 0) { if (field_0x756 >= 0) {
var_f29 = g_drawHIO.mLightDrop.mDropPikariAnimSpeed_Completed; 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 #ifdef TARGET_PC
// FRAME INTERP NOTE: Set even if not advancing // FRAME INTERP NOTE: Set even if not advancing
var_f28 = g_drawHIO.mLightDrop.mPikariScaleComplete; var_f28 = g_drawHIO.mLightDrop.mPikariScaleComplete;
@@ -749,12 +750,12 @@ void dMeter2Draw_c::draw() {
int temp_r5_3 = temp_r5_2 + 1; int temp_r5_3 = temp_r5_2 + 1;
if (field_0x756 == temp_r5_3) { 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++; field_0x756++;
} }
var_f28 = g_drawHIO.mLightDrop.mPikariScaleComplete; var_f28 = g_drawHIO.mLightDrop.mPikariScaleComplete;
} else if (field_0x756 >= g_drawHIO.mLightDrop.field_0x54 + temp_r5_3) { } 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_0x62c[i] = 18.0f - var_f29;
field_0x66c[i] = 18.0f - g_drawHIO.mLightDrop.mPikariLoopAnimSpeed; 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) { if (field_0x66c[i] > 0.0f) {
drawPikari(mpSIParts[i][1], &g_drawHIO.mLightDrop.mPikariLoopBackStopFrame, drawPikari(mpSIParts[i][1], &g_drawHIO.mLightDrop.mPikariLoopBackStopFrame,
g_drawHIO.mLightDrop.mPikariLoopBackScale, 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) { if (field_0x62c[i] > 0.0f) {
drawPikari(mpSIParts[i][1], &field_0x62c[i], var_f28, drawPikari(mpSIParts[i][1], &field_0x62c[i], var_f28,
g_drawHIO.mLightDrop.mDropPikariFrontOuter, 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, 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) { 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++) { for (int i = 0; i < 16; i++) {
if (mpSIParts[i][0] != NULL) { if (mpSIParts[i][0] != NULL) {
mpSIParts[i][0]->scale(g_drawHIO.mLightDrop.mDropScale, mpSIParts[i][0]->scale(g_drawHIO.mLightDrop.mDropScale,
+47 -2
View File
@@ -745,7 +745,7 @@ int dMsgFlow_c::getParam(u8* params) {
return *(BE(int)*)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::query005, &dMsgFlow_c::query001, &dMsgFlow_c::query002, &dMsgFlow_c::query003,
&dMsgFlow_c::query006, &dMsgFlow_c::query007, &dMsgFlow_c::query004, &dMsgFlow_c::query008, &dMsgFlow_c::query006, &dMsgFlow_c::query007, &dMsgFlow_c::query004, &dMsgFlow_c::query008,
&dMsgFlow_c::query009, &dMsgFlow_c::query010, &dMsgFlow_c::query011, &dMsgFlow_c::query012, &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::query045, &dMsgFlow_c::query046, &dMsgFlow_c::query047, &dMsgFlow_c::query048,
&dMsgFlow_c::query049, &dMsgFlow_c::query050, &dMsgFlow_c::query051, &dMsgFlow_c::query052, &dMsgFlow_c::query049, &dMsgFlow_c::query050, &dMsgFlow_c::query051, &dMsgFlow_c::query052,
&dMsgFlow_c::query053, &dMsgFlow_c::query053,
#if TARGET_PC
&dMsgFlow_c::query054,
&dMsgFlow_c::query055,
#endif
}; };
#if DEBUG #if DEBUG
@@ -1730,7 +1735,7 @@ u16 dMsgFlow_c::query053(mesg_flow_node_branch* i_flowNode_p, fopAc_ac_c* i_spea
return ret; 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::event000, &dMsgFlow_c::event001, &dMsgFlow_c::event002, &dMsgFlow_c::event003,
&dMsgFlow_c::event004, &dMsgFlow_c::event005, &dMsgFlow_c::event006, &dMsgFlow_c::event007, &dMsgFlow_c::event004, &dMsgFlow_c::event005, &dMsgFlow_c::event006, &dMsgFlow_c::event007,
&dMsgFlow_c::event008, &dMsgFlow_c::event009, &dMsgFlow_c::event010, &dMsgFlow_c::event011, &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::event032, &dMsgFlow_c::event033, &dMsgFlow_c::event034, &dMsgFlow_c::event035,
&dMsgFlow_c::event036, &dMsgFlow_c::event037, &dMsgFlow_c::event038, &dMsgFlow_c::event039, &dMsgFlow_c::event036, &dMsgFlow_c::event037, &dMsgFlow_c::event038, &dMsgFlow_c::event039,
&dMsgFlow_c::event040, &dMsgFlow_c::event041, &dMsgFlow_c::event042, &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) { 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) { int dMsgFlow_c::event042(mesg_flow_node_event* i_flowNode_p, fopAc_ac_c* i_speaker_p) {
return 1; 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
View File
@@ -812,7 +812,14 @@ u32 dMsgObject_c::getMessageIndexAlways(u32 param_0) {
} }
u32 dMsgObject_c::getMessageIDAlways(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) { s16 dMsgObject_c::getMessageGroup(u32 param_0) {
@@ -1745,7 +1752,37 @@ void dMsgObject_c::readMessageGroupLocal(mDoDvdThd_mountXArchive_c** p_arcMount)
#if TARGET_PC #if TARGET_PC
// Original game UB // 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()) { switch (dComIfGs_getPalLanguage()) {
case dSv_player_config_c::LANGUAGE_GERMAN: case dSv_player_config_c::LANGUAGE_GERMAN:
snprintf(arcName, sizeof(arcName), "/res/Msgde/bmgres%d.arc", msgGroup); snprintf(arcName, sizeof(arcName), "/res/Msgde/bmgres%d.arc", msgGroup);
+1
View File
@@ -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); level_c::emitter_c* this_00 = field_0x210.get(param_0);
u8 uVar7 = getRM_ID(param_2); u8 uVar7 = getRM_ID(param_2);
JPAResourceManager* this_01 = mEmitterMng->getResourceManager(uVar7); JPAResourceManager* this_01 = mEmitterMng->getResourceManager(uVar7);
u32 uVar3 = this_01->getResUserWork(param_2); u32 uVar3 = this_01->getResUserWork(param_2);
if (this_00 != NULL) { if (this_00 != NULL) {
if (param_2 == this_00->getNameId()) { if (param_2 == this_00->getNameId()) {
+26
View File
@@ -23,6 +23,9 @@
#ifndef __MWERKS__ #ifndef __MWERKS__
#include "dusk/extras.h" #include "dusk/extras.h"
#include "dusk/logging.h" #include "dusk/logging.h"
#if DUSK_TPHD
#include "dusk/tphd/HdAssetLayer.hpp"
#endif
#endif #endif
dRes_info_c::dRes_info_c() { dRes_info_c::dRes_info_c() {
@@ -643,7 +646,20 @@ int dRes_info_c::setRes() {
} }
#if DEBUG #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); mSize = JKRGetRootHeap()->getSize(((JKRMemArchive*)mArchive)->mArcHeader) + JKRGetMemBlockSize(NULL, mDataHeap);
#endif
if (data_8074C6C0_debug) { if (data_8074C6C0_debug) {
JKRExpHeap* zeldaHeap = mDoExt_getZeldaHeap(); 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); 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; 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); JKRMemArchive* memArchive = JKR_NEW JKRMemArchive(i_archiveRes, i_bufferSize, JKRMEMBREAK_FLAG_UNKNOWN0);
if (memArchive == NULL || !memArchive->isMounted()) { if (memArchive == NULL || !memArchive->isMounted()) {
return 0; return 0;
+34 -2
View File
@@ -1504,7 +1504,39 @@ void dScnLogo_c::dvdDataLoad() {
mpCardIconCommand = aramMount(ICON_RES_PATH, mDoExt_getJ2dHeap()); mpCardIconCommand = aramMount(ICON_RES_PATH, mDoExt_getJ2dHeap());
#if TARGET_PC #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()) { switch (getPalLanguage()) {
case 1: case 1:
mpBmgResCommand = onMemMount("/res/Msgde/bmgres.arc"); mpBmgResCommand = onMemMount("/res/Msgde/bmgres.arc");
@@ -1612,7 +1644,7 @@ void dScnLogo_c::dvdDataLoad() {
mpRubyResCommand = onMemMount("/res/Fontus/rubyres.arc"); mpRubyResCommand = onMemMount("/res/Fontus/rubyres.arc");
#endif #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); mItemTableCommand = mDoDvdThd_toMainRam_c::create("/res/ItemTable/item_table.bin", 0, NULL);
JUT_ASSERT(2620, mItemTableCommand != NULL); JUT_ASSERT(2620, mItemTableCommand != NULL);
+5 -1
View File
@@ -118,7 +118,7 @@ u8 dSv_player_status_a_c::getMixItemIndex(int i_no) const {
} }
u16 dSv_player_status_a_c::getRupeeMax() 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) { switch (mWalletSize) {
case WALLET: case WALLET:
#if TARGET_PC #if TARGET_PC
@@ -138,6 +138,10 @@ u16 dSv_player_status_a_c::getRupeeMax() const {
#else #else
return 1000; return 1000;
#endif #endif
#if TARGET_PC
case 3: // colossal wallet
return 9999;
#endif
} }
} }
+95 -2
View File
@@ -25,8 +25,9 @@
#include "dusk/logging.h" #include "dusk/logging.h"
#include "dusk/string.hpp" #include "dusk/string.hpp"
#if TARGET_PC #if TARGET_PC
#include <format>
#include <fmt/ranges.h> #include <fmt/ranges.h>
#include "dusk/tphd/LosTable.hpp"
#include "os_report.h"
#endif #endif
void dStage_nextStage_c::set(const char* i_stage, s8 i_roomId, s16 i_point, s8 i_layer, s8 i_wipe, 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; return 0;
} }
} }
BOOL r26 = TRUE; BOOL r26 = TRUE;
for (int roomNo = 0; roomNo < ARRAY_SIZE(mStatus); roomNo++) { for (int roomNo = 0; roomNo < ARRAY_SIZE(mStatus); roomNo++) {
if (dStage_roomControl_c::checkStatusFlag(roomNo, 0x01)) { 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; 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) { static int dStage_roomReadInit(dStage_dt_c* i_stage, void* i_data, int param_2, void* param_3) {
UNUSED(param_2); UNUSED(param_2);
roomRead_class* p_node = (roomRead_class*)((int*)i_data + 1); 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 #endif
} }
#if TARGET_PC
if (dusk::tphd_active() && dusk::tphd::is_los_active()) {
dStage_LOSRoomReadOverride(p_node);
}
#endif
return 1; 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; dStage_MemoryConfig_data* entry_p = pd->field_0x4;
for (int i = 0; i < pd->m_num; i++) { 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); dStage_roomControl_c::setMemoryBlockID(entry_p->m_roomNo, entry_p->m_blockID);
entry_p++; entry_p++;
} }
+4
View File
@@ -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_s')))->setFont(mDoExt_getMesgFont());
static_cast<J2DTextBox*>(mpGetInScreen->search(MULTI_CHAR('get_in')))->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++) { for (int i = 0; i < 51; i++) {
m_getin_info[i].bck_frame = 0.0f; m_getin_info[i].bck_frame = 0.0f;
+18
View File
@@ -6,6 +6,10 @@
#include "d/d_path.h" #include "d/d_path.h"
#include "SSystem/SComponent/c_math.h" #include "SSystem/SComponent/c_math.h"
#if TARGET_PC
#include "dusk/logging.h"
#endif
static bool data_80450680 = true; static bool data_80450680 = true;
dTres_c::typeGroupData_c* dTres_c::mTypeGroupData; 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(); data_s* listData = p_list->field_0x4->getDataPointer();
typeGroupData_c* groupData = &mTypeGroupData[mNum]; typeGroupData_c* groupData = &mTypeGroupData[mNum];
for (int i = 0; i < p_list->field_0x0; i++, listData++, groupData++) { 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; *(data_s*)groupData = *listData;
groupData->mRoomNo = roomNo; groupData->mRoomNo = roomNo;
groupData->mStatus = 0; groupData->mStatus = 0;
u32 typeGroupNo = getTypeToTypeGroupNo(groupData->mType); 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->setNextDataPointer(NULL);
groupData->setTypeGroupNo(typeGroupNo); groupData->setTypeGroupNo(typeGroupNo);
+146
View File
@@ -8,6 +8,11 @@
#include <cstring> #include <cstring>
#ifdef DUSK_TPHD
#include <zlib.h>
#include <fstream>
#endif
namespace dusk { namespace dusk {
static const u8* s_dolData = nullptr; // pointer to dol data 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; 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 } // namespace dusk
+1
View File
@@ -311,4 +311,5 @@ std::string display_name_for_path(std::string_view path) {
#endif #endif
return fallback_display_name(path); return fallback_display_name(path);
} }
} // namespace dusk } // namespace dusk
+3
View File
@@ -19,4 +19,7 @@ void ShowFolderSelect(
std::string display_name_for_path(std::string_view path); 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 } // namespace dusk
+6
View File
@@ -20,6 +20,8 @@
#include <aurora/lib/internal.hpp> #include <aurora/lib/internal.hpp>
#include <SDL3/SDL_misc.h> #include <SDL3/SDL_misc.h>
#include "dusk/tphd/LosTable.hpp"
#if defined(__APPLE__) #if defined(__APPLE__)
#include <TargetConditionals.h> #include <TargetConditionals.h>
#endif #endif
@@ -106,6 +108,10 @@ namespace dusk {
ImGui::MenuItem("Stub Log", nullptr, &m_showStubLog); ImGui::MenuItem("Stub Log", nullptr, &m_showStubLog);
ImGui::MenuItem("Actor Spawner", nullptr, &m_showActorSpawner); ImGui::MenuItem("Actor Spawner", nullptr, &m_showActorSpawner);
if (ImGui::MenuItem("Load Cave of Shadows")) {
dusk::tphd::set_los_next_stage();
}
if (!dusk::IsGameLaunched) { if (!dusk::IsGameLaunched) {
ImGui::EndDisabled(); ImGui::EndDisabled();
} }
+31
View File
@@ -1,5 +1,8 @@
#include "dusk/settings.h" #include "dusk/settings.h"
#include "dusk/config.hpp" #include "dusk/config.hpp"
#include "dusk/main.h"
#include <system_error>
namespace dusk { namespace dusk {
@@ -158,6 +161,9 @@ UserSettings g_userSettings = {
.backend = { .backend = {
.isoPath {"backend.isoPath", ""}, .isoPath {"backend.isoPath", ""},
.isoVerification {"backend.isoVerification", DiscVerificationState::Unknown}, .isoVerification {"backend.isoVerification", DiscVerificationState::Unknown},
#if DUSK_TPHD
.hdContentPath {"backend.hdContentPath", ""},
#endif
.graphicsBackend {"backend.graphicsBackend", "auto"}, .graphicsBackend {"backend.graphicsBackend", "auto"},
.skipPreLaunchUI {"backend.skipPreLaunchUI", false}, .skipPreLaunchUI {"backend.skipPreLaunchUI", false},
.showPipelineCompilation {"backend.showPipelineCompilation", false}, .showPipelineCompilation {"backend.showPipelineCompilation", false},
@@ -212,6 +218,28 @@ UserSettings& getSettings() {
return g_userSettings; 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() { void registerSettings() {
// Video // Video
Register(g_userSettings.video.enableFullscreen); Register(g_userSettings.video.enableFullscreen);
@@ -343,6 +371,9 @@ void registerSettings() {
Register(g_userSettings.backend.isoPath); Register(g_userSettings.backend.isoPath);
Register(g_userSettings.backend.isoVerification); Register(g_userSettings.backend.isoVerification);
#if DUSK_TPHD
Register(g_userSettings.backend.hdContentPath);
#endif
Register(g_userSettings.backend.graphicsBackend); Register(g_userSettings.backend.graphicsBackend);
Register(g_userSettings.backend.skipPreLaunchUI); Register(g_userSettings.backend.skipPreLaunchUI);
Register(g_userSettings.backend.showPipelineCompilation); Register(g_userSettings.backend.showPipelineCompilation);
+691
View File
@@ -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
+78
View File
@@ -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
+89
View File
@@ -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;
}
}
+79
View File
@@ -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
+39
View File
@@ -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
+135
View File
@@ -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
+32
View File
@@ -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
+120
View File
@@ -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;
}
}
+59
View File
@@ -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
+24
View File
@@ -503,6 +503,20 @@ void file_dialog_callback(void*, const char* path, const char* error) {
begin_disc_verification(path); 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; PrelaunchState sPrelaunchState;
} // namespace } // namespace
@@ -638,6 +652,8 @@ void ensure_initialized() noexcept {
state.activeDiscPath = state.configuredDiscPath; state.activeDiscPath = state.configuredDiscPath;
state.configuredDiscValidation = state.configuredDiscValidation =
verification_from_config(getSettings().backend.isoVerification.getValue()); verification_from_config(getSettings().backend.isoVerification.getValue());
state.configuredHdContentPath = getSettings().backend.hdContentPath;
state.activeHdContentPath = state.configuredHdContentPath;
state.initialLanguage = getSettings().game.language; state.initialLanguage = getSettings().game.language;
state.initialGraphicsBackend = getSettings().backend.graphicsBackend; state.initialGraphicsBackend = getSettings().backend.graphicsBackend;
state.initialCardFileType = getSettings().backend.cardFileType; state.initialCardFileType = getSettings().backend.cardFileType;
@@ -652,11 +668,19 @@ void open_iso_picker() noexcept {
kDiscFileFilters.data(), kDiscFileFilters.size(), nullptr, false); 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 { bool is_restart_pending() noexcept {
const auto& state = prelaunch_state(); const auto& state = prelaunch_state();
if (!state.activeDiscPath.empty() && state.configuredDiscPath != state.activeDiscPath) { if (!state.activeDiscPath.empty() && state.configuredDiscPath != state.activeDiscPath) {
return true; return true;
} }
if (state.configuredHdContentPath != state.activeHdContentPath) {
return true;
}
if (data::is_data_path_restart_pending()) { if (data::is_data_path_restart_pending()) {
return true; return true;
} }
+3
View File
@@ -47,6 +47,8 @@ struct PrelaunchState {
iso::ValidationError configuredDiscValidation = iso::ValidationError::Unknown; iso::ValidationError configuredDiscValidation = iso::ValidationError::Unknown;
std::string activeDiscPath; std::string activeDiscPath;
iso::DiscInfo activeDiscInfo{}; iso::DiscInfo activeDiscInfo{};
std::string configuredHdContentPath;
std::string activeHdContentPath;
GameLanguage initialLanguage = GameLanguage::English; GameLanguage initialLanguage = GameLanguage::English;
std::string initialGraphicsBackend; std::string initialGraphicsBackend;
int initialCardFileType = 0; int initialCardFileType = 0;
@@ -60,6 +62,7 @@ PrelaunchState& prelaunch_state() noexcept;
void ensure_initialized() noexcept; void ensure_initialized() noexcept;
void refresh_configured_disc_state() noexcept; void refresh_configured_disc_state() noexcept;
void open_iso_picker() noexcept; void open_iso_picker() noexcept;
void open_folder_picker() noexcept;
bool is_restart_pending() noexcept; bool is_restart_pending() noexcept;
void try_push_verification_modal(Document& host); void try_push_verification_modal(Document& host);
+74 -5
View File
@@ -59,6 +59,22 @@ constexpr std::array kLanguageNames = {
"Italian", "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 = { constexpr std::array kCardFileTypes = {
"Card Image", "Card Image",
"GCI Folder", "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/>" pane.add_rml("Set the disc image that Dusklight uses to launch the game.<br/><br/>"
"Changes require a restart."); "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 #if DUSK_CAN_CHANGE_DATA_FOLDER
leftPane.register_control( leftPane.register_control(
leftPane.add_select_button({ leftPane.add_select_button({
@@ -625,21 +673,31 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
#endif #endif
leftPane.register_control( leftPane.register_control(
leftPane.add_select_button({ leftPane.add_select_button({
.key = "Language", .key = dusk::tphd_active() ? "Language (HD)" : "Language",
.getValue = .getValue =
[] { [] {
const auto& state = prelaunch_state(); const auto& state = prelaunch_state();
if (!state.configuredDiscCanLaunch || !state.configuredDiscInfo.isPal) { if (!state.configuredDiscCanLaunch) {
return kLanguageNames[0]; return kLanguageNames[0];
} }
const u8 idx = static_cast<u8>(getSettings().game.language.getValue()); 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]; return kLanguageNames[idx];
}, },
.isDisabled = .isDisabled =
[] { [] {
const auto& state = prelaunch_state(); const auto& state = prelaunch_state();
return !state.configuredDiscCanLaunch || return !state.configuredDiscCanLaunch ||
!state.configuredDiscInfo.isPal; (!state.configuredDiscInfo.isPal && !dusk::tphd_active());
}, },
.isModified = .isModified =
[] { [] {
@@ -648,9 +706,20 @@ SettingsWindow::SettingsWindow(bool prelaunch) : mPrelaunch(prelaunch) {
}, },
}), }),
rightPane, [](Pane& pane) { 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({ pane.add_button({
.text = kLanguageNames[i], .text = languageNames->data()[i],
.isSelected = .isSelected =
[i] { [i] {
return getSettings().game.language.getValue() == return getSettings().game.language.getValue() ==
+4 -1
View File
@@ -730,7 +730,10 @@ u8 var_r30 = fopAcM::HeapAdjustEntry;
#endif #endif
u32 size = i_size & 0xFFFFFF; 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; size *= 2;
#endif #endif
bool result = fopAcM_entrySolidHeap_(i_actor, i_heapCallback, size); bool result = fopAcM_entrySolidHeap_(i_actor, i_heapCallback, size);
+7
View File
@@ -2225,6 +2225,13 @@ void mDoExt_invJntPacket::draw() {
JUT_ASSERT(5011, shapePkt != NULL); JUT_ASSERT(5011, shapePkt != NULL);
shapePkt->getShape()->loadPreDrawSetting(); 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 { do {
if (!shapePkt->getShape()->checkFlag(1)) { if (!shapePkt->getShape()->checkFlag(1)) {
if (shapePkt->getDisplayListObj() != NULL) { if (shapePkt->getDisplayListObj() != NULL) {
+17 -3
View File
@@ -813,6 +813,18 @@ int mDoMch_Create() {
gameHeapSize += 0x200000; gameHeapSize += 0x200000;
gameHeapSize += 0x100000; gameHeapSize += 0x100000;
dynamicLinkHeapSize = 0x180000; 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 #if !DEBUG
// Fakematch because the heap sizes differ between debug and retail. // Fakematch because the heap sizes differ between debug and retail.
@@ -860,9 +872,11 @@ int mDoMch_Create() {
#if DEBUG #if DEBUG
dynamicLinkHeapSize *= 2; dynamicLinkHeapSize *= 2;
#endif #endif
archiveHeapSize *= 2; if (!dusk::tphd_active()) {
j2dHeapSize *= 2; archiveHeapSize *= 2;
gameHeapSize *= 20; // NOTE: increased from 2 to 20 to try to solve heap alloc crashes. maybe do a better fix later j2dHeapSize *= 2;
gameHeapSize *= 20; // NOTE: increased from 2 to 20 to try to solve heap alloc crashes. maybe do a better fix later
}
#endif #endif
JFWSystem::setSysHeapSize(arenaSize); JFWSystem::setSysHeapSize(arenaSize);
+17 -3
View File
@@ -90,6 +90,7 @@
#include "dusk/io.hpp" #include "dusk/io.hpp"
#include "dusk/version.hpp" #include "dusk/version.hpp"
#include "dusk/discord_presence.hpp" #include "dusk/discord_presence.hpp"
#include "dusk/tphd/HdAssetLayer.hpp"
#include "tracy/Tracy.hpp" #include "tracy/Tracy.hpp"
#include "f_pc/f_pc_draw.h" #include "f_pc/f_pc_draw.h"
#include "tracy/Tracy.hpp" #include "tracy/Tracy.hpp"
@@ -483,9 +484,9 @@ u8 OSGetLanguage() {
} }
static void LanguageInit() { 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. // Doubt this matters, but avoid funky shit.
if (!dusk::version::isRegionPal()) { if (!dusk::version::isRegionPal() && !dusk::tphd_active()) {
return; return;
} }
@@ -609,7 +610,11 @@ int game_main(int argc, char* argv[]) {
config.desiredBackend = ResolveDesiredBackend(parsed_arg_options); config.desiredBackend = ResolveDesiredBackend(parsed_arg_options);
config.logCallback = &aurora_log_callback; config.logCallback = &aurora_log_callback;
config.logLevel = startupLogLevel; 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.mem2Size = 24 * 1024 * 1024;
config.allowJoystickBackgroundEvents = dusk::getSettings().game.allowBackgroundInput; config.allowJoystickBackgroundEvents = dusk::getSettings().game.allowBackgroundInput;
config.pauseOnFocusLost = dusk::getSettings().game.pauseOnFocusLost; config.pauseOnFocusLost = dusk::getSettings().game.pauseOnFocusLost;
@@ -762,6 +767,15 @@ int game_main(int argc, char* argv[]) {
dusk::IsGameLaunched = true; 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_ENABLE_SENTRY_NATIVE
if (dusk::crash_reporting::get_consent() == dusk::crash_reporting::Consent::Unknown) { if (dusk::crash_reporting::get_consent() == dusk::crash_reporting::Consent::Unknown) {
dusk::ui::push_document(std::make_unique<dusk::ui::CrashReportWindow>()); dusk::ui::push_document(std::make_unique<dusk::ui::CrashReportWindow>());