From c0b74c98838e120384603fcc0c15b172bed1eacd Mon Sep 17 00:00:00 2001 From: parax0 Date: Fri, 15 Jan 2016 16:36:58 -0700 Subject: [PATCH] Added support for EGMC and a basic EGMC visualizer dialog --- src/Core/Core.pro | 8 +- src/Core/Resource/CGameArea.cpp | 5 + src/Core/Resource/CGameArea.h | 4 + src/Core/Resource/CPoiToWorld.cpp | 27 ++++ src/Core/Resource/CPoiToWorld.h | 40 ++++++ src/Core/Resource/CResCache.cpp | 3 + src/Core/Resource/EResType.h | 25 ++-- src/Core/Resource/Factory/CAreaLoader.cpp | 57 ++++++-- src/Core/Resource/Factory/CAreaLoader.h | 1 + .../Resource/Factory/CPoiToWorldLoader.cpp | 17 +++ src/Core/Resource/Factory/CPoiToWorldLoader.h | 17 +++ src/Core/Scene/CModelNode.cpp | 11 +- src/Core/Scene/CModelNode.h | 46 ++----- src/Core/Scene/CScene.cpp | 38 +++--- src/Core/Scene/CScriptNode.cpp | 5 + src/Core/Scene/CScriptNode.h | 5 +- src/Core/Scene/FShowFlags.cpp | 2 +- src/Core/Scene/FShowFlags.h | 17 +-- src/Core/ScriptExtra/CPointOfInterestExtra.h | 1 + src/Editor/CSceneViewport.cpp | 26 +++- src/Editor/CSceneViewport.h | 3 + src/Editor/Editor.pro | 11 +- src/Editor/Icons.qrc | 4 +- src/Editor/WorldEditor/CPoiMapEditDialog.cpp | 129 ++++++++++++++++++ src/Editor/WorldEditor/CPoiMapEditDialog.h | 48 +++++++ src/Editor/WorldEditor/CPoiMapEditDialog.ui | 93 +++++++++++++ src/Editor/WorldEditor/CPoiMapModel.cpp | 112 +++++++++++++++ src/Editor/WorldEditor/CPoiMapModel.h | 42 ++++++ src/Editor/WorldEditor/CWorldEditor.cpp | 45 +++++- src/Editor/WorldEditor/CWorldEditor.h | 6 + src/Editor/WorldEditor/CWorldEditor.ui | 6 + src/Editor/WorldEditor/WModifyTab.ui | 6 + src/Editor/icons/POI Important.png | Bin 0 -> 3095 bytes src/Editor/icons/POI Normal.png | Bin 0 -> 3178 bytes src/Editor/main.cpp | 4 + 35 files changed, 763 insertions(+), 101 deletions(-) create mode 100644 src/Core/Resource/CPoiToWorld.cpp create mode 100644 src/Core/Resource/CPoiToWorld.h create mode 100644 src/Core/Resource/Factory/CPoiToWorldLoader.cpp create mode 100644 src/Core/Resource/Factory/CPoiToWorldLoader.h create mode 100644 src/Editor/WorldEditor/CPoiMapEditDialog.cpp create mode 100644 src/Editor/WorldEditor/CPoiMapEditDialog.h create mode 100644 src/Editor/WorldEditor/CPoiMapEditDialog.ui create mode 100644 src/Editor/WorldEditor/CPoiMapModel.cpp create mode 100644 src/Editor/WorldEditor/CPoiMapModel.h create mode 100644 src/Editor/icons/POI Important.png create mode 100644 src/Editor/icons/POI Normal.png diff --git a/src/Core/Core.pro b/src/Core/Core.pro index 342a7e14..57c03b4e 100644 --- a/src/Core/Core.pro +++ b/src/Core/Core.pro @@ -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 diff --git a/src/Core/Resource/CGameArea.cpp b/src/Core/Resource/CGameArea.cpp index 51841e04..f6d22aaa 100644 --- a/src/Core/Resource/CGameArea.cpp +++ b/src/Core/Resource/CGameArea.cpp @@ -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; diff --git a/src/Core/Resource/CGameArea.h b/src/Core/Resource/CGameArea.h index bc253df6..f5112c21 100644 --- a/src/Core/Resource/CGameArea.h +++ b/src/Core/Resource/CGameArea.h @@ -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 @@ -40,6 +41,8 @@ class CGameArea : public CResource CCollisionMeshGroup *mCollision; // Lights std::vector> mLightLayers; + // Object to Static Geometry Map + TResPtr mpPoiToWorldMap; public: CGameArea(); @@ -65,6 +68,7 @@ public: u32 GetLightLayerCount(); u32 GetLightCount(u32 layer); CLight* GetLight(u32 layer, u32 light); + CPoiToWorld* GetPoiToWorldMap(); CAABox AABox(); }; diff --git a/src/Core/Resource/CPoiToWorld.cpp b/src/Core/Resource/CPoiToWorld.cpp new file mode 100644 index 00000000..3ba9d389 --- /dev/null +++ b/src/Core/Resource/CPoiToWorld.cpp @@ -0,0 +1,27 @@ +#include "CPoiToWorld.h" + +CPoiToWorld::CPoiToWorld() +{ +} + +CPoiToWorld::~CPoiToWorld() +{ +} + +void CPoiToWorld::LinksForMeshID(std::list& 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& rOutMeshIDs, u32 InstanceID) +{ + for (u32 iLink = 0; iLink < mMeshLinks.size(); iLink++) + { + if (mMeshLinks[iLink].PoiInstanceID == InstanceID) + rOutMeshIDs.push_back(mMeshLinks[iLink].MeshID); + } +} diff --git a/src/Core/Resource/CPoiToWorld.h b/src/Core/Resource/CPoiToWorld.h new file mode 100644 index 00000000..e2c00954 --- /dev/null +++ b/src/Core/Resource/CPoiToWorld.h @@ -0,0 +1,40 @@ +#ifndef CPOITOWORLD_H +#define CPOITOWORLD_H + +#include "CResource.h" +#include + +class CPoiToWorld : public CResource +{ + DECLARE_RESOURCE_TYPE(ePoiToWorld) + friend class CPoiToWorldLoader; + +public: + struct SPoiMeshLink + { + u32 MeshID; + u32 PoiInstanceID; + }; + +private: + std::vector mMeshLinks; + +public: + CPoiToWorld(); + ~CPoiToWorld(); + + void LinksForMeshID(std::list& rOutInstanceIDs, u32 MeshID); + void LinksForInstanceID(std::list& rOutMeshIDs, u32 InstanceID); + + inline u32 NumMeshLinks() + { + return mMeshLinks.size(); + } + + inline const SPoiMeshLink& MeshLinkByIndex(u32 Index) + { + return mMeshLinks[Index]; + } +}; + +#endif // CPOITOWORLD_H diff --git a/src/Core/Resource/CResCache.cpp b/src/Core/Resource/CResCache.cpp index e22338e8..031d11ae 100644 --- a/src/Core/Resource/CResCache.cpp +++ b/src/Core/Resource/CResCache.cpp @@ -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 diff --git a/src/Core/Resource/EResType.h b/src/Core/Resource/EResType.h index 90ed216d..4fe43ec7 100644 --- a/src/Core/Resource/EResType.h +++ b/src/Core/Resource/EResType.h @@ -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 diff --git a/src/Core/Resource/Factory/CAreaLoader.cpp b/src/Core/Resource/Factory/CAreaLoader.cpp index d91010da..8ad592c0 100644 --- a/src/Core/Resource/Factory/CAreaLoader.cpp +++ b/src/Core/Resource/Factory/CAreaLoader.cpp @@ -76,16 +76,25 @@ void CAreaLoader::ReadGeometryPrime() // Geometry std::vector 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 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 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)); diff --git a/src/Core/Resource/Factory/CAreaLoader.h b/src/Core/Resource/Factory/CAreaLoader.h index 10542d2c..7312161c 100644 --- a/src/Core/Resource/Factory/CAreaLoader.h +++ b/src/Core/Resource/Factory/CAreaLoader.h @@ -75,6 +75,7 @@ class CAreaLoader void ReadCompressedBlocks(); void Decompress(); void ReadCollision(); + void ReadEGMC(); void SetUpObjects(); public: diff --git a/src/Core/Resource/Factory/CPoiToWorldLoader.cpp b/src/Core/Resource/Factory/CPoiToWorldLoader.cpp new file mode 100644 index 00000000..e7e46d62 --- /dev/null +++ b/src/Core/Resource/Factory/CPoiToWorldLoader.cpp @@ -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; +} diff --git a/src/Core/Resource/Factory/CPoiToWorldLoader.h b/src/Core/Resource/Factory/CPoiToWorldLoader.h new file mode 100644 index 00000000..b79b85c9 --- /dev/null +++ b/src/Core/Resource/Factory/CPoiToWorldLoader.h @@ -0,0 +1,17 @@ +#ifndef CPOITOWORLDLOADER_H +#define CPOITOWORLDLOADER_H + +#include "Core/Resource/CPoiToWorld.h" +#include "Core/Resource/TResPtr.h" + +class CPoiToWorldLoader +{ + TResPtr mpPoiToWorld; + + CPoiToWorldLoader() {} + +public: + static CPoiToWorld* LoadEGMC(IInputStream& rEGMC); +}; + +#endif // CPOITOWORLDLOADER_H diff --git a/src/Core/Scene/CModelNode.cpp b/src/Core/Scene/CModelNode.cpp index dc1c91f2..58235d59 100644 --- a/src/Core/Scene/CModelNode.cpp +++ b/src/Core/Scene/CModelNode.cpp @@ -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; -} diff --git a/src/Core/Scene/CModelNode.h b/src/Core/Scene/CModelNode.h index eb75a3f3..b3d34ed2 100644 --- a/src/Core/Scene/CModelNode.h +++ b/src/Core/Scene/CModelNode.h @@ -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 diff --git a/src/Core/Scene/CScene.cpp b/src/Core/Scene/CScene.cpp index 21e3592b..6c0bd473 100644 --- a/src/Core/Scene/CScene.cpp +++ b/src/Core/Scene/CScene.cpp @@ -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,23 +89,24 @@ void CScene::SetActiveArea(CGameArea *pArea) mpArea = pArea; mpAreaRootNode = new CRootNode(this, mpSceneRootNode); - if (mSplitTerrain) - { - u32 Count = mpArea->GetStaticModelCount(); + // Create static nodes + u32 Count = mpArea->GetStaticModelCount(); - for (u32 iMdl = 0; iMdl < Count; iMdl++) - CreateStaticNode(mpArea->GetStaticModel(iMdl)); + for (u32 iMdl = 0; iMdl < Count; iMdl++) + { + CStaticNode *pNode = CreateStaticNode(mpArea->GetStaticModel(iMdl)); + pNode->SetName("Static World Model " + TString::FromInt32(iMdl, 0, 10)); } - else - { - u32 Count = mpArea->GetTerrainModelCount(); - for (u32 iMdl = 0; iMdl < Count; iMdl++) - { - CModel *pModel = mpArea->GetTerrainModel(iMdl); - CModelNode *pNode = CreateModelNode(pModel); - pNode->SetDynamicLighting(false); - } + // 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; diff --git a/src/Core/Scene/CScriptNode.cpp b/src/Core/Scene/CScriptNode.cpp index 45dbe0c1..352ec36e 100644 --- a/src/Core/Scene/CScriptNode.cpp +++ b/src/Core/Scene/CScriptNode.cpp @@ -458,6 +458,11 @@ CScriptTemplate* CScriptNode::Template() const return mpInstance->Template(); } +CScriptExtra* CScriptNode::Extra() const +{ + return mpExtra; +} + CModel* CScriptNode::ActiveModel() const { return mpActiveModel; diff --git a/src/Core/Scene/CScriptNode.h b/src/Core/Scene/CScriptNode.h index dc6536d3..ea124676 100644 --- a/src/Core/Scene/CScriptNode.h +++ b/src/Core/Scene/CScriptNode.h @@ -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 mpActiveModel; TResPtr 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; diff --git a/src/Core/Scene/FShowFlags.cpp b/src/Core/Scene/FShowFlags.cpp index ba3f1fe0..51d4e1c2 100644 --- a/src/Core/Scene/FShowFlags.cpp +++ b/src/Core/Scene/FShowFlags.cpp @@ -1,3 +1,3 @@ #include "FShowFlags.h" -const FShowFlags gkGameModeShowFlags = eShowWorld | eShowObjectGeometry | eShowSky; +const FShowFlags gkGameModeShowFlags = eShowMergedWorld | eShowObjectGeometry | eShowSky; diff --git a/src/Core/Scene/FShowFlags.h b/src/Core/Scene/FShowFlags.h index a2913306..0dbe3da1 100644 --- a/src/Core/Scene/FShowFlags.h +++ b/src/Core/Scene/FShowFlags.h @@ -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) diff --git a/src/Core/ScriptExtra/CPointOfInterestExtra.h b/src/Core/ScriptExtra/CPointOfInterestExtra.h index 7db7fe46..d516f1cc 100644 --- a/src/Core/ScriptExtra/CPointOfInterestExtra.h +++ b/src/Core/ScriptExtra/CPointOfInterestExtra.h @@ -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; diff --git a/src/Editor/CSceneViewport.cpp b/src/Editor/CSceneViewport.cpp index 91a1c4cb..9187fe13 100644 --- a/src/Editor/CSceneViewport.cpp +++ b/src/Editor/CSceneViewport.cpp @@ -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); diff --git a/src/Editor/CSceneViewport.h b/src/Editor/CSceneViewport.h index e628706f..10b5fa92 100644 --- a/src/Editor/CSceneViewport.h +++ b/src/Editor/CSceneViewport.h @@ -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(); diff --git a/src/Editor/Editor.pro b/src/Editor/Editor.pro index a2628686..dfdc8496 100644 --- a/src/Editor/Editor.pro +++ b/src/Editor/Editor.pro @@ -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 diff --git a/src/Editor/Icons.qrc b/src/Editor/Icons.qrc index eeaf41cd..157e59b0 100644 --- a/src/Editor/Icons.qrc +++ b/src/Editor/Icons.qrc @@ -1,5 +1,5 @@ - + icons/Down.png icons/Free Camera.png icons/Material Highlight.png @@ -28,5 +28,7 @@ icons/Unlink.png icons/World.png icons/SelectMode.png + icons/POI Important.png + icons/POI Normal.png diff --git a/src/Editor/WorldEditor/CPoiMapEditDialog.cpp b/src/Editor/WorldEditor/CPoiMapEditDialog.cpp new file mode 100644 index 00000000..8804bb52 --- /dev/null +++ b/src/Editor/WorldEditor/CPoiMapEditDialog.cpp @@ -0,0 +1,129 @@ +#include "CPoiMapEditDialog.h" +#include "ui_CPoiMapEditDialog.h" +#include "CWorldEditor.h" +#include +#include + +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& rkModels = mSourceModel.GetPoiMeshList(pPOI); + + // Check whether this is an important scan + bool IsImportant = false; + TResPtr pScan = static_cast(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& 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); +} diff --git a/src/Editor/WorldEditor/CPoiMapEditDialog.h b/src/Editor/WorldEditor/CPoiMapEditDialog.h new file mode 100644 index 00000000..99fe3543 --- /dev/null +++ b/src/Editor/WorldEditor/CPoiMapEditDialog.h @@ -0,0 +1,48 @@ +#ifndef CPOIMAPEDITDIALOG_H +#define CPOIMAPEDITDIALOG_H + +#include +#include "CPoiMapModel.h" +#include +#include + +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 diff --git a/src/Editor/WorldEditor/CPoiMapEditDialog.ui b/src/Editor/WorldEditor/CPoiMapEditDialog.ui new file mode 100644 index 00000000..6312ce74 --- /dev/null +++ b/src/Editor/WorldEditor/CPoiMapEditDialog.ui @@ -0,0 +1,93 @@ + + + CPoiMapEditDialog + + + + 0 + 0 + 469 + 327 + + + + Edit POI to World Mappings + + + + + + + QAbstractItemView::NoEditTriggers + + + QAbstractItemView::ScrollPerPixel + + + QAbstractItemView::ScrollPerPixel + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + toolBar + + + TopToolBarArea + + + false + + + + + + + + true + + + false + + + Highlight All + + + + + true + + + Highlight None + + + Highlight None + + + + + true + + + true + + + Highlight Selected + + + Highlight Selected + + + + + + diff --git a/src/Editor/WorldEditor/CPoiMapModel.cpp b/src/Editor/WorldEditor/CPoiMapModel.cpp new file mode 100644 index 00000000..615c6d20 --- /dev/null +++ b/src/Editor/WorldEditor/CPoiMapModel.cpp @@ -0,0 +1,112 @@ +#include "CPoiMapModel.h" +#include "CWorldEditor.h" +#include "Editor/UICommon.h" +#include +#include + +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 NodeMap; + + for (CSceneIterator It(mpEditor->Scene(), eModelNode, true); !It.DoneIterating(); ++It) + { + CModelNode *pNode = static_cast(*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(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& CPoiMapModel::GetPoiMeshList(const QModelIndex& rkIndex) const +{ + CScriptNode *pPOI = PoiNodePointer(rkIndex); + return GetPoiMeshList(pPOI); +} + +const QList& CPoiMapModel::GetPoiMeshList(CScriptNode *pPOI) const +{ + return mPoiLookupMap[pPOI]->Models; +} diff --git a/src/Editor/WorldEditor/CPoiMapModel.h b/src/Editor/WorldEditor/CPoiMapModel.h new file mode 100644 index 00000000..a336c18d --- /dev/null +++ b/src/Editor/WorldEditor/CPoiMapModel.h @@ -0,0 +1,42 @@ +#ifndef CPOIMAPMODEL_H +#define CPOIMAPMODEL_H + +#include +#include +#include +#include +#include +#include + +class CWorldEditor; + +class CPoiMapModel : public QAbstractListModel +{ + Q_OBJECT + +public: + +private: + CWorldEditor *mpEditor; + TResPtr mpPoiToWorld; + + struct SEditorPoiMap + { + CScriptNode *pPOI; + QList Models; + }; + QList mMaps; + QMap 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& GetPoiMeshList(const QModelIndex& rkIndex) const; + const QList& GetPoiMeshList(CScriptNode *pPOI) const; +}; + +#endif // CPOIMAPMODEL_H diff --git a/src/Editor/WorldEditor/CWorldEditor.cpp b/src/Editor/WorldEditor/CWorldEditor.cpp index 9808c15c..06f6f626 100644 --- a/src/Editor/WorldEditor/CWorldEditor.cpp +++ b/src/Editor/WorldEditor/CWorldEditor.cpp @@ -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(); + } +} diff --git a/src/Editor/WorldEditor/CWorldEditor.h b/src/Editor/WorldEditor/CWorldEditor.h index be79c110..fa81f1e7 100644 --- a/src/Editor/WorldEditor/CWorldEditor.h +++ b/src/Editor/WorldEditor/CWorldEditor.h @@ -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 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 diff --git a/src/Editor/WorldEditor/CWorldEditor.ui b/src/Editor/WorldEditor/CWorldEditor.ui index ec72e51b..572997f3 100644 --- a/src/Editor/WorldEditor/CWorldEditor.ui +++ b/src/Editor/WorldEditor/CWorldEditor.ui @@ -289,6 +289,7 @@ Tools + @@ -758,6 +759,11 @@ Ctrl+I + + + Edit POI to World Map + + diff --git a/src/Editor/WorldEditor/WModifyTab.ui b/src/Editor/WorldEditor/WModifyTab.ui index d2c8493b..45dee2c9 100644 --- a/src/Editor/WorldEditor/WModifyTab.ui +++ b/src/Editor/WorldEditor/WModifyTab.ui @@ -173,6 +173,9 @@ false + + 21 + @@ -195,6 +198,9 @@ 75 + + 21 + diff --git a/src/Editor/icons/POI Important.png b/src/Editor/icons/POI Important.png new file mode 100644 index 0000000000000000000000000000000000000000..a258aa21e43c249b0ca2b3bb8b930ffc93b90db5 GIT binary patch literal 3095 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 Q!vFvP07*qoM6N<$f{q94w*UYD literal 0 HcmV?d00001 diff --git a/src/Editor/main.cpp b/src/Editor/main.cpp index 3ea787ff..8c65685e 100644 --- a/src/Editor/main.cpp +++ b/src/Editor/main.cpp @@ -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(); }