Added support for editing and resaving EGMC files + improved its preview rendering

This commit is contained in:
parax0
2016-01-16 01:13:27 -07:00
parent c0b74c9883
commit 5c3a37ca4a
20 changed files with 605 additions and 134 deletions

View File

@@ -184,7 +184,8 @@ HEADERS += \
Scene/CSceneIterator.h \
Resource/CResourceInfo.h \
Resource/CPoiToWorld.h \
Resource/Factory/CPoiToWorldLoader.h
Resource/Factory/CPoiToWorldLoader.h \
Resource/Cooker/CPoiToWorldCooker.h
# Source Files
SOURCES += \
@@ -272,4 +273,5 @@ SOURCES += \
Scene/CScene.cpp \
Scene/CSceneIterator.cpp \
Resource/CPoiToWorld.cpp \
Resource/Factory/CPoiToWorldLoader.cpp
Resource/Factory/CPoiToWorldLoader.cpp \
Resource/Cooker/CPoiToWorldCooker.cpp

View File

@@ -6,22 +6,74 @@ CPoiToWorld::CPoiToWorld()
CPoiToWorld::~CPoiToWorld()
{
for (auto it = mMaps.begin(); it != mMaps.end(); it++)
delete *it;
}
void CPoiToWorld::LinksForMeshID(std::list<u32>& rOutInstanceIDs, u32 MeshID)
void CPoiToWorld::AddPoi(u32 PoiID)
{
for (u32 iLink = 0; iLink < mMeshLinks.size(); iLink++)
// Check if this POI already exists
auto it = mPoiLookupMap.find(PoiID);
if (it == mPoiLookupMap.end())
{
if (mMeshLinks[iLink].MeshID == MeshID)
rOutInstanceIDs.push_back(mMeshLinks[iLink].PoiInstanceID);
SPoiMap *pMap = new SPoiMap();
pMap->PoiID = PoiID;
mMaps.push_back(pMap);
mPoiLookupMap[PoiID] = pMap;
}
}
void CPoiToWorld::LinksForInstanceID(std::list<u32>& rOutMeshIDs, u32 InstanceID)
void CPoiToWorld::AddPoiMeshMap(u32 PoiID, u32 ModelID)
{
for (u32 iLink = 0; iLink < mMeshLinks.size(); iLink++)
// Make sure the POI exists; the add function won't do anything if it does
AddPoi(PoiID);
SPoiMap *pMap = mPoiLookupMap[PoiID];
// Check whether this model ID is already mapped to this POI
for (auto it = pMap->ModelIDs.begin(); it != pMap->ModelIDs.end(); it++)
{
if (mMeshLinks[iLink].PoiInstanceID == InstanceID)
rOutMeshIDs.push_back(mMeshLinks[iLink].MeshID);
if (*it == ModelID)
return;
}
// We didn't return, so this is a new mapping
pMap->ModelIDs.push_back(ModelID);
}
void CPoiToWorld::RemovePoi(u32 PoiID)
{
for (auto it = mMaps.begin(); it != mMaps.end(); it++)
{
if ((*it)->PoiID == PoiID)
{
mMaps.erase(it);
mPoiLookupMap.erase(PoiID);
return;
}
}
}
void CPoiToWorld::RemovePoiMeshMap(u32 PoiID, u32 ModelID)
{
auto MapIt = mPoiLookupMap.find(PoiID);
if (MapIt != mPoiLookupMap.end())
{
SPoiMap *pMap = MapIt->second;
for (auto ListIt = pMap->ModelIDs.begin(); ListIt != pMap->ModelIDs.end(); ListIt++)
{
if (*ListIt == ModelID)
{
pMap->ModelIDs.erase(ListIt);
if (pMap->ModelIDs.empty())
RemovePoi(PoiID);
break;
}
}
}
}

View File

