Added support for EGMC and a basic EGMC visualizer dialog

This commit is contained in:
parax0 2016-01-15 16:36:58 -07:00
parent b71e1268fa
commit c0b74c9883
35 changed files with 763 additions and 101 deletions

View File

@ -182,7 +182,9 @@ HEADERS += \
Scene/FShowFlags.h \
Scene/CScene.h \
Scene/CSceneIterator.h \
Resource/CResourceInfo.h
Resource/CResourceInfo.h \
Resource/CPoiToWorld.h \
Resource/Factory/CPoiToWorldLoader.h
# Source Files
SOURCES += \
@ -268,4 +270,6 @@ SOURCES += \
Resource/Script/IProperty.cpp \
Scene/FShowFlags.cpp \
Scene/CScene.cpp \
Scene/CSceneIterator.cpp
Scene/CSceneIterator.cpp \
Resource/CPoiToWorld.cpp \
Resource/Factory/CPoiToWorldLoader.cpp

View File

@ -179,6 +179,11 @@ CLight* CGameArea::GetLight(u32 layer, u32 light)
return mLightLayers[layer][light];
}
CPoiToWorld* CGameArea::GetPoiToWorldMap()
{
return mpPoiToWorldMap;
}
CAABox CGameArea::AABox()
{
return mAABox;

View File

@ -5,6 +5,7 @@
#include "CCollisionMeshGroup.h"
#include "CLight.h"
#include "CMaterialSet.h"
#include "CPoiToWorld.h"
#include "Core/Resource/Model/CModel.h"
#include "Core/Resource/Model/CStaticModel.h"
#include <Common/types.h>
@ -40,6 +41,8 @@ class CGameArea : public CResource
CCollisionMeshGroup *mCollision;
// Lights
std::vector<std::vector<CLight*>> mLightLayers;
// Object to Static Geometry Map
TResPtr<CPoiToWorld> mpPoiToWorldMap;
public:
CGameArea();
@ -65,6 +68,7 @@ public:
u32 GetLightLayerCount();
u32 GetLightCount(u32 layer);
CLight* GetLight(u32 layer, u32 light);
CPoiToWorld* GetPoiToWorldMap();
CAABox AABox();
};

View File

@ -0,0 +1,27 @@
#include "CPoiToWorld.h"
CPoiToWorld::CPoiToWorld()
{
}
CPoiToWorld::~CPoiToWorld()
{
}
void CPoiToWorld::LinksForMeshID(std::list<u32>& rOutInstanceIDs, u32 MeshID)
{
for (u32 iLink = 0; iLink < mMeshLinks.size(); iLink++)
{
if (mMeshLinks[iLink].MeshID == MeshID)
rOutInstanceIDs.push_back(mMeshLinks[iLink].PoiInstanceID);
}
}
void CPoiToWorld::LinksForInstanceID(std::list<u32>& rOutMeshIDs, u32 InstanceID)
{
for (u32 iLink = 0; iLink < mMeshLinks.size(); iLink++)
{
if (mMeshLinks[iLink].PoiInstanceID == InstanceID)
rOutMeshIDs.push_back(mMeshLinks[iLink].MeshID);
}
}

View File

@ -0,0 +1,40 @@
#ifndef CPOITOWORLD_H
#define CPOITOWORLD_H
#include "CResource.h"
#include <list>
class CPoiToWorld : public CResource
{
DECLARE_RESOURCE_TYPE(ePoiToWorld)
friend class CPoiToWorldLoader;
public:
struct SPoiMeshLink
{
u32 MeshID;
u32 PoiInstanceID;
};
private:
std::vector<SPoiMeshLink> mMeshLinks;
public:
CPoiToWorld();
~CPoiToWorld();
void LinksForMeshID(std::list<u32>& rOutInstanceIDs, u32 MeshID);
void LinksForInstanceID(std::list<u32>& rOutMeshIDs, u32 InstanceID);
inline u32 NumMeshLinks()
{
return mMeshLinks.size();
}
inline const SPoiMeshLink& MeshLinkByIndex(u32 Index)
{
return mMeshLinks[Index];
}
};
#endif // CPOITOWORLD_H

View File

@ -4,6 +4,7 @@
#include "Core/Resource/Factory/CCollisionLoader.h"
#include "Core/Resource/Factory/CFontLoader.h"
#include "Core/Resource/Factory/CModelLoader.h"
#include "Core/Resource/Factory/CPoiToWorldLoader.h"
#include "Core/Resource/Factory/CScanLoader.h"
#include "Core/Resource/Factory/CStringLoader.h"
#include "Core/Resource/Factory/CTextureDecoder.h"
@ -145,6 +146,7 @@ CResource* CResCache::GetResource(CUniqueID ResID, CFourCC type)
else if (type == "FONT") Res = CFontLoader::LoadFONT(mem);
else if (type == "SCAN") Res = CScanLoader::LoadSCAN(mem);
else if (type == "DCLN") Res = CCollisionLoader::LoadDCLN(mem);
else if (type == "EGMC") Res = CPoiToWorldLoader::LoadEGMC(mem);
else SupportedFormat = false;
// Log errors
@ -197,6 +199,7 @@ CResource* CResCache::GetResource(const TString& ResPath)
else if (type == "FONT") Res = CFontLoader::LoadFONT(file);
else if (type == "SCAN") Res = CScanLoader::LoadSCAN(file);
else if (type == "DCLN") Res = CCollisionLoader::LoadDCLN(file);
else if (type == "EGMC") Res = CPoiToWorldLoader::LoadEGMC(file);
else SupportedFormat = false;
if (!Res) Res = new CResource(); // Default for unsupported formats

View File

