diff --git a/Editor/ProjectResourceFactoryBase.cpp b/Editor/ProjectResourceFactoryBase.cpp index 5fc6988b9..a7c892d1f 100644 --- a/Editor/ProjectResourceFactoryBase.cpp +++ b/Editor/ProjectResourceFactoryBase.cpp @@ -281,9 +281,9 @@ bool ProjectResourceFactoryBase::SyncCook(const hecl::ProjectPath& working) return m_clientProc.syncCook(working, m_cookSpec.get(), hecl::SharedBlenderToken); } -CFactoryFnReturn ProjectResourceFactoryBase::SyncMakeObject(const SObjectTag& tag, - const hecl::ProjectPath& path, - const CVParamTransfer& paramXfer) +CFactoryFnReturn ProjectResourceFactoryBase::BuildSync(const SObjectTag& tag, + const hecl::ProjectPath& path, + const CVParamTransfer& paramXfer) { /* Ensure requested resource is on the filesystem */ if (path.getPathType() != hecl::ProjectPath::Type::File) @@ -319,6 +319,13 @@ CFactoryFnReturn ProjectResourceFactoryBase::SyncMakeObject(const SObjectTag& ta } /* All good, build resource */ + if (m_factoryMgr.CanMakeMemory(tag)) + { + u32 length = fr.length(); + std::unique_ptr memBuf = fr.readUBytes(length); + return m_factoryMgr.MakeObjectFromMemory(tag, std::move(memBuf), length, false, paramXfer); + } + return m_factoryMgr.MakeObject(tag, fr, paramXfer); } @@ -419,7 +426,7 @@ std::unique_ptr ProjectResourceFactoryBase::Build(const urde::SObjec return {}; } - return SyncMakeObject(tag, search->second, paramXfer); + return BuildSync(tag, search->second, paramXfer); } void ProjectResourceFactoryBase::BuildAsync(const urde::SObjectTag& tag, diff --git a/Editor/ProjectResourceFactoryBase.hpp b/Editor/ProjectResourceFactoryBase.hpp index a18a748ac..72e7bae28 100644 --- a/Editor/ProjectResourceFactoryBase.hpp +++ b/Editor/ProjectResourceFactoryBase.hpp @@ -82,8 +82,8 @@ protected: hecl::ProjectPath GetCookedPath(const hecl::ProjectPath& working, bool pcTarget) const; bool SyncCook(const hecl::ProjectPath& working); - CFactoryFnReturn SyncMakeObject(const SObjectTag& tag, const hecl::ProjectPath& path, - const CVParamTransfer& paramXfer); + CFactoryFnReturn BuildSync(const SObjectTag& tag, const hecl::ProjectPath& path, + const CVParamTransfer& paramXfer); public: ProjectResourceFactoryBase(hecl::ClientProcess& clientProc) : m_clientProc(clientProc) {} diff --git a/Editor/ProjectResourceFactoryMP1.cpp b/Editor/ProjectResourceFactoryMP1.cpp index 45aacc5c7..d7b2df1f7 100644 --- a/Editor/ProjectResourceFactoryMP1.cpp +++ b/Editor/ProjectResourceFactoryMP1.cpp @@ -28,6 +28,7 @@ ProjectResourceFactoryMP1::ProjectResourceFactoryMP1(hecl::ClientProcess& client m_factoryMgr.AddFactory(FOURCC('PART'), urde::FParticleFactory); m_factoryMgr.AddFactory(FOURCC('FRME'), urde::RGuiFrameFactoryInGame); m_factoryMgr.AddFactory(FOURCC('FONT'), urde::FRasterFontFactory); + m_factoryMgr.AddFactory(FOURCC('CMDL'), urde::FModelFactory); } void ProjectResourceFactoryMP1::IndexMP1Resources(hecl::Database::Project& proj) diff --git a/Runtime/CFactoryMgr.cpp b/Runtime/CFactoryMgr.cpp index 48ac66cf0..70d1097c7 100644 --- a/Runtime/CFactoryMgr.cpp +++ b/Runtime/CFactoryMgr.cpp @@ -14,22 +14,53 @@ CFactoryFnReturn CFactoryMgr::MakeObject(const SObjectTag& tag, urde::CInputStre return search->second(tag, in, paramXfer); } -CFactoryFnReturn CFactoryMgr::MakeObjectFromMemory(const SObjectTag& tag, void* buf, int size, +bool CFactoryMgr::CanMakeMemory(const urde::SObjectTag& tag) const +{ + auto search = m_memFactories.find(tag.type); + return search != m_memFactories.cend(); +} + +CFactoryFnReturn CFactoryMgr::MakeObjectFromMemory(const SObjectTag& tag, std::unique_ptr&& buf, int size, bool compressed, const CVParamTransfer& paramXfer) { - auto search = m_factories.find(tag.type); - if (search == m_factories.end()) - return {}; + std::unique_ptr localBuf = std::move(buf); - if (compressed) + auto search = m_memFactories.find(tag.type); + if (search != m_memFactories.cend()) { - CZipInputStream r(std::make_unique(buf, size)); - return search->second(tag, r, paramXfer); + if (compressed) + { + std::unique_ptr compRead = + std::make_unique(localBuf.get(), size); + u32 decompLen = compRead->readUint32Big(); + CZipInputStream r(std::move(compRead)); + std::unique_ptr decompBuf = r.readUBytes(decompLen); + return search->second(tag, std::move(decompBuf), decompLen, paramXfer); + } + else + { + return search->second(tag, std::move(localBuf), size, paramXfer); + } } else { - CMemoryInStream r(buf, size); - return search->second(tag, r, paramXfer); + auto search = m_factories.find(tag.type); + if (search == m_factories.end()) + return {}; + + if (compressed) + { + std::unique_ptr compRead = + std::make_unique(localBuf.get(), size); + u32 decompLen = compRead->readUint32Big(); + CZipInputStream r(std::move(compRead)); + return search->second(tag, r, paramXfer); + } + else + { + CMemoryInStream r(localBuf.get(), size); + return search->second(tag, r, paramXfer); + } } } diff --git a/Runtime/CFactoryMgr.hpp b/Runtime/CFactoryMgr.hpp index e77af4179..65596718d 100644 --- a/Runtime/CFactoryMgr.hpp +++ b/Runtime/CFactoryMgr.hpp @@ -15,18 +15,27 @@ using CFactoryFnReturn = std::unique_ptr; using FFactoryFunc = std::function; +using FMemFactoryFunc = std::function&& in, u32 len, + const urde::CVParamTransfer& vparms)>; class CFactoryMgr { std::unordered_map m_factories; + std::unordered_map m_memFactories; public: CFactoryFnReturn MakeObject(const SObjectTag& tag, urde::CInputStream& in, const CVParamTransfer& paramXfer); - CFactoryFnReturn MakeObjectFromMemory(const SObjectTag& tag, void* buf, int size, bool compressed, + bool CanMakeMemory(const urde::SObjectTag& tag) const; + CFactoryFnReturn MakeObjectFromMemory(const SObjectTag& tag, std::unique_ptr&& buf, int size, bool compressed, const CVParamTransfer& paramXfer); void AddFactory(FourCC key, FFactoryFunc func) { m_factories[key] = func; } + void AddFactory(FourCC key, FMemFactoryFunc func) + { + m_memFactories[key] = func; + } }; } diff --git a/Runtime/Graphics/CModel.hpp b/Runtime/Graphics/CModel.hpp index 8f2e0e988..39112e85c 100644 --- a/Runtime/Graphics/CModel.hpp +++ b/Runtime/Graphics/CModel.hpp @@ -3,9 +3,14 @@ #include "RetroTypes.hpp" #include "zeus/CColor.hpp" +#include "CFactoryMgr.hpp" +#include "CToken.hpp" +#include "zeus/CAABox.hpp" namespace urde { +class IObjectStore; +class CTexture; struct CModelFlags { @@ -20,14 +25,66 @@ struct CModelFlags */ }; +class CBooModel +{ +public: + struct CSurface + { + const u8* m_data; + CBooModel* m_parent = nullptr; + CSurface* m_next = nullptr; + }; +private: + std::vector* x0_surfaces; + const u8* x4_matSet; + const void* x8_vbo; + const void* xc_ibo; + std::vector>* x1c_textures; + zeus::CAABox x20_aabb; + CSurface* x38_firstUnsortedSurface = nullptr; + CSurface* x3c_firstSortedSurface = nullptr; + bool x40_24_ : 1; + bool x40_25_ : 1; + u8 x41_shortNormals; +public: + CBooModel(std::vector* surfaces, std::vector>* textures, + const u8* matSet, const void* vbo, const void* ibo, const zeus::CAABox& aabb, + u8 shortNormals, bool unk); + + static void MakeTexuresFromMats(const u8* dataIn, + std::vector>& toksOut, + IObjectStore& store); + + const u8* GetMaterialByIndex(int idx) const; +}; + class CModel { public: + struct SShader + { + std::vector> x0_textures; + const u8* x10_data; + }; +private: + std::unique_ptr x0_data; + u32 x4_dataLen; + std::vector x8_surfaces; + std::vector x18_matSets; + std::unique_ptr x28_modelInst; + CModel* x30_next = nullptr; + CModel* x34_prev = nullptr; +public: + CModel(std::unique_ptr&& in, u32 dataLen, IObjectStore* store); void Draw(const CModelFlags& flags) const; void Touch(int) const; bool IsLoaded(int) const; }; +CFactoryFnReturn FModelFactory(const urde::SObjectTag& tag, + std::unique_ptr&& in, u32 len, + const urde::CVParamTransfer& vparms); + } #endif // __PSHAG_CMODEL_HPP__ diff --git a/Runtime/Graphics/CModelBoo.cpp b/Runtime/Graphics/CModelBoo.cpp index e6f07b1fa..22e2e9d8e 100644 --- a/Runtime/Graphics/CModelBoo.cpp +++ b/Runtime/Graphics/CModelBoo.cpp @@ -2,6 +2,120 @@ namespace urde { +static logvisor::Module Log("urde::CModelBoo"); + +CBooModel::CBooModel(std::vector* surfaces, std::vector>* textures, + const u8* matSet, const void* vbo, const void* ibo, const zeus::CAABox& aabb, + u8 shortNormals, bool unk) +: x0_surfaces(surfaces), x4_matSet(matSet), x8_vbo(vbo), xc_ibo(ibo), x1c_textures(textures), + x20_aabb(aabb), x40_24_(unk), x40_25_(0), x41_shortNormals(shortNormals) +{ + for (CSurface& surf : *x0_surfaces) + surf.m_parent = this; + + for (auto it=x0_surfaces->rbegin() ; it != x0_surfaces->rend() ; ++it) + { + u32 matId = hecl::SBig(*reinterpret_cast(it->m_data + 0xc)); + const u8* matData = GetMaterialByIndex(matId); + u32 matFlags = hecl::SBig(*reinterpret_cast(matData)); + if (matFlags & 0x10) + { + it->m_next = x3c_firstSortedSurface; + x3c_firstSortedSurface = &*it; + } + else + { + it->m_next = x38_firstUnsortedSurface; + x38_firstUnsortedSurface = &*it; + } + } +} + +void CBooModel::MakeTexuresFromMats(const u8* dataIn, + std::vector>& toksOut, + IObjectStore& store) +{ + u32 texCount = hecl::SBig(*reinterpret_cast(dataIn)); + dataIn += 4; + toksOut.reserve(texCount); + for (u32 i=0 ; i(dataIn)); + dataIn += 4; + toksOut.emplace_back(store.GetObj({SBIG('TXTR'), id})); + } +} + +const u8* CBooModel::GetMaterialByIndex(int idx) const +{ + const u32* matOffs = reinterpret_cast(x4_matSet + (x1c_textures->size() + 1) * 4); + u32 matCount = hecl::SBig(*matOffs); + ++matOffs; + + const u8* materialBase = reinterpret_cast(matOffs + matCount); + if (idx == 0) + return materialBase; + + u32 offset = hecl::SBig(matOffs[idx-1]); + return materialBase + offset; +} + +static const u8* MemoryFromPartData(const u8*& dataCur, const s32*& secSizeCur) +{ + const u8* ret; + if (*secSizeCur) + ret = dataCur; + else + ret = nullptr; + + dataCur += hecl::SBig(*secSizeCur); + ++secSizeCur; + return ret; +} + +CModel::CModel(std::unique_ptr&& in, u32 dataLen, IObjectStore* store) +: x0_data(std::move(in)), x4_dataLen(dataLen) +{ + u32 version = hecl::SBig(*reinterpret_cast(x0_data.get() + 0x4)); + u32 flags = hecl::SBig(*reinterpret_cast(x0_data.get() + 0x8)); + if (version != 16) + Log.report(logvisor::Fatal, "invalid CMDL for loading with boo"); + + u32 secCount = hecl::SBig(*reinterpret_cast(x0_data.get() + 0x24)); + u32 matSetCount = hecl::SBig(*reinterpret_cast(x0_data.get() + 0x28)); + x18_matSets.reserve(matSetCount); + const u8* dataCur = x0_data.get() + ROUND_UP_32(0x2c + secCount * 4); + const s32* secSizeCur = reinterpret_cast(x0_data.get() + 0x2c); + for (u32 i=0 ; i(surfInfo)); + x8_surfaces.reserve(surfCount); + for (u32 i=0 ; i(x0_data.get() + 0x18); + zeus::CAABox aabb(hecl::SBig(aabbPtr[0]), hecl::SBig(aabbPtr[1]), hecl::SBig(aabbPtr[2]), + hecl::SBig(aabbPtr[3]), hecl::SBig(aabbPtr[4]), hecl::SBig(aabbPtr[5])); + x28_modelInst = std::make_unique(&x8_surfaces, &x18_matSets[0].x0_textures, + x18_matSets[0].x10_data, vboData, iboData, + aabb, flags & 0x2, true); +} void CModel::Draw(const CModelFlags& flags) const { @@ -16,4 +130,12 @@ bool CModel::IsLoaded(int) const return false; } +CFactoryFnReturn FModelFactory(const urde::SObjectTag& tag, + std::unique_ptr&& in, u32 len, + const urde::CVParamTransfer& vparms) +{ + IObjectStore* store = static_cast*>(vparms.GetObj())->GetParam(); + return TToken::GetIObjObjectFor(std::make_unique(std::move(in), len, store)); +} + }