@@ -3,37 +3,41 @@
#include "CResource.h"
#include <list>
#include <map>
#include <vector>
class CPoiToWorld : public CResource
{
DECLARE_RESOURCE_TYPE(ePoiToWorld)
friend class CPoiToWorldLoader;
public:
struct SPoiMeshLink
struct SPoiMap
{
u32 MeshID;
u32 PoiInstanceID;
u32 PoiID;
std::list<u32> ModelIDs;
};
private:
std::vector<SPoiMeshLink> mMeshLinks;
std::vector<SPoiMap*> mMaps;
std::map<u32,SPoiMap*> mPoiLookupMap;
public:
CPoiToWorld();
~CPoiToWorld();
void LinksForMeshID(std::list<u32>& rOutInstanceIDs, u32 MeshID);
void LinksForInstanceID(std::list<u32>& rOutMeshIDs, u32 InstanceID);
void AddPoi(u32 PoiID);
void AddPoiMeshMap(u32 PoiID, u32 ModelID);
void RemovePoi(u32 PoiID);
void RemovePoiMeshMap(u32 PoiID, u32 ModelID);
inline u32 NumMeshLinks()
inline u32 NumMappedPOIs() const
{
return mMeshLinks.size();
return mMaps.size();
}
inline const SPoiMeshLink& MeshLinkByIndex(u32 Index)
inline const SPoiMap* MapByIndex(u32 Index) const
{
return mMeshLinks[Index];
return mMaps[Index];
}
};

View File

@@ -0,0 +1,36 @@
#include "CPoiToWorldCooker.h"
void CPoiToWorldCooker::WriteEGMC(CPoiToWorld *pPoiToWorld, IOutputStream& rOut)
{
// Create mappings list
struct SPoiMapping
{
u32 MeshID;
u32 PoiID;
};
std::vector<SPoiMapping> Mappings;
for (u32 iPoi = 0; iPoi < pPoiToWorld->NumMappedPOIs(); iPoi++)
{
const CPoiToWorld::SPoiMap *kpMap = pPoiToWorld->MapByIndex(iPoi);
for (auto it = kpMap->ModelIDs.begin(); it != kpMap->ModelIDs.end(); it++)
{
SPoiMapping Mapping;
Mapping.MeshID = *it;
Mapping.PoiID = kpMap->PoiID;
Mappings.push_back(Mapping);
}
}
// Write EGMC
rOut.WriteLong(Mappings.size());
for (u32 iMap = 0; iMap < Mappings.size(); iMap++)
{
rOut.WriteLong(Mappings[iMap].MeshID);
rOut.WriteLong(Mappings[iMap].PoiID);
}
rOut.WriteToBoundary(32, -1);
}

View File

@@ -0,0 +1,14 @@
#ifndef CPOITOWORLDCOOKER_H
#define CPOITOWORLDCOOKER_H
#include "Core/Resource/CPoiToWorld.h"
#include <FileIO/FileIO.h>
class CPoiToWorldCooker
{
CPoiToWorldCooker() {}
public:
static void WriteEGMC(CPoiToWorld *pPoiToWorld, IOutputStream& rOut);
};
#endif // CPOITOWORLDCOOKER_H

View File

@@ -239,12 +239,7 @@ void CModelLoader::LoadSurfaceHeaderPrime(IInputStream& Model, SSurface *pSurf)
pSurf->ReflectionDirection = CVector3f(Model);
if (mVersion >= eEchoesDemo)
{
Model.Seek(0x2, SEEK_CUR); // Skipping unknown value
pSurf->MeshID = Model.ReadShort();
}
else
pSurf->MeshID = -1;
Model.Seek(0x4, SEEK_CUR); // Skipping unknown values
bool HasAABox = (ExtraSize >= 0x18); // MREAs have a set of bounding box coordinates here.

View File