@ -33,18 +33,19 @@ enum EResType
eParticle = 27,
eParticleElectric = 28,
eParticleSwoosh = 29,
eProjectile = 30,
eResource = 31,
eSaveWorld = 32,
eScan = 33,
eSkeleton = 34,
eSkin = 35,
eStateMachine = 36,
eStringTable = 37,
eTexture = 38,
eTweak = 39,
eVideo = 40,
eWorld = 41
ePoiToWorld = 30,
eProjectile = 31,
eResource = 32,
eSaveWorld = 33,
eScan = 34,
eSkeleton = 35,
eSkin = 36,
eStateMachine = 37,
eStringTable = 38,
eTexture = 39,
eTweak = 40,
eVideo = 41,
eWorld = 42
};
#endif // ERESTYPE

View File

@ -76,16 +76,25 @@ void CAreaLoader::ReadGeometryPrime()
// Geometry
std::vector<CModel*> FileModels;
for (u32 m = 0; m < mNumMeshes; m++) {
std::cout << "\rLoading mesh " << std::dec << m + 1 << "/" << mNumMeshes;
for (u32 iMesh = 0; iMesh < mNumMeshes; iMesh++)
{
CModel *pModel = CModelLoader::LoadWorldModel(*mpMREA, *mBlockMgr, *mpArea->mMaterialSet, mVersion);
FileModels.push_back(pModel);
if (mVersion <= ePrime)
mpArea->AddWorldModel(pModel);
if (mVersion >= eEchoes) {
// For Echoes+, load surface mesh IDs, then skip to the start of the next mesh
else
{
u16 NumSurfaces = mpMREA->ReadShort();
for (u32 iSurf = 0; iSurf < NumSurfaces; iSurf++)
{
mpMREA->Seek(0x2, SEEK_CUR);
pModel->GetSurface(iSurf)->MeshID = mpMREA->ReadShort();
}
mBlockMgr->ToNextBlock();
mBlockMgr->ToNextBlock();
}
@ -102,7 +111,6 @@ void CAreaLoader::ReadGeometryPrime()
}
mpArea->MergeTerrain();
std::cout << "\n";
}
void CAreaLoader::ReadSCLYPrime()
@ -341,22 +349,36 @@ void CAreaLoader::ReadGeometryCorruption()
mBlockMgr->ToNextBlock();
// Geometry
std::vector<CModel*> FileModels;
u32 CurWOBJSection = 1;
u32 CurGPUSection = mGPUBlockNum;
for (u32 iMesh = 0; iMesh < mNumMeshes; iMesh++)
{
std::cout << "\rLoading mesh " << std::dec << iMesh + 1 << "/" << mNumMeshes;
CModel *pWorldModel = CModelLoader::LoadCorruptionWorldModel(*mpMREA, *mBlockMgr, *mpArea->mMaterialSet, CurWOBJSection, CurGPUSection, mVersion);
mpArea->AddWorldModel(pWorldModel);
FileModels.push_back(pWorldModel);
CurWOBJSection += 4;
CurGPUSection = mBlockMgr->CurrentBlock();
// Load surface mesh IDs
mBlockMgr->ToBlock(CurWOBJSection - 2);
u16 NumSurfaces = mpMREA->ReadShort();
for (u32 iSurf = 0; iSurf < NumSurfaces; iSurf++)
{
mpMREA->Seek(0x2, SEEK_CUR);
pWorldModel->GetSurface(iSurf)->MeshID = mpMREA->ReadShort();
}
}
std::vector<CModel*> SplitModels;
CModelLoader::BuildWorldMeshes(FileModels, SplitModels, true);
for (u32 iMdl = 0; iMdl < SplitModels.size(); iMdl++)
mpArea->AddWorldModel(SplitModels[iMdl]);
mpArea->MergeTerrain();
std::cout << "\n";
}
void CAreaLoader::ReadLightsCorruption()
@ -511,6 +533,14 @@ void CAreaLoader::ReadCollision()
mpArea->mCollision = CCollisionLoader::LoadAreaCollision(*mpMREA);
}
void CAreaLoader::ReadEGMC()
{
Log::FileWrite(mpMREA->GetSourceString(), "Reading EGMC");
mBlockMgr->ToBlock(mEGMCBlockNum);
CUniqueID EGMC(*mpMREA, (mVersion <= eEchoes ? e32Bit : e64Bit));
mpArea->mpPoiToWorldMap = gResCache.GetResource(EGMC, "EGMC");
}
void CAreaLoader::SetUpObjects()
{
// Iterate over all objects
@ -598,6 +628,7 @@ CGameArea* CAreaLoader::LoadMREA(IInputStream& MREA)
Loader.ReadSCLYPrime();
Loader.ReadCollision();
Loader.ReadLightsPrime();
Loader.ReadEGMC();
break;
case eEchoes:
Loader.ReadHeaderEchoes();
@ -605,6 +636,7 @@ CGameArea* CAreaLoader::LoadMREA(IInputStream& MREA)
Loader.ReadSCLYEchoes();
Loader.ReadCollision();
Loader.ReadLightsPrime();
Loader.ReadEGMC();
break;
case eCorruptionProto:
Loader.ReadHeaderCorruption();
@ -612,6 +644,7 @@ CGameArea* CAreaLoader::LoadMREA(IInputStream& MREA)
Loader.ReadSCLYEchoes();
Loader.ReadCollision();
Loader.ReadLightsCorruption();
Loader.ReadEGMC();
break;
case eCorruption:
case eReturns:
@ -619,7 +652,11 @@ CGameArea* CAreaLoader::LoadMREA(IInputStream& MREA)
Loader.ReadGeometryCorruption();
Loader.ReadSCLYEchoes();
Loader.ReadCollision();
if (Loader.mVersion == eCorruption) Loader.ReadLightsCorruption();
if (Loader.mVersion == eCorruption)
{
Loader.ReadLightsCorruption();
Loader.ReadEGMC();
}
break;
default:
Log::FileError(MREA.GetSourceString(), "Unsupported MREA version: " + TString::HexString(version));

View File

@ -75,6 +75,7 @@ class CAreaLoader
void ReadCompressedBlocks();
void Decompress();
void ReadCollision();
void ReadEGMC();
void SetUpObjects();
public:

View File

@ -0,0 +1,17 @@
#include "CPoiToWorldLoader.h"
CPoiToWorld* CPoiToWorldLoader::LoadEGMC(IInputStream& rEGMC)
{
CPoiToWorld *pOut = new CPoiToWorld();
u32 NumLinks = rEGMC.ReadLong();
for (u32 iLink = 0; iLink < NumLinks; iLink++)
{
CPoiToWorld::SPoiMeshLink Link;
Link.MeshID = rEGMC.ReadLong();
Link.PoiInstanceID = rEGMC.ReadLong();
pOut->mMeshLinks.push_back(Link);
}
return pOut;
}

View File

@ -0,0 +1,17 @@
#ifndef CPOITOWORLDLOADER_H
#define CPOITOWORLDLOADER_H
#include "Core/Resource/CPoiToWorld.h"
#include "Core/Resource/TResPtr.h"
class CPoiToWorldLoader
{
TResPtr<CPoiToWorld> mpPoiToWorld;
CPoiToWorldLoader() {}
public:
static CPoiToWorld* LoadEGMC(IInputStream& rEGMC);
};
#endif // CPOITOWORLDLOADER_H

View File

@ -10,6 +10,7 @@ CModelNode::CModelNode(CScene *pScene, CSceneNode *pParent, CModel *pModel) : CS
mScale = CVector3f(1.f);
mLightingEnabled = true;
mForceAlphaOn = false;
mTintColor = CColor::skWhite;
}
ENodeType CModelNode::NodeType()
@ -103,6 +104,11 @@ SRayIntersection CModelNode::RayNodeIntersectTest(const CRay &Ray, u32 AssetID,
return out;
}
CColor CModelNode::TintColor(const SViewInfo& /*rkViewInfo*/) const
{
return mTintColor;
}
void CModelNode::SetModel(CModel *pModel)
{
mpModel = pModel;
@ -116,8 +122,3 @@ void CModelNode::SetModel(CModel *pModel)
MarkTransformChanged();
}
void CModelNode::ForceAlphaEnabled(bool Enable)
{
mForceAlphaOn = Enable;
}

