From aca91b9361a8ba23abf97ece54921c87a91edc78 Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Tue, 1 Feb 2022 23:18:03 -0800 Subject: [PATCH] More CModel re-reverse engineering --- Runtime/Graphics/CCubeModel.cpp | 106 ++++++++++++++++++++++++-------- Runtime/Graphics/CCubeModel.hpp | 35 ++++++++--- Runtime/Graphics/CModel.hpp | 2 +- Runtime/Graphics/CModelBoo.cpp | 2 +- 4 files changed, 108 insertions(+), 37 deletions(-) diff --git a/Runtime/Graphics/CCubeModel.cpp b/Runtime/Graphics/CCubeModel.cpp index d4dc0552d..40871c516 100644 --- a/Runtime/Graphics/CCubeModel.cpp +++ b/Runtime/Graphics/CCubeModel.cpp @@ -1,9 +1,9 @@ -#include "CCubeModel.hpp" - -#include "CGraphics.hpp" - -namespace metaforce { +#include "Runtime/Graphics/CCubeModel.hpp" +#include "Runtime/Graphics/CGraphics.hpp" +#include "Runtime/CSimplePool.hpp" +//TODO Remove WIP once we've transitioned to this +namespace metaforce::WIP { #pragma region CModel u32 CModel::sTotalMemory = 0; u32 CModel::sFrameCounter = 0; @@ -12,8 +12,8 @@ CModel* CModel::sThisFrameList = nullptr; CModel* CModel::sOneFrameList = nullptr; CModel* CModel::sTwoFrameList = nullptr; -static const u8* MemoryFromPartData(const u8*& dataCur, const u32*& secSizeCur) { - const u8* ret = nullptr; +static u8* MemoryFromPartData(u8*& dataCur, const u32*& secSizeCur) { + u8* ret = nullptr; if (*secSizeCur != 0) { ret = dataCur; } @@ -27,33 +27,70 @@ CModel::CModel(std::unique_ptr in, u32 dataLen, IObjectStore* store) , x4_dataLen(dataLen) , x34_next(sThisFrameList) , x38_lastFrame(CGraphics::GetFrameCounter() - 2) { - const u8* data = reinterpret_cast(x0_data.get()); - u32 flags = *reinterpret_cast(data + 8); + u8* data = x0_data.get(); + u32 flags = hecl::SBig(*reinterpret_cast(data + 8)); u32 sectionSizeStart = 0x2c; - if (hecl::SBig(*reinterpret_cast(data + 4)) == 1) { + if (hecl::SBig(*reinterpret_cast(data + 4)) == 1) { sectionSizeStart = 0x28; } - const u32* secSizeCur = reinterpret_cast(data + sectionSizeStart); + const u32* secSizeCur = reinterpret_cast(data + sectionSizeStart); s32 numMatSets = 1; - if (hecl::SBig(*reinterpret_cast(data + 4)) > 1) { - numMatSets = hecl::SBig(*reinterpret_cast(data + 0x28)); + if (hecl::SBig(*reinterpret_cast(data + 4)) > 1) { + numMatSets = hecl::SBig(*reinterpret_cast(data + 0x28)); } - const u8* dataCur = data + ROUND_UP_32(sectionSizeStart + hecl::SBig(*reinterpret_cast(data + 0x24)) * 4); + u8* dataCur = data + ROUND_UP_32(sectionSizeStart + hecl::SBig(*reinterpret_cast(data + 0x24)) * 4); x18_matSets.reserve(numMatSets); for (s32 i = 0; i < numMatSets; ++i) { - x18_matSets.emplace_back(static_cast(MemoryFromPartData(dataCur, secSizeCur))); + x18_matSets.emplace_back(static_cast(MemoryFromPartData(dataCur, secSizeCur))); auto shader = x18_matSets.back(); CCubeModel::MakeTexturesFromMats(shader.x10_data, shader.x0_textures, true); x4_dataLen += shader.x0_textures.size() * sizeof(TCachedToken); } + /* Metaforce note: Due to padding in zeus types we need to convert these and store locally */ + u32 numVertices = hecl::SBig(*secSizeCur) / (sizeof(float) * 3); const u8* positions = MemoryFromPartData(dataCur, secSizeCur); + for (u32 i = 0; i < numVertices; ++i) { + const auto* pos = reinterpret_cast(positions + (i * (sizeof(float) * 3))); + m_positions.emplace_back(hecl::SBig(pos[0]), hecl::SBig(pos[1]), hecl::SBig(pos[2])); + } + u32 numNormals = hecl::SBig(*secSizeCur); + numNormals /= ((flags & 2) == 0 ? sizeof(float) : sizeof(s16)) * 3; const u8* normals = MemoryFromPartData(dataCur, secSizeCur); + + for (u32 i = 0; i < numNormals; ++i) { + if ((flags & 2) == 0) { + const auto* norm = reinterpret_cast(normals + (i * (sizeof(float) * 3))); + m_floatNormals.emplace_back(hecl::SBig(norm[0]), hecl::SBig(norm[1]), hecl::SBig(norm[2])); + } else { + const auto* norm = reinterpret_cast(normals + (i * (sizeof(s16) * 3))); + m_shortNormals.emplace_back(std::array{hecl::SBig(norm[0]), hecl::SBig(norm[1]), hecl::SBig(norm[2])}); + } + } + u32 numColors = hecl::SBig(*secSizeCur) / (sizeof(int)); const u8* vtxColors = MemoryFromPartData(dataCur, secSizeCur); + + for (u32 i = 0; i < numColors; ++i) { + const u32 col = hecl::SBig(*reinterpret_cast(vtxColors + (i * (sizeof(u32))))); + m_colors.emplace_back(zeus::CColor(zeus::Comp32(col))); + } + + u32 numFloatUVs = hecl::SBig(*reinterpret_cast(secSizeCur)) / (sizeof(float) * 2); const u8* floatUVs = MemoryFromPartData(dataCur, secSizeCur); - const u8* shortUVs = nullptr; - if (((flags >> 2) & 1) != 0) { - shortUVs = MemoryFromPartData(dataCur, secSizeCur); + + for (u32 i = 0; i < numFloatUVs; ++i) { + const auto* norm = reinterpret_cast(floatUVs + (i * (sizeof(float) * 2))); + m_floatUVs.emplace_back(hecl::SBig(norm[0]), hecl::SBig(norm[1])); + } + + if ((flags & 4) != 0) { + u32 numShortUVs = hecl::SBig(*reinterpret_cast(secSizeCur)) / (sizeof(s16) * 2); + const u8* shortUVs = MemoryFromPartData(dataCur, secSizeCur); + + for (u32 i = 0; i < numShortUVs; ++i) { + const auto* norm = reinterpret_cast(shortUVs + (i * (sizeof(s16) * 2))); + m_shortUVs.emplace_back(std::array{hecl::SBig(norm[0]), hecl::SBig(norm[1])}); + } } const u8* surfaceInfo = MemoryFromPartData(dataCur, secSizeCur); @@ -61,14 +98,21 @@ CModel::CModel(std::unique_ptr in, u32 dataLen, IObjectStore* store) x8_surfaces.reserve(surfaceCount); for (u32 i = 0; i < surfaceCount; ++i) { - // Implement CCubeSurface loading taking into account endian + if (x8_surfaces.capacity() <= x8_surfaces.size()) { + x8_surfaces.reserve(x8_surfaces.capacity() * 2); + } + + x8_surfaces.emplace_back(MemoryFromPartData(dataCur, secSizeCur)); } - // TODO: need to endian swap the values - const auto* aabox = reinterpret_cast(data + 12); - x28_modelInst = - std::make_unique(&x8_surfaces, &x18_matSets[0].x0_textures, x18_matSets[0].x10_data, positions, - normals, vtxColors, floatUVs, shortUVs, aabox, flags, true, -1); + const float* bounds = reinterpret_cast(data + 12); + m_aabox.min = {hecl::SBig(bounds[0]), hecl::SBig(bounds[1]), hecl::SBig(bounds[2])}; + m_aabox.max = {hecl::SBig(bounds[3]), hecl::SBig(bounds[4]), hecl::SBig(bounds[5])}; + + /* This constructor has been changed from the original to take into account platform differences */ + x28_modelInst = std::make_unique(&x8_surfaces, &x18_matSets[0].x0_textures, x18_matSets[0].x10_data, + &m_positions, &m_floatNormals, &m_shortNormals, &m_colors, &m_floatUVs, + &m_shortUVs, &m_aabox, flags, true, -1); sThisFrameList = this; if (x34_next != nullptr) { @@ -86,6 +130,7 @@ void CModel::MoveToThisFrameList() { return; } + RemoveFromList(); if (sThisFrameList != nullptr) { x34_next = sThisFrameList; x34_next->x30_prev = this; @@ -115,8 +160,8 @@ void CModel::RemoveFromList() { void CModel::FrameDone() { ++sFrameCounter; - auto* iter = sTwoFrameList; if (sIsTextureTimeoutEnabled) { + auto* iter = sTwoFrameList; while (iter != nullptr) { auto* next = iter->x34_next; iter->VerifyCurrentShader(0); @@ -148,4 +193,15 @@ void CCubeModel::MakeTexturesFromMats(const u8* ptr, std::vector&& in, u32 len, + const metaforce::CVParamTransfer& vparms, CObjectReference* selfRef) { + CSimplePool* sp = vparms.GetOwnedObj(); + CFactoryFnReturn ret = TToken::GetIObjObjectFor(std::make_unique(std::move(in), len, sp)); + return ret; +} + } // namespace metaforce diff --git a/Runtime/Graphics/CCubeModel.hpp b/Runtime/Graphics/CCubeModel.hpp index 28a8e1400..8941aa3d5 100644 --- a/Runtime/Graphics/CCubeModel.hpp +++ b/Runtime/Graphics/CCubeModel.hpp @@ -3,12 +3,12 @@ #include #include -#include "GCNTypes.hpp" -#include "IObjectStore.hpp" -#include "CTexture.hpp" -#include "CToken.hpp" +#include "Runtime/GCNTypes.hpp" +#include "Runtime/IObjectStore.hpp" +#include "Runtime/Graphics/CTexture.hpp" +#include "Runtime/CToken.hpp" -namespace metaforce { +namespace metaforce::WIP { class CCubeSurface; class CCubeModel; @@ -34,7 +34,7 @@ private: std::unique_ptr x0_data; u32 x4_dataLen; - std::vector x8_surfaces; + std::vector x8_surfaces; std::vector x18_matSets; std::unique_ptr x28_modelInst = nullptr; u16 x2c_ = 0; @@ -42,6 +42,14 @@ private: CModel* x30_prev = nullptr; CModel* x34_next; u32 x38_lastFrame; + /* Resident copies of maintained data */ + zeus::CAABox m_aabox; + std::vector m_positions; + std::vector m_floatNormals; + std::vector> m_shortNormals; + std::vector m_colors; + std::vector m_floatUVs; + std::vector> m_shortUVs; public: CModel(std::unique_ptr in, u32 dataLen, IObjectStore* store); @@ -60,9 +68,11 @@ public: #pragma region CCubeModel class CCubeModel { public: - CCubeModel(const std::vector* surfaces, const std::vector>* textures, - const u8* materialData, const u8* positions, const u8* normals, const u8* vtxColors, const u8* floatUvs, - const u8* shortUVs, const zeus::CAABox* aabox, u8 flags, bool b1, u32 w1) {} + CCubeModel(const std::vector* surfaces, const std::vector>* textures, + const u8* materialData, const std::vector* positions, + const std::vector* floatNormals, const std::vector>* shortNormals, + const std::vector* vtxColors, const std::vector* floatUvs, + const std::vector>* shortUVs, const zeus::CAABox* aabox, u8 flags, bool b1, u32 w1) {} void UnlockTextures(); @@ -72,14 +82,17 @@ public: #pragma region CCubeSurface class CCubeSurface { + static constexpr zeus::CVector3f skDefaultNormal{1.f, 0.f, 0.f}; + public: enum class ECookie { }; public: + CCubeSurface(u8* ptr); bool IsValid() const; - static CCubeSurface* FromCookieValue(u32); + static CCubeSurface* FromCookieValue(u32 value); void GetCookie(ECookie cookie); void SetCookie(ECookie cookie, u32 value); u32 GetCookieValue() const; @@ -93,4 +106,6 @@ public: }; #pragma endregion +CFactoryFnReturn FModelFactory(const metaforce::SObjectTag& tag, std::unique_ptr&& in, u32 len, + const metaforce::CVParamTransfer& vparms, CObjectReference* selfRef); } // namespace metaforce diff --git a/Runtime/Graphics/CModel.hpp b/Runtime/Graphics/CModel.hpp index 71d9cfab9..a580bb86c 100644 --- a/Runtime/Graphics/CModel.hpp +++ b/Runtime/Graphics/CModel.hpp @@ -308,7 +308,7 @@ public: static void WarmupShaders(const SObjectTag& cmdlTag); }; -CFactoryFnReturn FModelFactory(const metaforce::SObjectTag& tag, std::unique_ptr&& in, u32 len, +CFactoryFnReturn FPCModelFactory(const metaforce::SObjectTag& tag, std::unique_ptr&& in, u32 len, const metaforce::CVParamTransfer& vparms, CObjectReference* selfRef); } // namespace metaforce diff --git a/Runtime/Graphics/CModelBoo.cpp b/Runtime/Graphics/CModelBoo.cpp index 63f063e9d..26286b4b0 100644 --- a/Runtime/Graphics/CModelBoo.cpp +++ b/Runtime/Graphics/CModelBoo.cpp @@ -1335,7 +1335,7 @@ void CModel::WarmupShaders(const SObjectTag& cmdlTag) { modelObj->_WarmupShaders(); } -CFactoryFnReturn FModelFactory(const metaforce::SObjectTag& tag, std::unique_ptr&& in, u32 len, +CFactoryFnReturn FPCModelFactory(const metaforce::SObjectTag& tag, std::unique_ptr&& in, u32 len, const metaforce::CVParamTransfer& vparms, CObjectReference* selfRef) { CSimplePool* sp = vparms.GetOwnedObj(); CFactoryFnReturn ret = TToken::GetIObjObjectFor(std::make_unique(std::move(in), len, sp, selfRef));