From 152890a4f55a8e20489558c0a2f2b7a8e5267753 Mon Sep 17 00:00:00 2001 From: Nitr4m12 <67806925+Nitr4m12@users.noreply.github.com> Date: Tue, 11 Aug 2026 16:29:45 -0400 Subject: [PATCH] g3d: Implement `nn::g3d::ResFile` --- CMakeLists.txt | 3 + include/nn/g3d/ResFile.h | 87 +++++++++------- include/nn/g3d/ResMaterialAnim.h | 4 +- include/nn/g3d/ResModel.h | 7 +- include/nn/g3d/ResSceneAnim.h | 34 +++---- include/nn/g3d/ResShapeAnim.h | 7 +- include/nn/g3d/ResSkeletalAnim.h | 4 + include/nn/g3d/detail/g3d_CommonHelper.h | 11 +++ include/nn/gfx/gfx_Device.h | 2 + include/nn/gfx/gfx_MemoryPool.h | 16 ++- src/NintendoWare/g3d/.gitkeep | 0 src/NintendoWare/g3d/g3d_ResFile.cpp | 120 +++++++++++++++++++++++ 12 files changed, 235 insertions(+), 60 deletions(-) create mode 100644 include/nn/g3d/detail/g3d_CommonHelper.h delete mode 100644 src/NintendoWare/g3d/.gitkeep create mode 100644 src/NintendoWare/g3d/g3d_ResFile.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 77d547e4..65fedbd6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -188,6 +188,7 @@ add_library(NintendoSDK OBJECT include/nn/ui2d/Parts.h include/nn/ui2d/Types.h include/nn/ui2d/Util.h + include/nn/g3d/detail/g3d_CommonHelper.h include/nn/g3d/BindFuncTable.h include/nn/g3d/ModelObj.h include/nn/g3d/ResMaterialAnim.h @@ -282,6 +283,8 @@ add_library(NintendoSDK OBJECT src/NintendoSDK/nvn/nvn_CppFuncPtrImpl.h src/NintendoSDK/nvn/nvn_FuncPtrImpl.h src/NintendoSDK/nvn/nvn_Impl.cpp + + src/NintendoWare/g3d/g3d_ResFile.cpp ) target_include_directories(NintendoSDK PUBLIC include/) diff --git a/include/nn/g3d/ResFile.h b/include/nn/g3d/ResFile.h index 8578514e..587d19fa 100644 --- a/include/nn/g3d/ResFile.h +++ b/include/nn/g3d/ResFile.h @@ -5,10 +5,15 @@ #pragma once -#include #include + +#include +#include +#include + #include #include +#include namespace nn { @@ -22,49 +27,63 @@ class ResModel; class ResMaterialAnim; class ResShapeAnim; class ResSceneAnim; -typedef void* TextureRef; +class ResSkeletalAnim; +class ResBoneVisibilityAnim; +struct TextureRef; + +using TextureBindCallback = nn::g3d::TextureRef (*)(char const*, void*); + +struct ResFileData { + util::BinaryFileHeader fileHeader; + util::BinTPtr pFileName; + util::BinTPtr pModels; + util::BinTPtr pModelDict; + util::BinTPtr pSkeletalAnims; + util::BinTPtr pSkeletalAnimDict; + util::BinTPtr pMaterialAnims; + util::BinTPtr pMaterialAnimsDict; + util::BinTPtr pBoneVisibilityAnims; + util::BinTPtr pBoneVisiDict; + util::BinTPtr pShapeAnims; + util::BinTPtr pShapeAnimDict; + util::BinTPtr pSceneAnims; + util::BinTPtr pSceneAnimDict; + util::BinTPtr pMemoryPool; + util::BinTPtr pMemoryPoolInfo; + u64 embeddedFilesOffset; + util::BinTPtr pEmbeddedFilesDict; + u64 padding; + u64 strTableOffset; + u32 strTableSize; + u16 modelCount; + u16 skeletalAnimCount; + u16 materialAnimCount; + u16 boneAnimCount; + u16 shapeAnimCount; + u16 sceneAnimCount; + u16 externalFileCount; +}; -class ResFile : public nn::util::BinaryFileHeader { +class ResFile : public nn::util::AccessorBase { public: - static bool IsValid(void const* modelSrc); + static constexpr s64 Signature = 0x2020202053455246; // "FRES " + + static bool IsValid(const void* modelSrc); + void Relocate(); void Unrelocate(); + static nn::g3d::ResFile* ResCast(void*); - s32 BindTexture(nn::g3d::TextureRef (*ref)(char const*, void*), void*); + + s32 BindTexture(TextureBindCallback callback, void*); void ReleaseTexture(); + void Setup(gfx::Device*); void Setup(gfx::Device*, gfx::MemoryPool*, s64, u64); + void Cleanup(gfx::Device*); void Reset(); - - u64 mFileNameLength; // _20 - nn::g3d::ResModel* mModels; // _28 - u64 mModelDictOffset; // _30 - u64 mSkeleAnimOffset; // _38 - u64 mSkeleAnimDictOffset; // _40 - nn::g3d::ResMaterialAnim* mMatAnims; // _48 - u64 mMatAnimsDictOffset; // _50 - u64 mBoneVisiOffset; // _58 - u64 mBoneVisiDictOffset; // _60 - nn::g3d::ResShapeAnim* mShapeAnims; // _68 - u64 mShapeAnimDictOffset; // _70 - nn::g3d::ResSceneAnim* mSceneAnims; // _78 - u64 mSceneAnimDictOffset; // _80 - u64 mMemoryPool; // _88 - u64 mBufferSection; // _90 - u64 mEmbeddedFilesOffset; // _98 - u64 mEmbeddedFilesDictOffset; // _A0 - u64 mPadding; // _A8 - u64 mStrTableOffset; // _B0 - u32 mStrTableSize; // _B8 - u16 mModelCount; // _BC - u16 mSkeleAnimCount; // _BE - u16 mMatAnimCount; // _C0 - u16 mBoneAnimCount; // _C2 - u16 mShapeAnimCount; // _C4 - u16 mSceneAnimCount; // _C6 - u16 mExternalFileCount; // _C8 - u8 mPad[0x6]; // _CA }; +static_assert(sizeof(ResFile) == 0xd0); } // namespace g3d } // namespace nn diff --git a/include/nn/g3d/ResMaterialAnim.h b/include/nn/g3d/ResMaterialAnim.h index 02580cee..e3e0dab6 100644 --- a/include/nn/g3d/ResMaterialAnim.h +++ b/include/nn/g3d/ResMaterialAnim.h @@ -9,13 +9,15 @@ namespace nn { namespace g3d { -typedef void* TextureRef; +struct TextureRef; class ResMaterialAnim { public: void ReleaseTexture(); s32 BindTexture(nn::g3d::TextureRef (*)(char const*, void*), void*); void Reset(); + + u8 _0[0x78]; }; } // namespace g3d } // namespace nn diff --git a/include/nn/g3d/ResModel.h b/include/nn/g3d/ResModel.h index 0c72dc86..7d80f27c 100644 --- a/include/nn/g3d/ResModel.h +++ b/include/nn/g3d/ResModel.h @@ -12,20 +12,21 @@ namespace nn { namespace g3d { class ResMaterial; -typedef void* TextureRef; +struct TextureRef; class ResModel { public: - u64 BindTexture(nn::g3d::TextureRef (*)(char const*, void*), void*); + s32 BindTexture(nn::g3d::TextureRef (*)(char const*, void*), void*); void ForceBindTexture(nn::g3d::TextureRef const&, char const*); void ReleaseTexture(); void Setup(gfx::Device*); + void Setup(gfx::Device*, gfx::MemoryPool*, s64); void Cleanup(gfx::Device*); void Reset(); void Reset(u32); nn::g3d::ResMaterial* FindMaterial(char const* materialName) const; - u8 _0[0x70]; + u8 _0[0x78]; }; } // namespace g3d } // namespace nn diff --git a/include/nn/g3d/ResSceneAnim.h b/include/nn/g3d/ResSceneAnim.h index 2df7bffa..6ddd1c26 100644 --- a/include/nn/g3d/ResSceneAnim.h +++ b/include/nn/g3d/ResSceneAnim.h @@ -6,6 +6,7 @@ #pragma once #include +#include namespace nn { namespace g3d { @@ -13,29 +14,26 @@ class ResLightAnim; class ResFogAnim; class BindFuncTable; -class ResSceneAnim { +class ResSceneAnim : public util::BinaryBlockHeader { public: s32 Bind(nn::g3d::BindFuncTable const&); void Release(); void Reset(); - char mMagic[4]; // _0 - s32 mBlockOffset; // _4 - u64 mBlockSize; // _8 - u64 mNameOffset; // _10 - u64 mPathOffset; // _18 - u64 mCameraAnimOffset; // _20 - u64 mCameraAnimDictOffset; // _28 - nn::g3d::ResLightAnim* mLightAnims; // _30 - u64 mLightAnimDictOffset; // _38 - nn::g3d::ResFogAnim* mFogAnims; // _40 - u64 mFogAnimDictOffset; // _48 - u64 mUserDataOffset; // _50 - u64 mUserDataDictOffset; // _58 - u16 mUserDataCount; // _60 - u16 mCameraAnimCount; // _62 - u16 mLightAnimCount; // _64 - u16 mFogAnimCount; // _66 + u64 mNameOffset; + u64 mPathOffset; + u64 mCameraAnimOffset; + u64 mCameraAnimDictOffset; + nn::g3d::ResLightAnim* mLightAnims; + u64 mLightAnimDictOffset; + nn::g3d::ResFogAnim* mFogAnims; + u64 mFogAnimDictOffset; + u64 mUserDataOffset; + u64 mUserDataDictOffset; + u16 mUserDataCount; + u16 mCameraAnimCount; + u16 mLightAnimCount; + u16 mFogAnimCount; }; } // namespace g3d } // namespace nn diff --git a/include/nn/g3d/ResShapeAnim.h b/include/nn/g3d/ResShapeAnim.h index 9f6f7b94..d526a43d 100644 --- a/include/nn/g3d/ResShapeAnim.h +++ b/include/nn/g3d/ResShapeAnim.h @@ -5,11 +5,16 @@ #pragma once +#include +#include + namespace nn { namespace g3d { -class ResShapeAnim { +class ResShapeAnim : util::BinaryBlockHeader { public: void Reset(); + + u8 _0[0x50]; }; } // namespace g3d } // namespace nn diff --git a/include/nn/g3d/ResSkeletalAnim.h b/include/nn/g3d/ResSkeletalAnim.h index 51db1be6..73d322ac 100644 --- a/include/nn/g3d/ResSkeletalAnim.h +++ b/include/nn/g3d/ResSkeletalAnim.h @@ -5,11 +5,15 @@ #pragma once +#include + namespace nn { namespace g3d { class ResSkeletalAnim { public: void Reset(); + + u8 _0[0x60]; }; } // namespace g3d } // namespace nn diff --git a/include/nn/g3d/detail/g3d_CommonHelper.h b/include/nn/g3d/detail/g3d_CommonHelper.h new file mode 100644 index 00000000..f2ac6ec5 --- /dev/null +++ b/include/nn/g3d/detail/g3d_CommonHelper.h @@ -0,0 +1,11 @@ +#include + +namespace nn::g3d::detail { + +NN_MIDDLEWARE(g_MiddlewareInfo, "Nintendo", "NintendoWare_G3d" NN_SDK_BUILD_STR); + +inline void UseMiddleWare() { + nn::util::ReferSymbol(g_MiddlewareInfo); +} + +} // namespace nn::g3d::detail \ No newline at end of file diff --git a/include/nn/gfx/gfx_Device.h b/include/nn/gfx/gfx_Device.h index 188e05ba..45aa654f 100644 --- a/include/nn/gfx/gfx_Device.h +++ b/include/nn/gfx/gfx_Device.h @@ -27,6 +27,8 @@ class TDevice : public detail::DeviceImpl, public: typedef DeviceInfo InfoType; + using detail::DeviceImpl::DeviceImpl; + static size_t GetRequiredMemorySize(const InfoType&); TDevice(); diff --git a/include/nn/gfx/gfx_MemoryPool.h b/include/nn/gfx/gfx_MemoryPool.h index 0ce29f26..262a4997 100644 --- a/include/nn/gfx/gfx_MemoryPool.h +++ b/include/nn/gfx/gfx_MemoryPool.h @@ -2,6 +2,7 @@ #include #include +#include namespace nn::gfx { @@ -12,13 +13,22 @@ class TMemoryPool : public detail::MemoryPoolImpl { public: typedef MemoryPoolInfo InfoType; + using detail::MemoryPoolImpl::MemoryPoolImpl; + static size_t GetPoolMemoryAlignment(TDevice*, const InfoType&); static size_t GetPoolMemorySizeGranularity(TDevice*, const InfoType&); - TMemoryPool(); + void Initialize(TDevice* device, const InfoType& info, const char* debugLabel) { + new (this) TMemoryPool(); + detail::MemoryPoolImpl::Initialize(device, info); + util::SetMemoryPoolDebugLabel(this, debugLabel); + } + + void Finalize(TDevice* device) { + detail::MemoryPoolImpl::Finalize(device); + this->~TMemoryPool(); + } - void Initialize(TDevice*, const InfoType&); - void Finalize(TDevice*); void* Map() const; void Unmap() const; void FlushMappedRange(ptrdiff_t, size_t) const; diff --git a/src/NintendoWare/g3d/.gitkeep b/src/NintendoWare/g3d/.gitkeep deleted file mode 100644 index e69de29b..00000000 diff --git a/src/NintendoWare/g3d/g3d_ResFile.cpp b/src/NintendoWare/g3d/g3d_ResFile.cpp new file mode 100644 index 00000000..1f501cfa --- /dev/null +++ b/src/NintendoWare/g3d/g3d_ResFile.cpp @@ -0,0 +1,120 @@ +#include + +#include + +#include +#include +#include +#include +#include + +#include + +namespace nn::g3d { + +bool ResFile::IsValid(const void* modelSrc) { + return reinterpret_cast(modelSrc)->IsValid(Signature, 8, 0, 0); +} + +void ResFile::Relocate() { + if (!fileHeader.IsRelocated()) + fileHeader.GetRelocationTable()->Relocate(); +} + +void ResFile::Unrelocate() { + if (fileHeader.IsRelocated()) + fileHeader.GetRelocationTable()->Unrelocate(); +} + +ResFile* ResFile::ResCast(void* ptr) { + auto* file = reinterpret_cast(ptr); + + if (ptr != nullptr) { + file->Relocate(); + file->fileHeader.IsEndianReverse(); + } + + return file; +} + +s32 ResFile::BindTexture(TextureBindCallback callback, void* ptr) { + s32 result = 0; + + s32 mdlCount = modelCount; + for (s32 i{0}; i < mdlCount; ++i) + result |= pModels.Get()[i].BindTexture(callback, ptr); + + s32 matAnimCount = materialAnimCount; + for (s32 i{0}; i < matAnimCount; ++i) + result |= pMaterialAnims.Get()[i].BindTexture(callback, ptr); + + return result; +} + +void ResFile::ReleaseTexture() { + s32 mdlCount = modelCount; + for (s32 i{0}; i < mdlCount; ++i) + pModels.Get()[i].ReleaseTexture(); + + s32 matAnimCount = materialAnimCount; + for (s32 i{0}; i < matAnimCount; ++i) + pMaterialAnims.Get()[i].ReleaseTexture(); +} + +void ResFile::Setup(gfx::Device* device) { + detail::UseMiddleWare(); + + if (pMemoryPool.Get() != nullptr && pMemoryPoolInfo.Get() != nullptr) + pMemoryPool.Get()->Initialize(device, *pMemoryPoolInfo.Get(), "g3d"); + + s32 mdlCount = modelCount; + for (s32 i{0}; i < mdlCount; ++i) + pModels.Get()[i].Setup(device); +} + +void ResFile::Setup(gfx::Device* device, gfx::MemoryPool* memPool, s64 bufferOffset, + [[maybe_unused]] u64 p3) { + if (pMemoryPool.Get() != nullptr && pMemoryPoolInfo.Get() != nullptr) + bufferOffset = reinterpret_cast(pMemoryPoolInfo.Get()->GetPoolMemory()) + + (bufferOffset - reinterpret_cast(this)); + + s32 mdlCount = modelCount; + for (s32 i{0}; i < mdlCount; ++i) + pModels.Get()[i].Setup(device, memPool, bufferOffset); +} + +void ResFile::Cleanup(gfx::Device* device) { + s32 mdlCount = modelCount; + for (s32 i{0}; i < mdlCount; ++i) + pModels.Get()[i].Cleanup(device); + + if (pMemoryPoolInfo.Get() != nullptr && + pMemoryPool.Get()->ToData()->state != gfx::MemoryPool::DataType::State_NotInitialized) + pMemoryPool.Get()->Finalize(device); +} + +void ResFile::Reset() { + s32 mdlCount = modelCount; + for (s32 i{0}; i < mdlCount; ++i) + pModels.Get()[i].Reset(); + + s32 sklAnimCount = skeletalAnimCount; + for (s32 i{0}; i < sklAnimCount; ++i) + pSkeletalAnims.Get()[i].Reset(); + + s32 matAnimCount = materialAnimCount; + for (s32 i{0}; i < matAnimCount; ++i) + pMaterialAnims.Get()[i].Reset(); + + s32 shpAnimCount = shapeAnimCount; + for (s32 i{0}; i < shpAnimCount; ++i) + pShapeAnims.Get()[i].Reset(); + + s32 scnAnimCount = sceneAnimCount; + for (s32 i{0}; i < scnAnimCount; ++i) + pSceneAnims.Get()[i].Reset(); + + padding = 0; +} + +} // namespace nn::g3d \ No newline at end of file