View File

@ -10,6 +10,7 @@ class CModelNode : public CSceneNode
u32 mActiveMatSet;
bool mLightingEnabled;
bool mForceAlphaOn;
CColor mTintColor;
public:
explicit CModelNode(CScene *pScene, CSceneNode *pParent = 0, CModel *pModel = 0);
@ -20,41 +21,20 @@ public:
virtual void DrawSelection();
virtual void RayAABoxIntersectTest(CRayCollisionTester& Tester, const SViewInfo& ViewInfo);
virtual SRayIntersection RayNodeIntersectTest(const CRay &Ray, u32 AssetID, const SViewInfo& ViewInfo);
virtual CColor TintColor(const SViewInfo& rkViewInfo) const;
// Setters
void SetModel(CModel *pModel);
void SetMatSet(u32 MatSet);
void SetDynamicLighting(bool Enable);
void ForceAlphaEnabled(bool Enable);
CModel* Model();
u32 MatSet();
bool IsDynamicLightingEnabled();
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 FUNCTIONS ************
inline void CModelNode::SetMatSet(u32 MatSet)
{
mActiveMatSet = MatSet;
}
inline void CModelNode::SetDynamicLighting(bool Enable)
{
mLightingEnabled = Enable;
}
inline CModel* CModelNode::Model()
{
return mpModel;
}
inline u32 CModelNode::MatSet()
{
return mActiveMatSet;
}
inline bool CModelNode::IsDynamicLightingEnabled()
{
return mLightingEnabled;
}
#endif // CMODELNODE_H

View File

