diff --git a/src/Core/GameProject/CDependencyTree.cpp b/src/Core/GameProject/CDependencyTree.cpp index 895bb747..1a12ad3a 100644 --- a/src/Core/GameProject/CDependencyTree.cpp +++ b/src/Core/GameProject/CDependencyTree.cpp @@ -142,7 +142,8 @@ void CScriptInstanceDependency::ParseStructDependencies(CScriptInstanceDependenc if (SoundID != -1) { - SSoundInfo Info = CGameProject::ActiveProject()->AudioManager()->GetSoundInfo(SoundID); + CGameProject *pProj = pStruct->Instance()->Area()->Entry()->Project(); + SSoundInfo Info = pProj->AudioManager()->GetSoundInfo(SoundID); if (Info.pAudioGroup) { diff --git a/src/Core/GameProject/CGameExporter.cpp b/src/Core/GameProject/CGameExporter.cpp index 2e91277a..f282fe4a 100644 --- a/src/Core/GameProject/CGameExporter.cpp +++ b/src/Core/GameProject/CGameExporter.cpp @@ -53,8 +53,6 @@ bool CGameExporter::Export(nod::DiscBase *pDisc, const TString& rkOutputDir, CAs return false; // Create project - CGameProject *pOldActiveProj = CGameProject::ActiveProject(); - mpProject = CGameProject::CreateProjectForExport( this, mExportDir, @@ -68,11 +66,13 @@ bool CGameExporter::Export(nod::DiscBase *pDisc, const TString& rkOutputDir, CAs mFilesystemAddress); mpProject->SetProjectName(mGameName); - mpProject->SetActive(); mpStore = mpProject->ResourceStore(); mContentDir = mpStore->RawDir(false); mCookedDir = mpStore->CookedDir(false); + CResourceStore *pOldStore = gpResourceStore; + gpResourceStore = mpStore; + // Export game data LoadPaks(); ExportCookedResources(); @@ -82,7 +82,7 @@ bool CGameExporter::Export(nod::DiscBase *pDisc, const TString& rkOutputDir, CAs // Export finished! mProjectPath = mpProject->ProjectPath(); delete mpProject; - if (pOldActiveProj) pOldActiveProj->SetActive(); + if (pOldStore) gpResourceStore = pOldStore; return true; } diff --git a/src/Core/GameProject/CGameProject.cpp b/src/Core/GameProject/CGameProject.cpp index de535198..9e561ff2 100644 --- a/src/Core/GameProject/CGameProject.cpp +++ b/src/Core/GameProject/CGameProject.cpp @@ -3,19 +3,14 @@ #include "Core/Resource/Script/CMasterTemplate.h" #include -CGameProject *CGameProject::mspActiveProject = nullptr; - CGameProject::~CGameProject() { if (mpResourceStore) { ASSERT(!mpResourceStore->IsDirty()); - } - if (IsActive()) - { - mspActiveProject = nullptr; - gpResourceStore = nullptr; + if (gpResourceStore == mpResourceStore) + gpResourceStore = nullptr; } for (u32 iPkg = 0; iPkg < mPackages.size(); iPkg++) @@ -99,15 +94,6 @@ void CGameProject::Serialize(IArchive& rArc) } } -void CGameProject::SetActive() -{ - if (mspActiveProject != this) - { - mspActiveProject = this; - gpResourceStore = mpResourceStore; - } -} - void CGameProject::GetWorldList(std::list& rOut) const { for (u32 iPkg = 0; iPkg < mPackages.size(); iPkg++) diff --git a/src/Core/GameProject/CGameProject.h b/src/Core/GameProject/CGameProject.h index 58fca0d0..6f0ba745 100644 --- a/src/Core/GameProject/CGameProject.h +++ b/src/Core/GameProject/CGameProject.h @@ -45,8 +45,6 @@ class CGameProject eVer_Current = eVer_Max - 1 }; - static CGameProject *mspActiveProject; - // Private Constructor CGameProject() : mProjectName("Unnamed Project") @@ -67,7 +65,6 @@ public: bool Save(); void Serialize(IArchive& rArc); - void SetActive(); void GetWorldList(std::list& rOut) const; CAssetID FindNamedResource(const TString& rkName) const; @@ -107,10 +104,7 @@ public: inline CAudioManager* AudioManager() const { return mpAudioManager; } inline EGame Game() const { return mGame; } inline float BuildVersion() const { return mBuildVersion; } - inline bool IsActive() const { return mspActiveProject == this; } inline bool IsWiiBuild() const { return mBuildVersion >= 3.f; } - - static inline CGameProject* ActiveProject() { return mspActiveProject; } }; #endif // CGAMEPROJECT_H diff --git a/src/Core/GameProject/CResourceEntry.cpp b/src/Core/GameProject/CResourceEntry.cpp index e2f0c852..cbf10e07 100644 --- a/src/Core/GameProject/CResourceEntry.cpp +++ b/src/Core/GameProject/CResourceEntry.cpp @@ -497,3 +497,8 @@ void CResourceEntry::RemoveFromProject() Log::Error("RemoveFromProject called on transient resource entry: " + CookedAssetPath(true)); } } + +CGameProject* CResourceEntry::Project() const +{ + return mpStore->Project(); +} diff --git a/src/Core/GameProject/CResourceEntry.h b/src/Core/GameProject/CResourceEntry.h index 24907f89..58f1e69f 100644 --- a/src/Core/GameProject/CResourceEntry.h +++ b/src/Core/GameProject/CResourceEntry.h @@ -11,6 +11,7 @@ class CResource; class CResourceStore; +class CGameProject; class CDependencyTree; enum EResEntryFlag @@ -68,6 +69,7 @@ public: bool Move(const TWideString& rkDir, const TWideString& rkName); void AddToProject(const TWideString& rkDir, const TWideString& rkName); void RemoveFromProject(); + CGameProject* Project() const; // Accessors void SetDirty() { mFlags.SetFlag(eREF_NeedsRecook); } diff --git a/src/Core/Render/CDrawUtil.cpp b/src/Core/Render/CDrawUtil.cpp index aafc8135..da5c82ae 100644 --- a/src/Core/Render/CDrawUtil.cpp +++ b/src/Core/Render/CDrawUtil.cpp @@ -41,7 +41,7 @@ TResPtr CDrawUtil::mpLightMasks[4]; bool CDrawUtil::mDrawUtilInitialized = false; // ************ PUBLIC ************ -void CDrawUtil::DrawGrid() +void CDrawUtil::DrawGrid(CColor LineColor, CColor BoldLineColor) { Init(); @@ -55,11 +55,13 @@ void CDrawUtil::DrawGrid() glDepthMask(GL_TRUE); glLineWidth(1.0f); - UseColorShader(CColor(0.6f, 0.6f, 0.6f, 0.f)); + LineColor.A = 0.f; + UseColorShader(LineColor); mGridIndices.DrawElements(0, mGridIndices.GetSize() - 4); glLineWidth(1.5f); - UseColorShader(CColor::skTransparentBlack); + BoldLineColor.A = 0.f; + UseColorShader(BoldLineColor); mGridIndices.DrawElements(mGridIndices.GetSize() - 4, 4); } @@ -405,25 +407,32 @@ void CDrawUtil::Init() void CDrawUtil::InitGrid() { Log::Write("Creating grid"); - mGridVertices.SetVertexDesc(ePosition); - mGridVertices.Reserve(64); - for (s32 i = -7; i < 8; i++) + const int kGridSize = 501; // must be odd + const float kGridSpacing = 1.f; + int MinIdx = (kGridSize - 1) / -2; + int MaxIdx = (kGridSize - 1) / 2; + + mGridVertices.SetVertexDesc(ePosition); + mGridVertices.Reserve(kGridSize * 4); + + for (s32 i = MinIdx; i <= MaxIdx; i++) { if (i == 0) continue; - mGridVertices.AddVertex(CVector3f(-7.0f, float(i), 0.0f)); - mGridVertices.AddVertex(CVector3f( 7.0f, float(i), 0.0f)); - mGridVertices.AddVertex(CVector3f(float(i), -7.0f, 0.0f)); - mGridVertices.AddVertex(CVector3f(float(i), 7.0f, 0.0f)); + mGridVertices.AddVertex(CVector3f(MinIdx * kGridSpacing, i * kGridSpacing, 0.0f)); + mGridVertices.AddVertex(CVector3f(MaxIdx * kGridSpacing, i * kGridSpacing, 0.0f)); + mGridVertices.AddVertex(CVector3f(i * kGridSpacing, MinIdx * kGridSpacing, 0.0f)); + mGridVertices.AddVertex(CVector3f(i * kGridSpacing, MaxIdx * kGridSpacing, 0.0f)); } - mGridVertices.AddVertex(CVector3f(-7.0f, 0, 0.0f)); - mGridVertices.AddVertex(CVector3f( 7.0f, 0, 0.0f)); - mGridVertices.AddVertex(CVector3f(0, -7.0f, 0.0f)); - mGridVertices.AddVertex(CVector3f(0, 7.0f, 0.0f)); + mGridVertices.AddVertex(CVector3f(MinIdx * kGridSpacing, 0, 0.0f)); + mGridVertices.AddVertex(CVector3f(MaxIdx * kGridSpacing, 0, 0.0f)); + mGridVertices.AddVertex(CVector3f(0, MinIdx * kGridSpacing, 0.0f)); + mGridVertices.AddVertex(CVector3f(0, MaxIdx * kGridSpacing, 0.0f)); - mGridIndices.Reserve(60); - for (u16 i = 0; i < 60; i++) mGridIndices.AddIndex(i); + int NumIndices = kGridSize * 4; + mGridIndices.Reserve(NumIndices); + for (u16 i = 0; i < NumIndices; i++) mGridIndices.AddIndex(i); mGridIndices.SetPrimitiveType(GL_LINES); } diff --git a/src/Core/Render/CDrawUtil.h b/src/Core/Render/CDrawUtil.h index 13014945..91c33fda 100644 --- a/src/Core/Render/CDrawUtil.h +++ b/src/Core/Render/CDrawUtil.h @@ -57,7 +57,7 @@ class CDrawUtil static bool mDrawUtilInitialized; public: - static void DrawGrid(); + static void DrawGrid(CColor LineColor, CColor BoldLineColor); static void DrawSquare(); static void DrawSquare(const CVector2f& TexUL, const CVector2f& TexUR, const CVector2f& TexBR, const CVector2f& TexBL); diff --git a/src/Core/Resource/Factory/CAnimEventLoader.cpp b/src/Core/Resource/Factory/CAnimEventLoader.cpp index 5494bccc..3eabd614 100644 --- a/src/Core/Resource/Factory/CAnimEventLoader.cpp +++ b/src/Core/Resource/Factory/CAnimEventLoader.cpp @@ -67,7 +67,7 @@ void CAnimEventLoader::LoadEvents(IInputStream& rEVNT, bool IsEchoes) if (SoundID != 0xFFFF) { - SSoundInfo SoundInfo = CGameProject::ActiveProject()->AudioManager()->GetSoundInfo(SoundID); + SSoundInfo SoundInfo = mpEventData->Entry()->Project()->AudioManager()->GetSoundInfo(SoundID); if (SoundInfo.pAudioGroup) mpEventData->AddEvent(CharIndex, SoundInfo.pAudioGroup->ID()); diff --git a/src/Core/Resource/Factory/CUnsupportedParticleLoader.cpp b/src/Core/Resource/Factory/CUnsupportedParticleLoader.cpp index 60c3a957..2913b0f4 100644 --- a/src/Core/Resource/Factory/CUnsupportedParticleLoader.cpp +++ b/src/Core/Resource/Factory/CUnsupportedParticleLoader.cpp @@ -1298,7 +1298,7 @@ void CUnsupportedParticleLoader::ParseSoundFunction(IInputStream& rFile) if (SoundID != 0xFFFF) { - SSoundInfo SoundInfo = CGameProject::ActiveProject()->AudioManager()->GetSoundInfo(SoundID); + SSoundInfo SoundInfo = mpGroup->Entry()->Project()->AudioManager()->GetSoundInfo(SoundID); mpGroup->AddDependency(SoundInfo.pAudioGroup); } diff --git a/src/Core/Scene/CSceneNode.cpp b/src/Core/Scene/CSceneNode.cpp index c4a58c6c..8f4757f5 100644 --- a/src/Core/Scene/CSceneNode.cpp +++ b/src/Core/Scene/CSceneNode.cpp @@ -293,8 +293,6 @@ void CSceneNode::Rotate(const CQuaternion& rkRotation, ETransformSpace Transform void CSceneNode::Rotate(const CQuaternion& rkRotation, const CVector3f& rkPivot, const CQuaternion& rkPivotRotation, ETransformSpace TransformSpace) { - Rotate(rkRotation, TransformSpace); - switch (TransformSpace) { case eWorldTransform: @@ -304,7 +302,7 @@ void CSceneNode::Rotate(const CQuaternion& rkRotation, const CVector3f& rkPivot, mPosition = rkPivot + ((rkPivotRotation * rkRotation * rkPivotRotation.Inverse()) * (mPosition - rkPivot)); break; } - MarkTransformChanged(); + Rotate(rkRotation, TransformSpace); } void CSceneNode::Scale(const CVector3f& rkScale) diff --git a/src/Editor/CEditorApplication.cpp b/src/Editor/CEditorApplication.cpp index cc21e216..284fd76d 100644 --- a/src/Editor/CEditorApplication.cpp +++ b/src/Editor/CEditorApplication.cpp @@ -13,6 +13,7 @@ CEditorApplication::CEditorApplication(int& rArgc, char **ppArgv) : QApplication(rArgc, ppArgv) + , mpActiveProject(nullptr) , mpWorldEditor(nullptr) , mpResourceBrowser(nullptr) , mpProjectDialog(nullptr) @@ -34,9 +35,56 @@ void CEditorApplication::InitEditor() mpWorldEditor = new CWorldEditor(); mpResourceBrowser = new CResourceBrowser(mpWorldEditor); mpProjectDialog = new CProjectOverviewDialog(); - connect(mpProjectDialog, SIGNAL(ActiveProjectChanged(CGameProject*)), mpResourceBrowser, SLOT(UpdateStore())); + mpWorldEditor->showMaximized(); +} - mpProjectDialog->show(); +bool CEditorApplication::CloseProject() +{ + if (mpActiveProject) + { + // Close active editor windows. todo: check for unsaved changes + foreach (IEditor *pEditor, mEditorWindows) + { + if (pEditor != mpWorldEditor && !pEditor->close()) + return false; + } + + // Close world + if (!mpWorldEditor->CloseWorld()) + return false; + + mpResourceBrowser->close(); + mpProjectDialog->close(); + + delete mpActiveProject; + mpActiveProject = nullptr; + emit ActiveProjectChanged(nullptr); + } + + return true; +} + +bool CEditorApplication::OpenProject(const QString& rkProjPath) +{ + // Close existing project + if (!CloseProject()) + return false; + + // Load new project + TWideString Path = TO_TWIDESTRING(rkProjPath); + mpActiveProject = CGameProject::LoadProject(Path); + + if (mpActiveProject) + { + gpResourceStore = mpActiveProject->ResourceStore(); + emit ActiveProjectChanged(mpActiveProject); + return true; + } + else + { + UICommon::ErrorMsg(mpWorldEditor, "Failed to open project! Is it already open in another Prime World Editor instance?"); + return false; + } } void CEditorApplication::EditResource(CResourceEntry *pEntry) @@ -58,7 +106,7 @@ void CEditorApplication::EditResource(CResourceEntry *pEntry) if (!pRes) { - QMessageBox::warning(nullptr, "Error", "Failed to load resource!"); + UICommon::ErrorMsg(mpWorldEditor, "Failed to load resource!"); return; } @@ -82,7 +130,7 @@ void CEditorApplication::EditResource(CResourceEntry *pEntry) mEditingMap[pEntry] = pEd; } else - QMessageBox::information(0, "Unsupported Resource", "This resource type is currently unsupported for editing."); + UICommon::InfoMsg(mpWorldEditor, "Unsupported Resource", "This resource type is currently unsupported for editing."); } } @@ -93,19 +141,20 @@ void CEditorApplication::NotifyAssetsModified() void CEditorApplication::CookAllDirtyPackages() { - CGameProject *pProj = CGameProject::ActiveProject(); + ASSERT(mpActiveProject != nullptr); - for (u32 iPkg = 0; iPkg < pProj->NumPackages(); iPkg++) + for (u32 iPkg = 0; iPkg < mpActiveProject->NumPackages(); iPkg++) { - CPackage *pPackage = pProj->PackageByIndex(iPkg); + CPackage *pPackage = mpActiveProject->PackageByIndex(iPkg); if (pPackage->NeedsRecook()) pPackage->Cook(); } - mpProjectDialog->SetupPackagesList(); + emit PackagesCooked(); } +// ************ SLOTS ************ void CEditorApplication::AddEditor(IEditor *pEditor) { mEditorWindows << pEditor; @@ -149,7 +198,7 @@ void CEditorApplication::OnEditorClose() IEditor *pEditor = qobject_cast(sender()); ASSERT(pEditor); - if (qobject_cast(pEditor) == nullptr) + if (pEditor != mpWorldEditor) { for (auto Iter = mEditingMap.begin(); Iter != mEditingMap.end(); Iter++) { @@ -162,7 +211,7 @@ void CEditorApplication::OnEditorClose() mEditorWindows.removeOne(pEditor); delete pEditor; - } - CGameProject::ActiveProject()->ResourceStore()->DestroyUnreferencedResources(); + mpActiveProject->ResourceStore()->DestroyUnreferencedResources(); + } } diff --git a/src/Editor/CEditorApplication.h b/src/Editor/CEditorApplication.h index d0a8a6bf..cd9551c8 100644 --- a/src/Editor/CEditorApplication.h +++ b/src/Editor/CEditorApplication.h @@ -1,6 +1,7 @@ #ifndef CEDITORAPPLICATION_H #define CEDITORAPPLICATION_H +#include #include #include #include @@ -18,23 +19,28 @@ class CEditorApplication : public QApplication { Q_OBJECT - QTimer mRefreshTimer; + CGameProject *mpActiveProject; CWorldEditor *mpWorldEditor; CResourceBrowser *mpResourceBrowser; CProjectOverviewDialog *mpProjectDialog; QVector mEditorWindows; QMap mEditingMap; + + QTimer mRefreshTimer; double mLastUpdate; public: CEditorApplication(int& rArgc, char **ppArgv); ~CEditorApplication(); void InitEditor(); + bool CloseProject(); + bool OpenProject(const QString& rkProjPath); void EditResource(CResourceEntry *pEntry); void NotifyAssetsModified(); void CookAllDirtyPackages(); // Accessors + inline CGameProject* ActiveProject() const { return mpActiveProject; } inline CWorldEditor* WorldEditor() const { return mpWorldEditor; } inline CResourceBrowser* ResourceBrowser() const { return mpResourceBrowser; } inline CProjectOverviewDialog* ProjectDialog() const { return mpProjectDialog; } @@ -48,7 +54,9 @@ public slots: void OnEditorClose(); signals: + void ActiveProjectChanged(CGameProject *pNewProj); void AssetsModified(); + void PackagesCooked(); }; #define gpEdApp static_cast(qApp) diff --git a/src/Editor/CGridRenderable.h b/src/Editor/CGridRenderable.h index 4d434642..b4d048e6 100644 --- a/src/Editor/CGridRenderable.h +++ b/src/Editor/CGridRenderable.h @@ -7,7 +7,21 @@ // Tiny helper to make sure the grid draws at the correct depth. class CGridRenderable : public IRenderable { + CColor mLineColor; + CColor mBoldLineColor; + public: + CGridRenderable() + : mLineColor(0.6f, 0.6f, 0.6f, 0.f) + , mBoldLineColor(0.f, 0.f, 0.f, 0.f) + {} + + inline void SetColor(const CColor& rkLineColor, const CColor& rkBoldColor) + { + mLineColor = rkLineColor; + mBoldLineColor = rkBoldColor; + } + void AddToRenderer(CRenderer *pRenderer, const SViewInfo&) { pRenderer->AddMesh(this, 0, CAABox::skOne, false, eDrawMesh); @@ -15,7 +29,7 @@ public: void Draw(FRenderOptions, int, ERenderCommand, const SViewInfo&) { - CDrawUtil::DrawGrid(); + CDrawUtil::DrawGrid(mLineColor, mBoldLineColor); } }; diff --git a/src/Editor/CProjectOverviewDialog.cpp b/src/Editor/CProjectOverviewDialog.cpp index 185144e6..70c921f0 100644 --- a/src/Editor/CProjectOverviewDialog.cpp +++ b/src/Editor/CProjectOverviewDialog.cpp @@ -32,35 +32,6 @@ CProjectOverviewDialog::~CProjectOverviewDialog() delete mpUI; } -void CProjectOverviewDialog::InternalLoadProject(const QString& rkPath) -{ - // Load project - TWideString Path = TO_TWIDESTRING(rkPath); - CGameProject *pNewProj = CGameProject::LoadProject(Path); - - if (pNewProj) - { - if (mpProject) delete mpProject; - mpProject = pNewProj; - mpProject->SetActive(); - SetupWorldsList(); - SetupPackagesList(); - emit ActiveProjectChanged(mpProject); - } - - else - { - UICommon::ErrorMsg(this, "Failed to open project! Is it already open in another Prime World Editor instance?"); - } -} - -void CProjectOverviewDialog::OpenProject() -{ - // Open project file - QString ProjPath = UICommon::OpenFileDialog(this, "Open Project", "Game Project (*.prj)"); - if (!ProjPath.isEmpty()) InternalLoadProject(ProjPath); -} - void CProjectOverviewDialog::ExportGame() { QString IsoPath = UICommon::OpenFileDialog(this, "Select ISO", "*.iso *.gcm *.tgc *.wbfs"); @@ -77,14 +48,12 @@ void CProjectOverviewDialog::ExportGame() int OpenChoice = QMessageBox::information(this, "Export complete", "Export finished successfully! Open new project?", QMessageBox::Yes, QMessageBox::No); if (OpenChoice == QMessageBox::Yes) - InternalLoadProject(ExportDialog.ProjectPath()); + gpEdApp->OpenProject(ExportDialog.ProjectPath()); } } void CProjectOverviewDialog::SetupWorldsList() { - ASSERT(mpProject != nullptr && mpProject->IsActive()); - std::list WorldIDs; mpProject->GetWorldList(WorldIDs); mWorldEntries.clear(); @@ -111,7 +80,6 @@ void CProjectOverviewDialog::SetupWorldsList() void CProjectOverviewDialog::SetupPackagesList() { - ASSERT(mpProject != nullptr && mpProject->IsActive()); mpUI->PackagesList->clear(); for (u32 iPkg = 0; iPkg < mpProject->NumPackages(); iPkg++) diff --git a/src/Editor/CProjectOverviewDialog.h b/src/Editor/CProjectOverviewDialog.h index 8ebd4960..f371a6df 100644 --- a/src/Editor/CProjectOverviewDialog.h +++ b/src/Editor/CProjectOverviewDialog.h @@ -24,11 +24,7 @@ public: explicit CProjectOverviewDialog(QWidget *pParent = 0); ~CProjectOverviewDialog(); -protected: - void InternalLoadProject(const QString& rkPath); - public slots: - void OpenProject(); void ExportGame(); void LoadWorld(); void LaunchEditor(); diff --git a/src/Editor/CSceneViewport.cpp b/src/Editor/CSceneViewport.cpp index feb5cdba..136b7b85 100644 --- a/src/Editor/CSceneViewport.cpp +++ b/src/Editor/CSceneViewport.cpp @@ -20,6 +20,7 @@ CSceneViewport::CSceneViewport(QWidget *pParent) , mpContextMenu(nullptr) , mpMenuNode(nullptr) { + mGrid.SetColor(CColor(0.f, 0.f, 0.6f, 0.f), CColor(0.f, 0.f, 1.f, 0.f)); mLinkLine.SetColor(CColor::skYellow); mpRenderer = new CRenderer(); @@ -299,6 +300,7 @@ void CSceneViewport::Paint() { if (!mpScene) return; + mpRenderer->SetClearColor(CColor::skBlack); mpRenderer->BeginFrame(); // todo: The sky should really just be a regular node in the background depth group instead of having special rendering code here @@ -319,6 +321,10 @@ void CSceneViewport::Paint() pGizmo->AddToRenderer(mpRenderer, mViewInfo); } + // Draw grid if the scene is empty + if (!mViewInfo.GameMode && mpScene->ActiveArea() == nullptr) + mGrid.AddToRenderer(mpRenderer, mViewInfo); + // Draw the line for the link the user is editing. if (mLinkLineEnabled) mLinkLine.AddToRenderer(mpRenderer, mViewInfo); diff --git a/src/Editor/CSceneViewport.h b/src/Editor/CSceneViewport.h index ebbbb230..7851e05f 100644 --- a/src/Editor/CSceneViewport.h +++ b/src/Editor/CSceneViewport.h @@ -2,6 +2,7 @@ #define CSCENEVIEWPORT_H #include "CBasicViewport.h" +#include "CGridRenderable.h" #include "CLineRenderable.h" #include "INodeEditor.h" @@ -40,6 +41,9 @@ class CSceneViewport : public CBasicViewport QAction *mpSelectConnectedIncomingAction; QAction *mpSelectConnectedAllAction; + // Grid + CGridRenderable mGrid; + // Link Line bool mLinkLineEnabled; CLineRenderable mLinkLine; diff --git a/src/Editor/PropertyEdit/CPropertyModel.cpp b/src/Editor/PropertyEdit/CPropertyModel.cpp index 31638ada..b7344a7e 100644 --- a/src/Editor/PropertyEdit/CPropertyModel.cpp +++ b/src/Editor/PropertyEdit/CPropertyModel.cpp @@ -297,7 +297,7 @@ QVariant CPropertyModel::data(const QModelIndex& rkIndex, int Role) const u32 SoundID = pSound->Get(); if (SoundID == -1) return "[None]"; - CGameProject *pProj = CGameProject::ActiveProject(); + CGameProject *pProj = pSound->Instance()->Area()->Entry()->Project(); SSoundInfo SoundInfo = pProj->AudioManager()->GetSoundInfo(SoundID); QString Out = QString::number(SoundID); diff --git a/src/Editor/ResourceBrowser/CResourceBrowser.cpp b/src/Editor/ResourceBrowser/CResourceBrowser.cpp index 115534d7..b07ddc32 100644 --- a/src/Editor/ResourceBrowser/CResourceBrowser.cpp +++ b/src/Editor/ResourceBrowser/CResourceBrowser.cpp @@ -69,14 +69,15 @@ CResourceBrowser::CResourceBrowser(QWidget *pParent) QAction *pImportFromContentsTxtAction = new QAction("Import from Pak Contents List", this); pImportNamesMenu->addAction(pImportFromContentsTxtAction); -#if !PUBLIC_RELEASE - QAction *pGenerateAssetNamesAction = new QAction("Generate Asset Names", this); - pImportNamesMenu->addAction(pGenerateAssetNamesAction); -#endif - QAction *pImportFromAssetNameMapAction = new QAction("Import from Asset Name Map", this); pImportNamesMenu->addAction(pImportFromAssetNameMapAction); + QAction *pGenerateAssetNamesAction = new QAction("Generate Asset Names", this); + pImportNamesMenu->addAction(pGenerateAssetNamesAction); +#if !PUBLIC_RELEASE + pGenerateAssetNamesAction->setVisible(false); +#endif + // Set up connections connect(mpUI->StoreComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateStore())); connect(mpUI->SearchBar, SIGNAL(textChanged(QString)), this, SLOT(OnSearchStringChanged())); @@ -87,13 +88,11 @@ CResourceBrowser::CResourceBrowser(QWidget *pParent) connect(mpUI->ResourceTableView->selectionModel(), SIGNAL(currentChanged(QModelIndex,QModelIndex)), this, SLOT(OnResourceSelectionChanged(QModelIndex, QModelIndex))); connect(pImportFromContentsTxtAction, SIGNAL(triggered()), this, SLOT(OnImportPakContentsTxt())); connect(pImportFromAssetNameMapAction, SIGNAL(triggered()), this, SLOT(OnImportNamesFromAssetNameMap())); + connect(pGenerateAssetNamesAction, SIGNAL(triggered()), this, SLOT(OnGenerateAssetNames())); connect(mpUI->ExportNamesButton, SIGNAL(clicked()), this, SLOT(ExportAssetNames())); connect(&mUpdateFilterTimer, SIGNAL(timeout()), this, SLOT(UpdateFilter())); connect(mpFilterAllBox, SIGNAL(toggled(bool)), this, SLOT(OnFilterTypeBoxTicked(bool))); - -#if !PUBLIC_RELEASE - connect(pGenerateAssetNamesAction, SIGNAL(triggered()), this, SLOT(OnGenerateAssetNames())); -#endif + connect(gpEdApp, SIGNAL(ActiveProjectChanged(CGameProject*)), this, SLOT(UpdateStore())); } CResourceBrowser::~CResourceBrowser() diff --git a/src/Editor/TestDialog.cpp b/src/Editor/TestDialog.cpp index 83e42aed..e6b8b159 100644 --- a/src/Editor/TestDialog.cpp +++ b/src/Editor/TestDialog.cpp @@ -1,5 +1,6 @@ #include "TestDialog.h" #include "ui_TestDialog.h" +#include "CEditorApplication.h" #include TestDialog::TestDialog(QWidget *pParent) @@ -26,7 +27,7 @@ void TestDialog::OnSpinBoxChanged(int NewValue) void TestDialog::OnFind() { u32 SoundID = ui->spinBox->value(); - CGameProject *pProj = CGameProject::ActiveProject(); + CGameProject *pProj = gpEdApp->ActiveProject(); if (pProj) { diff --git a/src/Editor/WorldEditor/CWorldEditor.cpp b/src/Editor/WorldEditor/CWorldEditor.cpp index 7b8625dd..90c4a01a 100644 --- a/src/Editor/WorldEditor/CWorldEditor.cpp +++ b/src/Editor/WorldEditor/CWorldEditor.cpp @@ -17,17 +17,16 @@ #include "Editor/Widgets/WVectorEditor.h" #include "Editor/Undo/UndoCommands.h" +#include #include #include #include -#include -#include #include #include #include #include -#include +#include CWorldEditor::CWorldEditor(QWidget *parent) : INodeEditor(parent) @@ -90,7 +89,25 @@ CWorldEditor::CWorldEditor(QWidget *parent) mpCollisionDialog = new CCollisionRenderSettingsDialog(this, this); + // "Open Recent" menu + mpOpenRecentMenu = new QMenu(this); + ui->ActionOpenRecent->setMenu(mpOpenRecentMenu); + + for (u32 iAct = 0; iAct < mskMaxRecentProjects; iAct++) + { + QAction *pAction = new QAction(this); + pAction->setVisible(false); + connect(pAction, SIGNAL(triggered(bool)), this, SLOT(OpenRecentProject())); + + mpOpenRecentMenu->addAction(pAction); + mRecentProjectsActions[iAct] = pAction; + } + UpdateOpenRecentActions(); + // Connect signals and slots + connect(gpEdApp, SIGNAL(ActiveProjectChanged(CGameProject*)), this, SLOT(OnActiveProjectChanged(CGameProject*))); + connect(gpEdApp->clipboard(), SIGNAL(dataChanged()), this, SLOT(OnClipboardDataModified())); + connect(ui->MainViewport, SIGNAL(ViewportClick(SRayIntersection,QMouseEvent*)), this, SLOT(OnViewportClick(SRayIntersection,QMouseEvent*))); connect(ui->MainViewport, SIGNAL(InputProcessed(SRayIntersection,QMouseEvent*)), this, SLOT(OnViewportInputProcessed(SRayIntersection,QMouseEvent*))); connect(ui->MainViewport, SIGNAL(InputProcessed(SRayIntersection,QMouseEvent*)), this, SLOT(UpdateGizmoUI()) ); @@ -105,10 +122,10 @@ CWorldEditor::CWorldEditor(QWidget *parent) connect(ui->TransformSpinBox, SIGNAL(ValueChanged(CVector3f)), this, SLOT(OnTransformSpinBoxModified(CVector3f))); connect(ui->TransformSpinBox, SIGNAL(EditingDone(CVector3f)), this, SLOT(OnTransformSpinBoxEdited(CVector3f))); connect(ui->CamSpeedSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnCameraSpeedChange(double))); - connect(qApp->clipboard(), SIGNAL(dataChanged()), this, SLOT(OnClipboardDataModified())); connect(&mUndoStack, SIGNAL(indexChanged(int)), this, SLOT(OnUndoStackIndexChanged())); - connect(ui->ActionSave, SIGNAL(triggered()), this, SLOT(Save())); + connect(ui->ActionOpenProject, SIGNAL(triggered()), this, SLOT(OpenProject())); + connect(ui->ActionSave, SIGNAL(triggered()) , this, SLOT(Save())); connect(ui->ActionSaveAndRepack, SIGNAL(triggered()), this, SLOT(SaveAndRepack())); connect(ui->ActionCut, SIGNAL(triggered()), this, SLOT(Cut())); connect(ui->ActionCopy, SIGNAL(triggered()), this, SLOT(Copy())); @@ -172,6 +189,34 @@ void CWorldEditor::closeEvent(QCloseEvent *pEvent) } } +bool CWorldEditor::CloseWorld() +{ + if (CheckUnsavedChanges()) + { + ExitPickMode(); + ClearSelection(); + ui->MainViewport->ResetHover(); + ui->ModifyTabContents->ClearUI(); + ui->InstancesTabContents->SetMaster(nullptr); + + mUndoStack.clear(); + mpCollisionDialog->close(); + mpLinkDialog->close(); + + if (mpPoiDialog) + mpPoiDialog->close(); + + // Clear old area - hack until better world/area loader is implemented + if (mpArea) + mpArea->ClearScriptLayers(); + + mpArea = nullptr; + mpWorld = nullptr; + return true; + } + else return false; +} + void CWorldEditor::SetArea(CWorld *pWorld, CGameArea *pArea) { ExitPickMode(); @@ -188,10 +233,6 @@ void CWorldEditor::SetArea(CWorld *pWorld, CGameArea *pArea) mpPoiDialog = nullptr; } - // Clear old area - hack until better world/area loader is implemented - if ((mpArea) && (pArea != mpArea)) - mpArea->ClearScriptLayers(); - // Load new area mpArea = pArea; mpWorld = pWorld; @@ -355,6 +396,32 @@ void CWorldEditor::Paste() } } +void CWorldEditor::OpenProject() +{ + QString ProjPath = UICommon::OpenFileDialog(this, "Open Project", "Game Project (*.prj)"); + if (!ProjPath.isEmpty()) gpEdApp->OpenProject(ProjPath); +} + +void CWorldEditor::OpenRecentProject() +{ + QAction *pSender = qobject_cast(sender()); + + if (pSender) + { + QSettings Settings; + QStringList RecentProjectsList = Settings.value("WorldEditor/RecentProjectsList").toStringList(); + + int ProjIndex = pSender->data().toInt(); + QString ProjPath = RecentProjectsList[ProjIndex]; + gpEdApp->OpenProject(ProjPath); + } +} + +void CWorldEditor::CloseProject() +{ + gpEdApp->CloseProject(); +} + bool CWorldEditor::Save() { bool SaveAreaSuccess = mpArea->Entry()->Save(); @@ -384,6 +451,22 @@ bool CWorldEditor::SaveAndRepack() return true; } +void CWorldEditor::OnActiveProjectChanged(CGameProject *pProj) +{ + ui->ActionCloseProject->setEnabled( pProj != nullptr ); + if (!pProj) return; + + // Update recent projects list + QSettings Settings; + QStringList RecentProjectsList = Settings.value("WorldEditor/RecentProjectsList").toStringList(); + QString ProjPath = TO_QSTRING(pProj->ProjectPath()); + + RecentProjectsList.removeAll(ProjPath); + RecentProjectsList.prepend(ProjPath); + Settings.setValue("WorldEditor/RecentProjectsList", RecentProjectsList); + UpdateOpenRecentActions(); +} + void CWorldEditor::OnLinksModified(const QList& rkInstances) { foreach (CScriptObject *pInstance, rkInstances) @@ -509,6 +592,27 @@ void CWorldEditor::DeleteSelection() } } +void CWorldEditor::UpdateOpenRecentActions() +{ + QSettings Settings; + QStringList RecentProjectsList = Settings.value("WorldEditor/RecentProjectsList").toStringList(); + + for (int iProj = 0; iProj < mskMaxRecentProjects; iProj++) + { + QAction *pAction = mRecentProjectsActions[iProj]; + + if (iProj < RecentProjectsList.size()) + { + QString ActionText = QString("&%1 %2").arg(iProj).arg(RecentProjectsList[iProj]); + pAction->setText(ActionText); + pAction->setVisible(true); + } + + else + pAction->setVisible(false); + } +} + void CWorldEditor::UpdateStatusBar() { // Would be cool to do more frequent status bar updates with more info. Unfortunately, this causes lag. diff --git a/src/Editor/WorldEditor/CWorldEditor.h b/src/Editor/WorldEditor/CWorldEditor.h index b08fb493..fcabdbf7 100644 --- a/src/Editor/WorldEditor/CWorldEditor.h +++ b/src/Editor/WorldEditor/CWorldEditor.h @@ -34,7 +34,11 @@ class CWorldEditor; class CWorldEditor : public INodeEditor { Q_OBJECT + static const int mskMaxRecentProjects = 10; + Ui::CWorldEditor *ui; + QMenu *mpOpenRecentMenu; + QAction *mRecentProjectsActions[ mskMaxRecentProjects ]; TResPtr mpWorld; TResPtr mpArea; @@ -55,6 +59,7 @@ public: explicit CWorldEditor(QWidget *parent = 0); ~CWorldEditor(); void closeEvent(QCloseEvent *pEvent); + bool CloseWorld(); void SetArea(CWorld *pWorld, CGameArea *pArea); bool CheckUnsavedChanges(); bool HasAnyScriptNodesSelected() const; @@ -76,8 +81,14 @@ public slots: void Cut(); void Copy(); void Paste(); + + void OpenProject(); + void OpenRecentProject(); + void CloseProject(); bool Save(); bool SaveAndRepack(); + + void OnActiveProjectChanged(CGameProject *pProj); void OnLinksModified(const QList& rkInstances); void OnPropertyModified(IProperty *pProp); void SetSelectionActive(bool Active); @@ -85,6 +96,7 @@ public slots: void SetSelectionLayer(CScriptLayer *pLayer); void DeleteSelection(); + void UpdateOpenRecentActions(); void UpdateStatusBar(); void UpdateGizmoUI(); void UpdateSelectionUI(); diff --git a/src/Editor/WorldEditor/CWorldEditor.ui b/src/Editor/WorldEditor/CWorldEditor.ui index ae3e34d6..9e39fb6b 100644 --- a/src/Editor/WorldEditor/CWorldEditor.ui +++ b/src/Editor/WorldEditor/CWorldEditor.ui @@ -415,8 +415,16 @@ File + + + + + + + + @@ -478,26 +486,13 @@ - - - Open - - :/icons/Save.png:/icons/Save.png - Save - - - Ctrl+S - - - - - Open Model Viewer + Save World @@ -814,15 +809,48 @@ Save and Repack - - Ctrl+Shift+S - Collision Render Settings + + + + :/icons/Open_16px.png:/icons/Open_16px.png + + + Open Recent + + + + + + :/icons/Open_16px.png:/icons/Open_16px.png + + + Open Project + + + + + Export Game + + + + + Exit + + + + + false + + + Close Project + + diff --git a/src/Editor/main.cpp b/src/Editor/main.cpp index a1bc6220..1a2d65f7 100644 --- a/src/Editor/main.cpp +++ b/src/Editor/main.cpp @@ -25,6 +25,9 @@ int main(int argc, char *argv[]) // Create application QCoreApplication::setAttribute(Qt::AA_ShareOpenGLContexts); CEditorApplication App(argc, argv); + App.setApplicationName( APP_NAME ); + App.setApplicationVersion( APP_VERSION ); + App.setOrganizationName("Aruki"); App.setWindowIcon(QIcon(":/icons/AppIcon.ico")); // Init log