@@ -3,14 +3,13 @@
CPoiToWorld* CPoiToWorldLoader::LoadEGMC(IInputStream& rEGMC)
{
CPoiToWorld *pOut = new CPoiToWorld();
u32 NumLinks = rEGMC.ReadLong();
u32 NumMappings = rEGMC.ReadLong();
for (u32 iLink = 0; iLink < NumLinks; iLink++)
for (u32 iMap = 0; iMap < NumMappings; iMap++)
{
CPoiToWorld::SPoiMeshLink Link;
Link.MeshID = rEGMC.ReadLong();
Link.PoiInstanceID = rEGMC.ReadLong();
pOut->mMeshLinks.push_back(Link);
u32 MeshID = rEGMC.ReadLong();
u32 InstanceID = rEGMC.ReadLong();
pOut->AddPoiMeshMap(InstanceID, MeshID);
}
return pOut;

View File

@@ -10,6 +10,7 @@ CModelNode::CModelNode(CScene *pScene, CSceneNode *pParent, CModel *pModel) : CS
mScale = CVector3f(1.f);
mLightingEnabled = true;
mForceAlphaOn = false;
mEnableScanOverlay = false;
mTintColor = CColor::skWhite;
}
@@ -59,6 +60,18 @@ void CModelNode::Draw(FRenderOptions Options, int ComponentIndex, const SViewInf
mpModel->Draw(Options, mActiveMatSet);
else
mpModel->DrawSurface(Options, ComponentIndex, mActiveMatSet);
if (mEnableScanOverlay)
{
CDrawUtil::UseColorShader(mScanOverlayColor);
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_ZERO, GL_ZERO);
Options |= eNoMaterialSetup;
if (ComponentIndex < 0)
mpModel->Draw(Options, 0);
else
mpModel->DrawSurface(Options, ComponentIndex, mActiveMatSet);
}
}
void CModelNode::DrawSelection()

View File

@@ -11,6 +11,8 @@ class CModelNode : public CSceneNode
bool mLightingEnabled;
bool mForceAlphaOn;
CColor mTintColor;
bool mEnableScanOverlay;
CColor mScanOverlayColor;
public:
explicit CModelNode(CScene *pScene, CSceneNode *pParent = 0, CModel *pModel = 0);
@@ -26,15 +28,17 @@ public:
// Setters
void SetModel(CModel *pModel);
inline void SetMatSet(u32 MatSet) { mActiveMatSet = MatSet; }
inline void SetDynamicLighting(bool Enable) { mLightingEnabled = Enable; }
inline void ForceAlphaEnabled(bool Enable) { mForceAlphaOn = Enable; }
inline void SetTintColor(const CColor& rkTintColor) { mTintColor = rkTintColor; }
inline void ClearTintColor() { mTintColor = CColor::skWhite; }
inline CModel* Model() const { return mpModel; }
inline u32 MatSet() const { return mActiveMatSet; }
inline bool IsDynamicLightingEnabled() const { return mLightingEnabled; }
inline u32 FindMeshID() const { return mpModel->GetSurface(0)->MeshID; }
inline void SetMatSet(u32 MatSet) { mActiveMatSet = MatSet; }
inline void SetDynamicLighting(bool Enable) { mLightingEnabled = Enable; }
inline void ForceAlphaEnabled(bool Enable) { mForceAlphaOn = Enable; }
inline void SetTintColor(const CColor& rkTintColor) { mTintColor = rkTintColor; }
inline void ClearTintColor() { mTintColor = CColor::skWhite; }
inline void SetScanOverlayEnabled(bool Enable) { mEnableScanOverlay = Enable; }
inline void SetScanOverlayColor(const CColor& rkColor) { mScanOverlayColor = rkColor; }
inline CModel* Model() const { return mpModel; }
inline u32 MatSet() const { return mActiveMatSet; }
inline bool IsDynamicLightingEnabled() const { return mLightingEnabled; }
inline u32 FindMeshID() const { return mpModel->GetSurface(0)->MeshID; }
};
#endif // CMODELNODE_H