@ -1,6 +1,7 @@
#include "CScene.h"
#include "Core/Render/CGraphics.h"
#include "Core/Resource/CResCache.h"
#include "Core/Resource/CPoiToWorld.h"
#include "Core/Resource/Script/CScriptLayer.h"
#include "Core/CRayCollisionTester.h"
@ -88,24 +89,25 @@ void CScene::SetActiveArea(CGameArea *pArea)
mpArea = pArea;
mpAreaRootNode = new CRootNode(this, mpSceneRootNode);
if (mSplitTerrain)
{
// Create static nodes
u32 Count = mpArea->GetStaticModelCount();
for (u32 iMdl = 0; iMdl < Count; iMdl++)
CreateStaticNode(mpArea->GetStaticModel(iMdl));
}
else
{
u32 Count = mpArea->GetTerrainModelCount();
CStaticNode *pNode = CreateStaticNode(mpArea->GetStaticModel(iMdl));
pNode->SetName("Static World Model " + TString::FromInt32(iMdl, 0, 10));
}
// Create model nodes
Count = mpArea->GetTerrainModelCount();
for (u32 iMdl = 0; iMdl < Count; iMdl++)
{
CModel *pModel = mpArea->GetTerrainModel(iMdl);
CModelNode *pNode = CreateModelNode(pModel);
pNode->SetName("World Model " + TString::FromInt32(iMdl, 0, 10));
pNode->SetDynamicLighting(false);
}
}
CreateCollisionNode(mpArea->GetCollision());
@ -298,7 +300,8 @@ CGameArea* CScene::GetActiveArea()
FShowFlags CScene::ShowFlagsForNodeFlags(FNodeFlags NodeFlags)
{
FShowFlags Out;
if (NodeFlags & eStaticNode) Out |= eShowWorld;
if (NodeFlags & eModelNode) Out |= eShowSplitWorld;
if (NodeFlags & eStaticNode) Out |= eShowMergedWorld;
if (NodeFlags & eScriptNode) Out |= eShowObjects;
if (NodeFlags & eCollisionNode) Out |= eShowWorldCollision;
if (NodeFlags & eLightNode) Out |= eShowLights;
@ -307,8 +310,9 @@ FShowFlags CScene::ShowFlagsForNodeFlags(FNodeFlags NodeFlags)
FNodeFlags CScene::NodeFlagsForShowFlags(FShowFlags ShowFlags)
{
FNodeFlags Out = eRootNode | eModelNode;
if (ShowFlags & eShowWorld) Out |= eStaticNode;
FNodeFlags Out = eRootNode;
if (ShowFlags & eShowSplitWorld) Out |= eModelNode;
if (ShowFlags & eShowMergedWorld) Out |= eStaticNode;
if (ShowFlags & eShowWorldCollision) Out |= eCollisionNode;
if (ShowFlags & eShowObjects) Out |= eScriptNode | eScriptExtraNode;
if (ShowFlags & eShowLights) Out |= eLightNode;

View File

@ -458,6 +458,11 @@ CScriptTemplate* CScriptNode::Template() const
return mpInstance->Template();
}
CScriptExtra* CScriptNode::Extra() const
{
return mpExtra;
}
CModel* CScriptNode::ActiveModel() const
{
return mpActiveModel;

View File

@ -7,10 +7,12 @@
#include "Core/Resource/Script/CScriptObject.h"
#include "Core/CLightParameters.h"
class CScriptExtra;
class CScriptNode : public CSceneNode
{
CScriptObject *mpInstance;
class CScriptExtra *mpExtra;
CScriptExtra *mpExtra;
TResPtr<CModel> mpActiveModel;
TResPtr<CTexture> mpBillboard;
@ -39,6 +41,7 @@ public:
void GeneratePosition();
CScriptObject* Object() const;
CScriptTemplate* Template() const;
CScriptExtra* Extra() const;
CModel* ActiveModel() const;
bool UsesModel() const;
bool HasPreviewVolume() const;

View File

@ -1,3 +1,3 @@
#include "FShowFlags.h"
const FShowFlags gkGameModeShowFlags = eShowWorld | eShowObjectGeometry | eShowSky;
const FShowFlags gkGameModeShowFlags = eShowMergedWorld | eShowObjectGeometry | eShowSky;

View File

@ -6,14 +6,15 @@
enum EShowFlag
{
eShowNone = 0x00,
eShowWorld = 0x01,
eShowWorldCollision = 0x02,
eShowObjectGeometry = 0x04,
eShowObjectCollision = 0x08,
eShowObjects = 0x0C,
eShowLights = 0x10,
eShowSky = 0x20,
eShowAll = 0x3F
eShowSplitWorld = 0x01,
eShowMergedWorld = 0x02,
eShowWorldCollision = 0x04,
eShowObjectGeometry = 0x08,
eShowObjectCollision = 0x10,
eShowObjects = 0x18,
eShowLights = 0x20,
eShowSky = 0x40,
eShowAll = 0x7F
};
DECLARE_FLAGS(EShowFlag, FShowFlags)

View File

@ -15,6 +15,7 @@ public:
explicit CPointOfInterestExtra(CScriptObject *pInstance, CScene *pScene, CSceneNode *pParent = 0);
void PropertyModified(IProperty* pProperty);
void ModifyTintColor(CColor& Color);
CScan* GetScan() const { return mpScanData; }
static const CColor skRegularColor;
static const CColor skImportantColor;

View File

@ -10,6 +10,7 @@ CSceneViewport::CSceneViewport(QWidget *pParent)
: CBasicViewport(pParent),
mpEditor(nullptr),
mpScene(nullptr),
mRenderingMergedWorld(true),
mGizmoTransforming(false),
mpHoverNode(nullptr),
mHoverPoint(CVector3f::skZero),
@ -22,7 +23,7 @@ CSceneViewport::CSceneViewport(QWidget *pParent)
mViewInfo.pScene = mpScene;
mViewInfo.pRenderer = mpRenderer;
mViewInfo.ShowFlags = eShowWorld | eShowObjectGeometry | eShowLights | eShowSky;
mViewInfo.ShowFlags = eShowMergedWorld | eShowObjectGeometry | eShowLights | eShowSky;
CreateContextMenu();
}
@ -46,6 +47,25 @@ void CSceneViewport::SetShowFlag(EShowFlag Flag, bool Visible)
mViewInfo.ShowFlags &= ~Flag;
}
void CSceneViewport::SetShowWorld(bool Visible)
{
if (mRenderingMergedWorld)
SetShowFlag(eShowMergedWorld, Visible);
else
SetShowFlag(eShowSplitWorld, Visible);
}
void CSceneViewport::SetRenderMergedWorld(bool b)
{
mRenderingMergedWorld = b;
if (mViewInfo.ShowFlags & (eShowSplitWorld | eShowMergedWorld))
{
SetShowFlag(eShowSplitWorld, !b);
SetShowFlag(eShowMergedWorld, b);
}
}
FShowFlags CSceneViewport::ShowFlags() const
{
return mViewInfo.ShowFlags;
@ -251,7 +271,7 @@ void CSceneViewport::ContextMenu(QContextMenuEvent* pEvent)
// Set up actions
TString NodeName;
bool HasHoverNode = (mpHoverNode && mpHoverNode->NodeType() != eStaticNode);
bool HasHoverNode = (mpHoverNode && (mpHoverNode->NodeType() != eStaticNode) && (mpHoverNode->NodeType() != eModelNode));
bool HasSelection = mpEditor->HasSelection();
bool IsScriptNode = (mpHoverNode && mpHoverNode->NodeType() == eScriptNode);
@ -327,7 +347,7 @@ void CSceneViewport::OnMouseRelease(QMouseEvent *pEvent)
// Object selection/deselection
else
{
bool validNode = (mpHoverNode && (mpHoverNode->NodeType() != eStaticNode));
bool validNode = (mpHoverNode && (mpHoverNode->NodeType() != eStaticNode) && (mpHoverNode->NodeType() != eModelNode));
bool altPressed = ((pEvent->modifiers() & Qt::AltModifier) != 0);
bool ctrlPressed = ((pEvent->modifiers() & Qt::ControlModifier) != 0);

View File

@ -11,6 +11,7 @@ class CSceneViewport : public CBasicViewport
INodeEditor *mpEditor;
CScene *mpScene;
CRenderer *mpRenderer;
bool mRenderingMergedWorld;
// Scene interaction
bool mGizmoHovering;
@ -37,6 +38,8 @@ public:
~CSceneViewport();
void SetScene(INodeEditor *pEditor, CScene *pScene);
void SetShowFlag(EShowFlag Flag, bool Visible);
void SetShowWorld(bool Visible);
void SetRenderMergedWorld(bool b);
FShowFlags ShowFlags() const;
CRenderer* Renderer();
CSceneNode* HoverNode();

View File

@ -127,7 +127,9 @@ HEADERS += \
UICommon.h \
CErrorLogDialog.h \
Undo/CSelectAllCommand.h \
Undo/CInvertSelectionCommand.h
Undo/CInvertSelectionCommand.h \
WorldEditor/CPoiMapEditDialog.h \
WorldEditor/CPoiMapModel.h
# Source Files
SOURCES += \
@ -175,7 +177,9 @@ SOURCES += \
UICommon.cpp \
CErrorLogDialog.cpp \
Undo/CSelectAllCommand.cpp \
Undo/CInvertSelectionCommand.cpp
Undo/CInvertSelectionCommand.cpp \
WorldEditor/CPoiMapEditDialog.cpp \
WorldEditor/CPoiMapModel.cpp
# UI Files
FORMS += \
@ -190,4 +194,5 @@ FORMS += \
WorldEditor/WCreateTab.ui \
WorldEditor/WInstancesTab.ui \
WorldEditor/WModifyTab.ui \
CErrorLogDialog.ui
CErrorLogDialog.ui \
WorldEditor/CPoiMapEditDialog.ui

View File

@ -1,5 +1,5 @@
<RCC>
<qresource>
<qresource prefix="/">
<file>icons/Down.png</file>
<file>icons/Free Camera.png</file>
<file>icons/Material Highlight.png</file>
@ -28,5 +28,7 @@
<file>icons/Unlink.png</file>
<file>icons/World.png</file>
<file>icons/SelectMode.png</file>
<file>icons/POI Important.png</file>
<file>icons/POI Normal.png</file>
</qresource>
</RCC>

View File

@ -0,0 +1,129 @@
#include "CPoiMapEditDialog.h"
#include "ui_CPoiMapEditDialog.h"
#include "CWorldEditor.h"
#include <Core/Resource/CScan.h>
#include <Core/ScriptExtra/CPointOfInterestExtra.h>
CPoiMapEditDialog::CPoiMapEditDialog(CWorldEditor *pEditor, QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::CPoiMapEditDialog)
, mpEditor(pEditor)
, mSourceModel(pEditor, this)
, mHighlightMode(eHighlightSelected)
{
mModel.setSourceModel(&mSourceModel);
mModel.sort(0);
ui->setupUi(this);
ui->ListView->setModel(&mModel);
QActionGroup *pGroup = new QActionGroup(this);
pGroup->addAction(ui->ActionHighlightSelected);
pGroup->addAction(ui->ActionHighlightAll);
pGroup->addAction(ui->ActionHighlightNone);
SetHighlightSelected();
connect(ui->ActionHighlightSelected, SIGNAL(triggered()), this, SLOT(SetHighlightSelected()));
connect(ui->ActionHighlightAll, SIGNAL(triggered()), this, SLOT(SetHighlightAll()));
connect(ui->ActionHighlightNone, SIGNAL(triggered()), this, SLOT(SetHighlightNone()));
connect(ui->ListView->selectionModel(), SIGNAL(selectionChanged(QItemSelection,QItemSelection)),
this, SLOT(OnSelectionChanged(QItemSelection,QItemSelection)));
connect(ui->ListView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(OnItemDoubleClick(QModelIndex)));
connect(ui->ButtonBox, SIGNAL(accepted()), this, SLOT(close()));
connect(ui->ButtonBox, SIGNAL(rejected()), this, SLOT(close()));
}
CPoiMapEditDialog::~CPoiMapEditDialog()
{
delete ui;
// Clear model tints
if (mHighlightMode != eHighlightNone)
SetHighlightNone();
}
void CPoiMapEditDialog::HighlightPoiModels(const QModelIndex& rkIndex)
{
// Get POI and models
QModelIndex SourceIndex = mModel.mapToSource(rkIndex);
CScriptNode *pPOI = mSourceModel.PoiNodePointer(SourceIndex);
const QList<CModelNode*>& rkModels = mSourceModel.GetPoiMeshList(pPOI);
// Check whether this is an important scan
bool IsImportant = false;
TResPtr<CScan> pScan = static_cast<CPointOfInterestExtra*>(pPOI->Extra())->GetScan();
if (pScan)
IsImportant = pScan->IsImportant();
// Highlight the meshes
for (int iMdl = 0; iMdl < rkModels.size(); iMdl++)
rkModels[iMdl]->SetTintColor(IsImportant ? CColor::skRed : CColor::skBlue);
}
void CPoiMapEditDialog::UnhighlightPoiModels(const QModelIndex& rkIndex)
{
QModelIndex SourceIndex = mModel.mapToSource(rkIndex);
const QList<CModelNode*>& rkModels = mSourceModel.GetPoiMeshList(SourceIndex);
for (int iMdl = 0; iMdl < rkModels.size(); iMdl++)
rkModels[iMdl]->ClearTintColor();
}
void CPoiMapEditDialog::SetHighlightSelected()
{
const QItemSelection kSelection = ui->ListView->selectionModel()->selection();
for (int iRow = 0; iRow < mModel.rowCount(QModelIndex()); iRow++)
{
QModelIndex Index = mModel.index(iRow, 0);
if (kSelection.contains(Index))
HighlightPoiModels(Index);
else
UnhighlightPoiModels(Index);
}
mHighlightMode = eHighlightSelected;
}
void CPoiMapEditDialog::SetHighlightAll()
{
for (int iRow = 0; iRow < mModel.rowCount(QModelIndex()); iRow++)
HighlightPoiModels(mModel.index(iRow, 0));
mHighlightMode = eHighlightAll;
}
void CPoiMapEditDialog::SetHighlightNone()
{
for (int iRow = 0; iRow < mModel.rowCount(QModelIndex()); iRow++)
UnhighlightPoiModels(mModel.index(iRow, 0));
mHighlightMode = eHighlightNone;
}
void CPoiMapEditDialog::OnSelectionChanged(const QItemSelection& rkSelected, const QItemSelection& rkDeselected)
{
if (mHighlightMode == eHighlightSelected)
{
// Clear highlight on deselected models
QModelIndexList DeselectedIndices = rkDeselected.indexes();
for (int iIdx = 0; iIdx < DeselectedIndices.size(); iIdx++)
UnhighlightPoiModels(DeselectedIndices[iIdx]);
// Highlight newly selected models
QModelIndexList SelectedIndices = rkSelected.indexes();
for (int iIdx = 0; iIdx < SelectedIndices.size(); iIdx++)
HighlightPoiModels(SelectedIndices[iIdx]);
}
}
void CPoiMapEditDialog::OnItemDoubleClick(QModelIndex Index)
{
QModelIndex SourceIndex = mModel.mapToSource(Index);
CScriptNode *pPOI = mSourceModel.PoiNodePointer(SourceIndex);
mpEditor->ClearAndSelectNode(pPOI);
}

View File

@ -0,0 +1,48 @@
#ifndef CPOIMAPEDITDIALOG_H
#define CPOIMAPEDITDIALOG_H
#include <QMainWindow>
#include "CPoiMapModel.h"
#include <QItemSelection>
#include <QSortFilterProxyModel>
namespace Ui {
class CPoiMapEditDialog;
}
class CPoiMapEditDialog : public QMainWindow
{
Q_OBJECT
Ui::CPoiMapEditDialog *ui;
enum EHighlightMode
{
eHighlightAll,
eHighlightNone,
eHighlightSelected
};
CWorldEditor *mpEditor;
CPoiMapModel mSourceModel;
QSortFilterProxyModel mModel;
EHighlightMode mHighlightMode;
public:
explicit CPoiMapEditDialog(CWorldEditor *pEditor, QWidget *parent = 0);
~CPoiMapEditDialog();
void closeEvent(QCloseEvent *) { emit Closed(); }
void HighlightPoiModels(const QModelIndex& rkIndex);
void UnhighlightPoiModels(const QModelIndex& rkIndex);
public slots:
void SetHighlightSelected();
void SetHighlightAll();
void SetHighlightNone();
void OnSelectionChanged(const QItemSelection& rkSelected, const QItemSelection& rkDeselected);
void OnItemDoubleClick(QModelIndex Index);
signals:
void Closed();
};
#endif // CPOIMAPEDITDIALOG_H

View File

@ -0,0 +1,93 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>CPoiMapEditDialog</class>
<widget class="QMainWindow" name="CPoiMapEditDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>469</width>
<height>327</height>
</rect>
</property>
<property name="windowTitle">
<string>Edit POI to World Mappings</string>
</property>
<widget class="QWidget" name="centralwidget">
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QListView" name="ListView">
<property name="editTriggers">
<set>QAbstractItemView::NoEditTriggers</set>
</property>
<property name="verticalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
<property name="horizontalScrollMode">
<enum>QAbstractItemView::ScrollPerPixel</enum>
</property>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="ButtonBox">
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QToolBar" name="ToolBar">
<property name="windowTitle">
<string>toolBar</string>
</property>
<attribute name="toolBarArea">
<enum>TopToolBarArea</enum>
</attribute>
<attribute name="toolBarBreak">
<bool>false</bool>
</attribute>
<addaction name="ActionHighlightSelected"/>
<addaction name="ActionHighlightAll"/>
<addaction name="ActionHighlightNone"/>
</widget>
<action name="ActionHighlightAll">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>false</bool>
</property>
<property name="text">
<string>Highlight All</string>
</property>
</action>
<action name="ActionHighlightNone">
<property name="checkable">
<bool>true</bool>
</property>
<property name="text">
<string>Highlight None</string>
</property>
<property name="toolTip">
<string>Highlight None</string>
</property>
</action>
<action name="ActionHighlightSelected">
<property name="checkable">
<bool>true</bool>
</property>
<property name="checked">
<bool>true</bool>
</property>
<property name="text">
<string>Highlight Selected</string>
</property>
<property name="toolTip">
<string>Highlight Selected</string>
</property>
</action>
</widget>
<resources/>
<connections/>
</ui>

View File

@ -0,0 +1,112 @@
#include "CPoiMapModel.h"
#include "CWorldEditor.h"
#include "Editor/UICommon.h"
#include <Core/Scene/CSceneIterator.h>
#include <Core/ScriptExtra/CPointOfInterestExtra.h>
CPoiMapModel::CPoiMapModel(CWorldEditor *pEditor, QObject *pParent /*= 0*/)
: QAbstractListModel(pParent)
, mpEditor(pEditor)
{
mpEditor = pEditor;
mpPoiToWorld = mpEditor->ActiveArea()->GetPoiToWorldMap();
if (mpPoiToWorld)
{
// Create map of model nodes
QMap<u32,CModelNode*> NodeMap;
for (CSceneIterator It(mpEditor->Scene(), eModelNode, true); !It.DoneIterating(); ++It)
{
CModelNode *pNode = static_cast<CModelNode*>(*It);
NodeMap[pNode->FindMeshID()] = pNode;
}
// Create list of mappings
for (u32 iMap = 0; iMap < mpPoiToWorld->NumMeshLinks(); iMap++)
{
const CPoiToWorld::SPoiMeshLink& rkLink = mpPoiToWorld->MeshLinkByIndex(iMap);
CScriptNode *pPOI = mpEditor->Scene()->ScriptNodeByID(rkLink.PoiInstanceID);
if (!mPoiLookupMap.contains(pPOI))
{
SEditorPoiMap Map;
Map.pPOI = pPOI;
mMaps << Map;
mPoiLookupMap[pPOI] = &mMaps.last();
}
if (NodeMap.contains(rkLink.MeshID))
mPoiLookupMap[pPOI]->Models << NodeMap[rkLink.MeshID];
}
}
}
QVariant CPoiMapModel::headerData(int Section, Qt::Orientation Orientation, int Role) const
{
if ( (Section == 0) && (Orientation == Qt::Horizontal) && (Role == Qt::DisplayRole) )
return "PointOfInterest";
return QVariant::Invalid;
}
int CPoiMapModel::rowCount(const QModelIndex& /*rkParent*/) const
{
return mMaps.size();
}
QVariant CPoiMapModel::data(const QModelIndex& rkIndex, int Role) const
{
if (rkIndex.row() < mMaps.size())
{
const SEditorPoiMap& rkMap = mMaps[rkIndex.row()];
if (Role == Qt::DisplayRole)
{
if (rkMap.pPOI)
return TO_QSTRING(rkMap.pPOI->Object()->InstanceName());
else
return "[INVALID POI]";
}
else if (Role == Qt::DecorationRole)
{
bool IsImportant = false;
if (rkMap.pPOI)
{
// Get scan
CScan *pScan = static_cast<CPointOfInterestExtra*>(rkMap.pPOI->Extra())->GetScan();
if (pScan)
IsImportant = pScan->IsImportant();
}
if (IsImportant)
return QIcon(":/icons/POI Important.png");
else
return QIcon(":/icons/POI Normal.png");
}
}
return QVariant::Invalid;
}
CScriptNode* CPoiMapModel::PoiNodePointer(const QModelIndex& rkIndex) const
{
if (rkIndex.row() < mMaps.size())
return mMaps[rkIndex.row()].pPOI;
return nullptr;
}
const QList<CModelNode*>& CPoiMapModel::GetPoiMeshList(const QModelIndex& rkIndex) const
{
CScriptNode *pPOI = PoiNodePointer(rkIndex);
return GetPoiMeshList(pPOI);
}
const QList<CModelNode*>& CPoiMapModel::GetPoiMeshList(CScriptNode *pPOI) const
{
return mPoiLookupMap[pPOI]->Models;
}

View File

@ -0,0 +1,42 @@
#ifndef CPOIMAPMODEL_H
#define CPOIMAPMODEL_H
#include <Core/Resource/CPoiToWorld.h>
#include <Core/Resource/TResPtr.h>
#include <Core/Scene/CModelNode.h>
#include <Core/Scene/CScriptNode.h>
#include <QAbstractTableModel>
#include <QVector>
class CWorldEditor;
class CPoiMapModel : public QAbstractListModel
{
Q_OBJECT
public:
private:
CWorldEditor *mpEditor;
TResPtr<CPoiToWorld> mpPoiToWorld;
struct SEditorPoiMap
{
CScriptNode *pPOI;
QList<CModelNode*> Models;
};
QList<SEditorPoiMap> mMaps;
QMap<CScriptNode*,SEditorPoiMap*> mPoiLookupMap;
public:
explicit CPoiMapModel(CWorldEditor *pEditor, QObject *pParent = 0);
QVariant headerData(int Section, Qt::Orientation Orientation, int Role) const;
int rowCount(const QModelIndex& rkParent) const;
QVariant data(const QModelIndex& rkIndex, int Role) const;
CScriptNode* PoiNodePointer(const QModelIndex& rkIndex) const;
const QList<CModelNode*>& GetPoiMeshList(const QModelIndex& rkIndex) const;
const QList<CModelNode*>& GetPoiMeshList(CScriptNode *pPOI) const;
};
#endif // CPOIMAPMODEL_H

View File

@ -28,6 +28,7 @@ CWorldEditor::CWorldEditor(QWidget *parent) :
mpArea = nullptr;
mpWorld = nullptr;
mpPoiDialog = nullptr;
mGizmoHovering = false;
mGizmoTransforming = false;
@ -80,6 +81,12 @@ CWorldEditor::~CWorldEditor()
delete ui;
}
void CWorldEditor::closeEvent(QCloseEvent *)
{
if (mpPoiDialog)
mpPoiDialog->close();
}
bool CWorldEditor::eventFilter(QObject *pObj, QEvent *pEvent)
{
if (pObj == ui->MainDock)
@ -103,6 +110,12 @@ void CWorldEditor::SetArea(CWorld *pWorld, CGameArea *pArea)
ui->InstancesTabContents->SetArea(pArea);
mUndoStack.clear();
if (mpPoiDialog)
{
delete mpPoiDialog;
mpPoiDialog = nullptr;
}
// Clear old area - hack until better world/area loader is implemented
if ((mpArea) && (pArea != mpArea))
mpArea->ClearScriptLayers();
@ -160,7 +173,7 @@ void CWorldEditor::UpdateStatusBar()
{
CSceneNode *pHoverNode = ui->MainViewport->HoverNode();
if (pHoverNode && (pHoverNode->NodeType() != eStaticNode))
if (pHoverNode && (pHoverNode->NodeType() != eStaticNode) && (pHoverNode->NodeType() != eModelNode))
StatusText = TO_QSTRING(pHoverNode->Name());
}
}
@ -259,7 +272,7 @@ void CWorldEditor::UpdateCursor()
if (ui->MainViewport->IsHoveringGizmo())
ui->MainViewport->SetCursorState(Qt::SizeAllCursor);
else if ((pHoverNode) && (pHoverNode->NodeType() != eStaticNode))
else if ((pHoverNode) && (pHoverNode->NodeType() != eStaticNode) && (pHoverNode->NodeType() != eModelNode))
ui->MainViewport->SetCursorState(Qt::PointingHandCursor);
else
ui->MainViewport->SetCursorState(Qt::ArrowCursor);
@ -350,10 +363,17 @@ void CWorldEditor::OnTransformSpinBoxEdited(CVector3f)
UpdateGizmoUI();
}
void CWorldEditor::OnClosePoiEditDialog()
{
delete mpPoiDialog;
mpPoiDialog = nullptr;
ui->MainViewport->SetRenderMergedWorld(true);
}
// These functions are from "Go to slot" in the designer
void CWorldEditor::on_ActionDrawWorld_triggered()
{
ui->MainViewport->SetShowFlag(eShowWorld, ui->ActionDrawWorld->isChecked());
ui->MainViewport->SetShowWorld(ui->ActionDrawWorld->isChecked());
}
void CWorldEditor::on_ActionDrawCollision_triggered()
@ -477,13 +497,28 @@ void CWorldEditor::on_ActionGameMode_triggered()
void CWorldEditor::on_ActionSelectAll_triggered()
{
FNodeFlags NodeFlags = CScene::NodeFlagsForShowFlags(ui->MainViewport->ShowFlags());
NodeFlags &= ~(eStaticNode | eCollisionNode);
NodeFlags &= ~(eModelNode | eStaticNode | eCollisionNode);
SelectAll(NodeFlags);
}
void CWorldEditor::on_ActionInvertSelection_triggered()
{
FNodeFlags NodeFlags = CScene::NodeFlagsForShowFlags(ui->MainViewport->ShowFlags());
NodeFlags &= ~(eStaticNode | eCollisionNode);
NodeFlags &= ~(eModelNode | eStaticNode | eCollisionNode);
InvertSelection(NodeFlags);
}
void CWorldEditor::on_ActionEditPoiToWorldMap_triggered()
{
if (!mpPoiDialog)
{
mpPoiDialog = new CPoiMapEditDialog(this, this);
mpPoiDialog->show();
ui->MainViewport->SetRenderMergedWorld(false);
connect(mpPoiDialog, SIGNAL(Closed()), this, SLOT(OnClosePoiEditDialog()));
}
else
{
mpPoiDialog->show();
}
}

View File

@ -1,6 +1,7 @@
#ifndef CWORLDEDITOR_H
#define CWORLDEDITOR_H
#include "CPoiMapEditDialog.h"
#include "Editor/INodeEditor.h"
#include "Editor/CGizmo.h"
@ -34,9 +35,12 @@ class CWorldEditor : public INodeEditor
TResPtr<CGameArea> mpArea;
QTimer mRefreshTimer;
CPoiMapEditDialog *mpPoiDialog;
public:
explicit CWorldEditor(QWidget *parent = 0);
~CWorldEditor();
void closeEvent(QCloseEvent *);
bool eventFilter(QObject *pObj, QEvent *pEvent);
void SetArea(CWorld *pWorld, CGameArea *pArea);
CGameArea* ActiveArea();
@ -58,6 +62,7 @@ private slots:
void OnCameraSpeedChange(double speed);
void OnTransformSpinBoxModified(CVector3f value);
void OnTransformSpinBoxEdited(CVector3f value);
void OnClosePoiEditDialog();
void on_ActionDrawWorld_triggered();
void on_ActionDrawCollision_triggered();
void on_ActionDrawObjects_triggered();
@ -79,6 +84,7 @@ private slots:
void on_ActionGameMode_triggered();
void on_ActionSelectAll_triggered();
void on_ActionInvertSelection_triggered();
void on_ActionEditPoiToWorldMap_triggered();
};
#endif // CWORLDEDITOR_H

