From b71e1268fa6e07877ec3e54bce43b0315466e369 Mon Sep 17 00:00:00 2001 From: parax0 Date: Thu, 14 Jan 2016 21:15:06 -0700 Subject: [PATCH] Added experimental code for re-splitting world meshes in MP2/3/DKCR --- src/Core/Resource/Factory/CAreaLoader.cpp | 20 ++++++- src/Core/Resource/Factory/CModelLoader.cpp | 62 +++++++++++++++++++++- src/Core/Resource/Factory/CModelLoader.h | 1 + src/Core/Resource/Model/SSurface.h | 2 + 4 files changed, 82 insertions(+), 3 deletions(-) diff --git a/src/Core/Resource/Factory/CAreaLoader.cpp b/src/Core/Resource/Factory/CAreaLoader.cpp index 65aa13a3..d91010da 100644 --- a/src/Core/Resource/Factory/CAreaLoader.cpp +++ b/src/Core/Resource/Factory/CAreaLoader.cpp @@ -74,17 +74,33 @@ void CAreaLoader::ReadGeometryPrime() mBlockMgr->ToNextBlock(); // Geometry + std::vector FileModels; + for (u32 m = 0; m < mNumMeshes; m++) { std::cout << "\rLoading mesh " << std::dec << m + 1 << "/" << mNumMeshes; - CModel *pTerrainModel = CModelLoader::LoadWorldModel(*mpMREA, *mBlockMgr, *mpArea->mMaterialSet, mVersion); - mpArea->AddWorldModel(pTerrainModel); + CModel *pModel = CModelLoader::LoadWorldModel(*mpMREA, *mBlockMgr, *mpArea->mMaterialSet, mVersion); + FileModels.push_back(pModel); + + if (mVersion <= ePrime) + mpArea->AddWorldModel(pModel); if (mVersion >= eEchoes) { mBlockMgr->ToNextBlock(); mBlockMgr->ToNextBlock(); } } + + // Split meshes + if (mVersion >= eEchoesDemo) + { + std::vector SplitModels; + CModelLoader::BuildWorldMeshes(FileModels, SplitModels, true); + + for (u32 iMdl = 0; iMdl < SplitModels.size(); iMdl++) + mpArea->AddWorldModel(SplitModels[iMdl]); + } + mpArea->MergeTerrain(); std::cout << "\n"; } diff --git a/src/Core/Resource/Factory/CModelLoader.cpp b/src/Core/Resource/Factory/CModelLoader.cpp index 47131771..9f4969e0 100644 --- a/src/Core/Resource/Factory/CModelLoader.cpp +++ b/src/Core/Resource/Factory/CModelLoader.cpp @@ -1,6 +1,7 @@ #include "CModelLoader.h" #include "CMaterialLoader.h" #include "Core/Log.h" +#include CModelLoader::CModelLoader() { @@ -236,7 +237,15 @@ void CModelLoader::LoadSurfaceHeaderPrime(IInputStream& Model, SSurface *pSurf) Model.Seek(0xC, SEEK_CUR); u32 ExtraSize = Model.ReadLong(); pSurf->ReflectionDirection = CVector3f(Model); - if (mVersion >= eEchoesDemo) Model.Seek(0x4, SEEK_CUR); // Extra values in Echoes. Not sure what they are. + + if (mVersion >= eEchoesDemo) + { + Model.Seek(0x2, SEEK_CUR); // Skipping unknown value + pSurf->MeshID = Model.ReadShort(); + } + else + pSurf->MeshID = -1; + bool HasAABox = (ExtraSize >= 0x18); // MREAs have a set of bounding box coordinates here. // If this surface has a bounding box, we can just read it here. Otherwise we'll fill it in manually. @@ -555,6 +564,57 @@ CModel* CModelLoader::LoadCorruptionWorldModel(IInputStream &MREA, CBlockMgrIn & return pModel; } +void CModelLoader::BuildWorldMeshes(const std::vector& rkIn, std::vector& rOut, bool DeleteInputModels) +{ + // This function takes the gigantic models with all surfaces combined from MP2/3/DKCR and splits the surfaces to reform the original uncombined meshes. + std::map OutputMap; + + for (u32 iMdl = 0; iMdl < rkIn.size(); iMdl++) + { + CModel *pModel = rkIn[iMdl]; + pModel->mHasOwnSurfaces = false; + pModel->mHasOwnMaterials = false; + + for (u32 iSurf = 0; iSurf < pModel->mSurfaces.size(); iSurf++) + { + SSurface *pSurf = pModel->mSurfaces[iSurf]; + u32 ID = (u32) pSurf->MeshID; + auto Iter = OutputMap.find(ID); + + // No model for this ID; create one! + if (Iter == OutputMap.end()) + { + CModel *pOutMdl = new CModel(); + pOutMdl->mMaterialSets.resize(1); + pOutMdl->mMaterialSets[0] = pModel->mMaterialSets[0]; + pOutMdl->mHasOwnMaterials = false; + pOutMdl->mSurfaces.push_back(pSurf); + pOutMdl->mHasOwnSurfaces = true; + pOutMdl->mVertexCount = pSurf->VertexCount; + pOutMdl->mTriangleCount = pSurf->TriangleCount; + pOutMdl->mAABox.ExpandBounds(pSurf->AABox); + + OutputMap[ID] = pOutMdl; + rOut.push_back(pOutMdl); + } + + // Existing model; add this surface to it + else + { + CModel *pOutMdl = Iter->second; + pOutMdl->mSurfaces.push_back(pSurf); + pOutMdl->mVertexCount += pSurf->VertexCount; + pOutMdl->mTriangleCount += pSurf->TriangleCount; + pOutMdl->mAABox.ExpandBounds(pSurf->AABox); + } + } + + // Done with this model, should we delete it? + if (DeleteInputModels) + delete pModel; + } +} + CModel* CModelLoader::ImportAssimpNode(const aiNode *pNode, const aiScene *pScene, CMaterialSet& matSet) { CModelLoader loader; diff --git a/src/Core/Resource/Factory/CModelLoader.h b/src/Core/Resource/Factory/CModelLoader.h index 0810fcf8..f5ee132a 100644 --- a/src/Core/Resource/Factory/CModelLoader.h +++ b/src/Core/Resource/Factory/CModelLoader.h @@ -59,6 +59,7 @@ public: static CModel* LoadCMDL(IInputStream& CMDL); static CModel* LoadWorldModel(IInputStream& MREA, CBlockMgrIn& BlockMgr, CMaterialSet& MatSet, EGame Version); static CModel* LoadCorruptionWorldModel(IInputStream& MREA, CBlockMgrIn& BlockMgr, CMaterialSet& MatSet, u32 HeaderSecNum, u32 GPUSecNum, EGame Version); + static void BuildWorldMeshes(const std::vector& rkIn, std::vector& rOut, bool DeleteInputModels); static CModel* ImportAssimpNode(const aiNode *pNode, const aiScene *pScene, CMaterialSet& matSet); static EGame GetFormatVersion(u32 Version); }; diff --git a/src/Core/Resource/Model/SSurface.h b/src/Core/Resource/Model/SSurface.h index d3770a8f..232027ba 100644 --- a/src/Core/Resource/Model/SSurface.h +++ b/src/Core/Resource/Model/SSurface.h @@ -12,6 +12,7 @@ #include #include +// Should prolly be a class struct SSurface { u32 VertexCount; @@ -20,6 +21,7 @@ struct SSurface CVector3f CenterPoint; u32 MaterialID; CVector3f ReflectionDirection; + u16 MeshID; struct SPrimitive {