add HD particles

This commit is contained in:
Lurs
2026-07-01 16:44:22 +02:00
parent d23a5c6fd1
commit f34e26db30
3 changed files with 72 additions and 9 deletions
+15
View File
@@ -30,6 +30,10 @@
#include "dusk/math.h"
#endif
#if DUSK_TPHD
#include "dusk/tphd/HdAssetLayer.hpp"
#endif
#if DEBUG
//#pragma nosyminline on
#endif
@@ -1205,6 +1209,10 @@ void dPa_control_c::createCommon(void const* param_0) {
mHeap = mDoExt_createSolidHeapFromSystem(0, 0);
JKRHEAP_NAME(mHeap, "dPa_control_c::mHeap");
JUT_ASSERT(2518, mHeap != NULL);
#if DUSK_TPHD
dusk::tphd::register_hd_particle_textures("common-r", (void*)param_0,
m_resHeap->getSize((void*)param_0));
#endif
mCommonResMng = JKR_NEW_ARGS (mHeap, 0) JPAResourceManager(param_0, mHeap);
JUT_ASSERT(2521, mCommonResMng != NULL);
mCommonResMng->swapTexture(mDoGph_gInf_c::getFrameBufferTimg(), "dummy");
@@ -1231,6 +1239,13 @@ void dPa_control_c::createRoomScene() {
mSceneHeap = mDoExt_createSolidHeapFromGame(0, 0);
JKRHEAP_NAME(mSceneHeap, "dPa_control_c::mSceneHeap");
JUT_ASSERT(2573, mSceneHeap != NULL);
#if DUSK_TPHD
{
char stem[16];
std::snprintf(stem, sizeof(stem), "Pscene%03u", static_cast<unsigned>(field_0x18));
dusk::tphd::register_hd_particle_textures(stem, m_sceneRes, m_resHeap->getSize(m_sceneRes));
}
#endif
mSceneResMng = JKR_NEW_ARGS (mSceneHeap, 0) JPAResourceManager(m_sceneRes, mSceneHeap);
JUT_ASSERT(2576, mSceneResMng != NULL);
mSceneResMng->swapTexture(mDoGph_gInf_c::getFrameBufferTimg(), "dummy");
+54 -9
View File
@@ -476,6 +476,14 @@ void registerHdSurface(const Gx2FormatMapping& m, const GtxSurface& s,
}
}
void applyTimgAttributes(ResTIMG* timg, const GtxSurface& s, s32 imageOffset) {
timg->imageOffset = imageOffset;
const u8 hdMips = static_cast<u8>(std::clamp<u32>(s.mipCount, 1u, 11u));
timg->mipmapCount = hdMips;
timg->maxLOD = static_cast<s8>((hdMips - 1) * 8);
timg->maxAnisotropy = GX_ANISO_4;
}
bool register_hd_bti_replacement_for_buffer(const TphdPack& pack, std::string_view resourceName,
void* buffer, size_t resourceSize, bool replaceExistingPointer) {
if (buffer == nullptr || resourceSize < 0x20 || !endsWithSuffixCI(resourceName, ".bti")) {
@@ -503,10 +511,7 @@ bool register_hd_bti_replacement_for_buffer(const TphdPack& pack, std::string_vi
}
auto* timg = reinterpret_cast<ResTIMG*>(buffer);
timg->imageOffset = 0x20;
const u8 hdMips = static_cast<u8>(std::clamp<u32>(s.mipCount, 1u, 11u));
timg->mipmapCount = hdMips;
timg->maxLOD = static_cast<s8>((hdMips - 1) * 8);
applyTimgAttributes(timg, s, 0x20);
registerHdSurface(*m, s, static_cast<u8*>(buffer) + 0x20, gtx->name, 0, replaceExistingPointer);
return true;
}
@@ -572,11 +577,7 @@ size_t register_hd_bmd_textures_for_buffer(const TphdPack& pack, std::string_vie
}
const u32 newImgOff = 0x20 + i * 0x20;
timg->imageOffset = static_cast<s32>(newImgOff);
const u8 hdMips = static_cast<u8>(std::clamp<u32>(s.mipCount, 1u, 11u));
timg->mipmapCount = hdMips;
timg->maxLOD = static_cast<s8>((hdMips - 1) * 8);
timg->maxAnisotropy = GX_ANISO_4;
applyTimgAttributes(timg, s, static_cast<s32>(newImgOff));
registerHdSurface(*m, s, bmdBytes.data() + btiAbs + newImgOff, gtx->name, i,
replaceExistingPointer);
++reg;
@@ -894,6 +895,50 @@ void rebuild_hd_overlay_locked() {
}
void register_hd_particle_textures(std::string_view jpcStem, void* jpcBuffer, size_t jpcSize) {
if (g_contentPath.empty() || jpcBuffer == nullptr || jpcSize < 0x10) return;
auto* jpc = static_cast<u8*>(jpcBuffer);
if (std::memcmp(jpc, "JPAC2-10", 8) != 0) return;
const std::filesystem::path sidecar =
g_contentPath / "tex" / "Particle" / (std::string(jpcStem) + ".jpc.gtx.gz");
auto gz = read_file(sidecar);
if (!gz) return;
auto gfx2 = decompressGzip(*gz);
if (!gfx2) return;
auto surfaces = parseGtx(*gfx2);
if (surfaces.empty()) return;
// JPAC2-10 header: texture count @ +0x0A (BE u16), texture table @ +0x0C (BE u32).
const u32 texCnt = *reinterpret_cast<const BE(u16)*>(jpc + 0x0A);
const u32 texTableOff = *reinterpret_cast<const BE(u32)*>(jpc + 0x0C);
if (texCnt != surfaces.size()) {
HdLog.warn("HD particle {}: jpc texCnt {} != sidecar surfaces {} -> skip",
jpcStem, texCnt, surfaces.size());
return;
}
size_t reg = 0;
u32 off = texTableOff;
for (u32 i = 0; i < texCnt && off + 0x40 <= jpcSize; ++i) {
const u32 entrySize = *reinterpret_cast<const BE(u32)*>(jpc + off + 4);
const char* texName = reinterpret_cast<const char*>(jpc + off + 0x0C);
const auto& s = surfaces[i];
const Gx2FormatMapping* m = s.baseData.empty() ? nullptr : findFormatMapping(s.format);
if (m != nullptr && std::strncmp(texName, "dummy", 5) != 0) {
auto* timg = reinterpret_cast<ResTIMG*>(jpc + off + 0x20);
const s32 stored = timg->imageOffset;
const s32 imgOff = stored ? stored : 0x20;
applyTimgAttributes(timg, s, imgOff);
const void* pixelPtr = reinterpret_cast<const u8*>(timg) + imgOff;
registerHdSurface(*m, s, pixelPtr, jpcStem, i, true);
++reg;
}
off += entrySize ? entrySize : 0x40;
}
HdLog.info("registerHdParticle[{}]: {}/{} textures registered", jpcStem, reg, texCnt);
}
void set_hd_content_path(std::filesystem::path contentPath) {
g_contentPath = std::move(contentPath);
std::lock_guard lk{g_cacheMutex};
+3
View File
@@ -30,6 +30,9 @@ void register_mounted_hd_archive(s32 entryNum, void* arcBytes, size_t arcSize);
void register_copied_hd_resource(s32 entryNum, std::string_view resourceName, void* buffer,
size_t resourceSize);
// Register HD particle textures which live in a loose `tex/Particle/<jpcStem>.jpc.gtx.gz` sidecar
void register_hd_particle_textures(std::string_view jpcStem, void* jpcBuffer, size_t jpcSize);
// 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);