View File

@ -289,6 +289,7 @@
<string>Tools</string>
</property>
<addaction name="ActionEditLayers"/>
<addaction name="ActionEditPoiToWorldMap"/>
</widget>
<addaction name="menuFile"/>
<addaction name="menuEdit"/>
@ -758,6 +759,11 @@
<string>Ctrl+I</string>
</property>
</action>
<action name="ActionEditPoiToWorldMap">
<property name="text">
<string>Edit POI to World Map</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>

View File

@ -173,6 +173,9 @@
<attribute name="horizontalHeaderStretchLastSection">
<bool>false</bool>
</attribute>
<attribute name="verticalHeaderDefaultSectionSize">
<number>21</number>
</attribute>
</widget>
</item>
</layout>
@ -195,6 +198,9 @@
<attribute name="horizontalHeaderDefaultSectionSize">
<number>75</number>
</attribute>
<attribute name="verticalHeaderDefaultSectionSize">
<number>21</number>
</attribute>
</widget>
</item>
</layout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View File

@ -7,13 +7,16 @@
int main(int argc, char *argv[])
{
// Create application
QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts);
QApplication app(argc, argv);
CStartWindow w;
w.show();
// Load templates
CTemplateLoader::LoadGameList();
// Set up dark style
app.setStyle(new CDarkStyle);
qApp->setStyle(QStyleFactory::create("Fusion"));
@ -35,5 +38,6 @@ int main(int argc, char *argv[])
qApp->setPalette(darkPalette);
// Execute application
return app.exec();
}