Initial work towards making the World Editor the main application window

This commit is contained in:
Aruki 2017-02-11 18:35:33 -07:00
parent 568cd67994
commit 9928a599be
25 changed files with 323 additions and 136 deletions

View File

@ -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)
{

View File

@ -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;
}

View File

@ -3,18 +3,13 @@
#include "Core/Resource/Script/CMasterTemplate.h"
#include <Common/Serialization/XML.h>
CGameProject *CGameProject::mspActiveProject = nullptr;
CGameProject::~CGameProject()
{
if (mpResourceStore)
{
ASSERT(!mpResourceStore->IsDirty());
}
if (IsActive())
{
mspActiveProject = nullptr;
if (gpResourceStore == mpResourceStore)
gpResourceStore = nullptr;
}
@ -99,15 +94,6 @@ void CGameProject::Serialize(IArchive& rArc)
}
}
void CGameProject::SetActive()
{
if (mspActiveProject != this)
{
mspActiveProject = this;
gpResourceStore = mpResourceStore;
}
}
void CGameProject::GetWorldList(std::list<CAssetID>& rOut) const
{
for (u32 iPkg = 0; iPkg < mPackages.size(); iPkg++)

View File

@ -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<CAssetID>& 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

View File

@ -497,3 +497,8 @@ void CResourceEntry::RemoveFromProject()
Log::Error("RemoveFromProject called on transient resource entry: " + CookedAssetPath(true));
}
}
CGameProject* CResourceEntry::Project() const
{
return mpStore->Project();
}

View File

@ -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); }

View File

@ -41,7 +41,7 @@ TResPtr<CTexture> 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);
}

View File

@ -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);

View File

@ -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());

View File

@ -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);
}

View File

@ -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)

View File

@ -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<IEditor*>(sender());
ASSERT(pEditor);
if (qobject_cast<CWorldEditor*>(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();
}
}

View File

@ -1,6 +1,7 @@
#ifndef CEDITORAPPLICATION_H
#define CEDITORAPPLICATION_H
#include <Core/GameProject/CGameProject.h>
#include <QApplication>
#include <QTimer>
#include <QVector>
@ -18,23 +19,28 @@ class CEditorApplication : public QApplication
{
Q_OBJECT
QTimer mRefreshTimer;
CGameProject *mpActiveProject;
CWorldEditor *mpWorldEditor;
CResourceBrowser *mpResourceBrowser;
CProjectOverviewDialog *mpProjectDialog;
QVector<IEditor*> mEditorWindows;
QMap<CResourceEntry*,IEditor*> 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<CEditorApplication*>(qApp)

View File

@ -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);
}
};

View File

@ -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<CAssetID> 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++)

View File

@ -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();

View File

@ -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);

View File

@ -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;

View File

@ -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);

View File

@ -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()

View File

@ -1,5 +1,6 @@
#include "TestDialog.h"
#include "ui_TestDialog.h"
#include "CEditorApplication.h"
#include <Core/GameProject/CGameProject.h>
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)
{

View File

@ -17,17 +17,16 @@
#include "Editor/Widgets/WVectorEditor.h"
#include "Editor/Undo/UndoCommands.h"
#include <Common/Log.h>
#include <Core/GameProject/CGameProject.h>
#include <Core/Render/CDrawUtil.h>
#include <Core/Scene/CSceneIterator.h>
#include <Common/Log.h>
#include <iostream>
#include <QClipboard>
#include <QComboBox>
#include <QFontMetrics>
#include <QMessageBox>
#include <QOpenGLContext>
#include <QSettings>
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,9 +122,9 @@ 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->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()));
@ -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<QAction*>(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<CScriptObject*>& 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.

View File

@ -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<CWorld> mpWorld;
TResPtr<CGameArea> 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<CScriptObject*>& 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();

View File

@ -415,8 +415,16 @@
<property name="title">
<string>File</string>
</property>
<addaction name="ActionOpenProject"/>
<addaction name="ActionOpenRecent"/>
<addaction name="separator"/>
<addaction name="ActionSave"/>
<addaction name="ActionSaveAndRepack"/>
<addaction name="separator"/>
<addaction name="ActionExportGame"/>
<addaction name="separator"/>
<addaction name="ActionCloseProject"/>
<addaction name="ActionExit"/>
</widget>
<widget class="QMenu" name="menuEdit">
<property name="title">
@ -478,26 +486,13 @@
<addaction name="menuTools"/>
<addaction name="menuView"/>
</widget>
<action name="ActionOpen">
<property name="text">
<string>Open</string>
</property>
</action>
<action name="ActionSave">
<property name="icon">
<iconset resource="../Icons.qrc">
<normaloff>:/icons/Save.png</normaloff>:/icons/Save.png</iconset>
</property>
<property name="text">
<string>Save</string>
</property>
<property name="shortcut">
<string>Ctrl+S</string>
</property>
</action>
<action name="actionOpen_model_viewer">
<property name="text">
<string>Open Model Viewer</string>
<string>Save World</string>
</property>
</action>
<action name="ActionLink">
@ -814,15 +809,48 @@
<property name="toolTip">
<string>Save and Repack</string>
</property>
<property name="shortcut">
<string>Ctrl+Shift+S</string>
</property>
</action>
<action name="ActionCollisionRenderSettings">
<property name="text">
<string>Collision Render Settings</string>
</property>
</action>
<action name="ActionOpenRecent">
<property name="icon">
<iconset resource="../Icons.qrc">
<normaloff>:/icons/Open_16px.png</normaloff>:/icons/Open_16px.png</iconset>
</property>
<property name="text">
<string>Open Recent</string>
</property>
</action>
<action name="ActionOpenProject">
<property name="icon">
<iconset resource="../Icons.qrc">
<normaloff>:/icons/Open_16px.png</normaloff>:/icons/Open_16px.png</iconset>
</property>
<property name="text">
<string>Open Project</string>
</property>
</action>
<action name="ActionExportGame">
<property name="text">
<string>Export Game</string>
</property>
</action>
<action name="ActionExit">
<property name="text">
<string>Exit</string>
</property>
</action>
<action name="ActionCloseProject">
<property name="enabled">
<bool>false</bool>
</property>
<property name="text">
<string>Close Project</string>
</property>
</action>
</widget>
<customwidgets>
<customwidget>

View File

@ -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