PrimeWorldEditor/src/Editor/WorldEditor/CWorldEditor.cpp

1358 lines
45 KiB
C++

#include "CWorldEditor.h"
#include "ui_CWorldEditor.h"
#include "CConfirmUnlinkDialog.h"
#include "CLayerEditor.h"
#include "CTemplateMimeData.h"
#include "WCreateTab.h"
#include "WModifyTab.h"
#include "WInstancesTab.h"
#include "Editor/CAboutDialog.h"
#include "Editor/CBasicViewport.h"
#include "Editor/CExportGameDialog.h"
#include "Editor/CNodeCopyMimeData.h"
#include "Editor/CProjectSettingsDialog.h"
#include "Editor/CQuickplayPropertyEditor.h"
#include "Editor/CSelectionIterator.h"
#include "Editor/UICommon.h"
#include "Editor/PropertyEdit/CPropertyView.h"
#include "Editor/ResourceBrowser/CResourceBrowser.h"
#include "Editor/Widgets/WDraggableSpinBox.h"
#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/Resource/Script/NGameList.h>
#include <Core/Scene/CSceneIterator.h>
#include <QButtonGroup>
#include <QClipboard>
#include <QComboBox>
#include <QFontMetrics>
#include <QMessageBox>
#include <QSettings>
#include <QToolButton>
CWorldEditor::CWorldEditor(QWidget *parent)
: INodeEditor(parent)
, ui(new Ui::CWorldEditor)
, mpArea(nullptr)
, mpWorld(nullptr)
, mpLinkDialog(new CLinkDialog(this, this))
, mpGeneratePropertyNamesDialog(new CGeneratePropertyNamesDialog(this))
, mpTweakEditor(new CTweakEditor(this))
, mIsMakingLink(false)
, mpNewLinkSender(nullptr)
, mpNewLinkReceiver(nullptr)
{
debugf("Creating World Editor");
ui->setupUi(this);
UpdateWindowTitle();
mpSelection->SetAllowedNodeTypes(ENodeType::Script | ENodeType::Light);
// Add resource browser to the layout
QVBoxLayout *pLayout = new QVBoxLayout();
pLayout->setContentsMargins(0,0,0,0);
CResourceBrowser *pResourceBrowser = gpEdApp->ResourceBrowser();
pResourceBrowser->setParent(this);
pLayout->addWidget( pResourceBrowser );
ui->ResourceBrowserContainer->setLayout(pLayout);
// Initialize splitter
QList<int> SplitterSizes;
SplitterSizes << width() * 0.25 << width() * 0.53 << width() * 0.22;
ui->splitter->setSizes(SplitterSizes);
// Initialize UI stuff
ResetCamera();
ui->MainViewport->SetScene(this, &mScene);
ui->MainViewport->setAcceptDrops(true);
ui->TransformSpinBox->SetOrientation(Qt::Horizontal);
ui->TransformSpinBox->layout()->setContentsMargins(0,0,0,0);
ui->CamSpeedSpinBox->SetDefaultValue(1.0);
mpTransformCombo->setMinimumWidth(75);
ui->MainToolBar->addActions(mGizmoActions);
ui->MainToolBar->addWidget(mpTransformCombo);
AddUndoActions(ui->menuEdit, ui->ActionCut);
ui->menuEdit->insertSeparator(ui->ActionCut);
// Initialize sidebar
mpCurSidebar = nullptr;
mpRightSidebarLayout = new QVBoxLayout();
mpRightSidebarLayout->setContentsMargins(0, 0, 0, 0);
ui->RightSidebarFrame->setLayout(mpRightSidebarLayout);
mpWorldInfoSidebar = new CWorldInfoSidebar(this);
mpScriptSidebar = new CScriptEditSidebar(this);
mpPoiMapSidebar = new CPoiMapSidebar(this);
// Initialize edit mode toolbar
mpEditModeButtonGroup = new QButtonGroup(this);
connect(mpEditModeButtonGroup, SIGNAL(buttonClicked(int)), this, SLOT(ChangeEditMode(int)));
AddEditModeButton( QIcon(":/icons/World.svg"), "Edit World Info",eWEM_EditWorldInfo );
AddEditModeButton( QIcon(":/icons/Modify.svg"), "Edit Script", eWEM_EditScript );
mpPoiMapAction = AddEditModeButton( QIcon(":/icons/PoiSymbol_24px.svg"), "Edit POI Mappings", eWEM_EditPOIMappings );
mpPoiMapAction->setVisible(false);
ChangeEditMode(eWEM_EditWorldInfo);
// Initialize actions
addAction(ui->ActionIncrementGizmo);
addAction(ui->ActionDecrementGizmo);
AddUndoActions(ui->MainToolBar, ui->ActionLink);
ui->MainToolBar->insertSeparator(ui->ActionLink);
ui->ActionCut->setAutoRepeat(false);
ui->ActionCut->setShortcut(QKeySequence::Cut);
ui->ActionCopy->setAutoRepeat(false);
ui->ActionCopy->setShortcut(QKeySequence::Copy);
ui->ActionPaste->setAutoRepeat(false);
ui->ActionPaste->setShortcut(QKeySequence::Paste);
ui->ActionDelete->setAutoRepeat(false);
ui->ActionDelete->setShortcut(QKeySequence::Delete);
mpCollisionDialog = new CCollisionRenderSettingsDialog(this, this);
// Quickplay buttons
QToolButton* pQuickplayButton = new QToolButton(this);
pQuickplayButton->setIcon( QIcon(":/icons/Play_32px.svg") );
pQuickplayButton->setPopupMode( QToolButton::MenuButtonPopup );
pQuickplayButton->setMenu( new CQuickplayPropertyEditor(mQuickplayParms, this) );
pQuickplayButton->setToolTip( "Quickplay" );
ui->MainToolBar->addSeparator();
mpQuickplayAction = ui->MainToolBar->addWidget(pQuickplayButton);
mpQuickplayAction->setVisible(false);
mpQuickplayAction->setEnabled(false);
connect(pQuickplayButton, SIGNAL(pressed()), this, SLOT(LaunchQuickplay()));
// "Open Recent" menu
mpOpenRecentMenu = new QMenu(this);
ui->ActionOpenRecent->setMenu(mpOpenRecentMenu);
for (uint32 iAct = 0; iAct < mskMaxRecentProjects; iAct++)
{
QAction *pAction = new QAction(this);
pAction->setVisible(false);
pAction->setData((int) iAct);
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()) );
connect(ui->MainViewport, SIGNAL(InputProcessed(SRayIntersection,QMouseEvent*)), this, SLOT(UpdateStatusBar()) );
connect(ui->MainViewport, SIGNAL(InputProcessed(SRayIntersection,QMouseEvent*)), this, SLOT(UpdateCursor()) );
connect(ui->MainViewport, SIGNAL(GizmoMoved()), this, SLOT(OnGizmoMoved()));
connect(ui->MainViewport, SIGNAL(CameraOrbit()), this, SLOT(UpdateCameraOrbit()));
connect(this, SIGNAL(SelectionModified()), this, SLOT(OnSelectionModified()));
connect(this, SIGNAL(SelectionTransformed()), this, SLOT(UpdateCameraOrbit()));
connect(this, SIGNAL(PickModeEntered(QCursor)), this, SLOT(OnPickModeEnter(QCursor)));
connect(this, SIGNAL(PickModeExited()), this, SLOT(OnPickModeExit()));
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(&UndoStack(), 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->ActionExportGame, SIGNAL(triggered()), this, SLOT(ExportGame()));
connect(ui->ActionProjectSettings, SIGNAL(triggered()), this, SLOT(OpenProjectSettings()));
connect(ui->ActionCloseProject, SIGNAL(triggered()), this, SLOT(CloseProject()));
connect(ui->ActionExit, SIGNAL(triggered()), this, SLOT(close()));
connect(ui->ActionCut, SIGNAL(triggered()), this, SLOT(Cut()));
connect(ui->ActionCopy, SIGNAL(triggered()), this, SLOT(Copy()));
connect(ui->ActionPaste, SIGNAL(triggered()), this, SLOT(Paste()));
connect(ui->ActionDelete, SIGNAL(triggered()), this, SLOT(DeleteSelection()));
connect(ui->ActionSelectAll, SIGNAL(triggered()), this, SLOT(SelectAllTriggered()));
connect(ui->ActionInvertSelection, SIGNAL(triggered()), this, SLOT(InvertSelectionTriggered()));
connect(ui->ActionLink, SIGNAL(toggled(bool)), this, SLOT(OnLinkButtonToggled(bool)));
connect(ui->ActionUnlink, SIGNAL(triggered()), this, SLOT(OnUnlinkClicked()));
connect(ui->ActionEditTweaks, SIGNAL(triggered()), mpTweakEditor, SLOT(show()));
connect(ui->ActionEditLayers, SIGNAL(triggered()), this, SLOT(EditLayers()));
if (gTemplatesWritable)
connect(ui->ActionGeneratePropertyNames, SIGNAL(triggered()), mpGeneratePropertyNamesDialog, SLOT(show()));
else
ui->ActionGeneratePropertyNames->setEnabled(false);
connect(ui->ActionDrawWorld, SIGNAL(triggered()), this, SLOT(ToggleDrawWorld()));
connect(ui->ActionDrawObjects, SIGNAL(triggered()), this, SLOT(ToggleDrawObjects()));
connect(ui->ActionDrawCollision, SIGNAL(triggered()), this, SLOT(ToggleDrawCollision()));
connect(ui->ActionDrawObjectCollision, SIGNAL(triggered()), this, SLOT(ToggleDrawObjectCollision()));
connect(ui->ActionDrawLights, SIGNAL(triggered()), this, SLOT(ToggleDrawLights()));
connect(ui->ActionDrawSky, SIGNAL(triggered()), this, SLOT(ToggleDrawSky()));
connect(ui->ActionGameMode, SIGNAL(triggered()), this, SLOT(ToggleGameMode()));
connect(ui->ActionDisableAlpha, SIGNAL(triggered()), this, SLOT(ToggleDisableAlpha()));
connect(ui->ActionNoLighting, SIGNAL(triggered()), this, SLOT(SetNoLighting()));
connect(ui->ActionBasicLighting, SIGNAL(triggered()), this, SLOT(SetBasicLighting()));
connect(ui->ActionWorldLighting, SIGNAL(triggered()), this, SLOT(SetWorldLighting()));
connect(ui->ActionNoBloom, SIGNAL(triggered()), this, SLOT(SetNoBloom()));
connect(ui->ActionBloomMaps, SIGNAL(triggered()), this, SLOT(SetBloomMaps()));
connect(ui->ActionFakeBloom, SIGNAL(triggered()), this, SLOT(SetFakeBloom()));
connect(ui->ActionBloom, SIGNAL(triggered()), this, SLOT(SetBloom()));
connect(ui->ActionIncrementGizmo, SIGNAL(triggered()), this, SLOT(IncrementGizmo()));
connect(ui->ActionDecrementGizmo, SIGNAL(triggered()), this, SLOT(DecrementGizmo()));
connect(ui->ActionCollisionRenderSettings, SIGNAL(triggered()), mpCollisionDialog, SLOT(show()));
connect(ui->ActionAbout, SIGNAL(triggered(bool)), this, SLOT(About()));
}
CWorldEditor::~CWorldEditor()
{
mScene.ClearScene();
mpArea = nullptr;
mpWorld = nullptr;
if (gpResourceStore)
gpResourceStore->DestroyUnreferencedResources(); // this should destroy the area!
delete mpScriptSidebar; // For some reason WCreateTab filters an event during the viewport's destructor
delete ui;
}
bool CWorldEditor::CloseWorld()
{
if (CheckUnsavedChanges())
{
ExitPickMode();
ClearSelection();
ui->MainViewport->ResetHover();
mScene.ClearScene();
UndoStack().clear();
mpCollisionDialog->close();
mpLinkDialog->close();
mpQuickplayAction->setEnabled(false);
mpArea = nullptr;
mpWorld = nullptr;
if (gpResourceStore)
gpResourceStore->DestroyUnreferencedResources(); // this should destroy the area!
UpdateWindowTitle();
ui->ActionSave->setEnabled(false);
ui->ActionSaveAndRepack->setEnabled(false);
ui->ActionEditLayers->setEnabled(false);
emit MapChanged(mpWorld, mpArea);
return true;
}
else return false;
}
bool CWorldEditor::SetArea(CWorld *pWorld, int AreaIndex)
{
if (!CloseWorld())
return false;
ExitPickMode();
ui->MainViewport->ResetHover();
ClearSelection();
UndoStack().clear();
// Load new area
mpWorld = pWorld;
CAssetID AreaID = mpWorld->AreaResourceID(AreaIndex);
CResourceEntry *pAreaEntry = gpResourceStore->FindEntry(AreaID);
ASSERT(pAreaEntry);
mpArea = pAreaEntry->Load();
ASSERT(mpArea);
mpWorld->SetAreaLayerInfo(mpArea);
mScene.SetActiveArea(mpWorld, mpArea);
// Snap camera to new area
CCamera *pCamera = &ui->MainViewport->Camera();
if (pCamera->MoveMode() == ECameraMoveMode::Free)
{
CTransform4f AreaTransform = mpArea->Transform();
CVector3f AreaPosition(AreaTransform[0][3], AreaTransform[1][3], AreaTransform[2][3]);
pCamera->Snap(AreaPosition);
}
UpdateCameraOrbit();
// Update UI stuff
UpdateWindowTitle();
CGameTemplate *pGame = NGameList::GetGameTemplate(mpArea->Game());
mpLinkDialog->SetGame(pGame);
QString AreaName = TO_QSTRING(mpWorld->AreaInGameName(AreaIndex));
if (CurrentGame() < EGame::DKCReturns)
debugf("Loaded area: %s (%s)", *mpArea->Entry()->Name(), *TO_TSTRING(AreaName));
else
debugf("Loaded level: World %s / Area %s (%s)", *mpWorld->Entry()->Name(), *mpArea->Entry()->Name(), *TO_TSTRING(AreaName));
// Update paste action
OnClipboardDataModified();
// Update toolbar actions
ui->ActionSave->setEnabled(true);
ui->ActionSaveAndRepack->setEnabled(true);
ui->ActionEditLayers->setEnabled(true);
mpQuickplayAction->setEnabled(true);
// Emit signals
emit MapChanged(mpWorld, mpArea);
emit LayersModified();
return true;
}
void CWorldEditor::ResetCamera()
{
ui->MainViewport->Camera().Snap(CVector3f(0.f, 5.f, 1.f));
}
bool CWorldEditor::HasAnyScriptNodesSelected() const
{
for (CSelectionIterator It(mpSelection); It; ++It)
{
if (It->NodeType() == ENodeType::Script)
return true;
}
return false;
}
bool CWorldEditor::IsQuickplayEnabled() const
{
return mpQuickplayAction->isVisible() && mpQuickplayAction->isEnabled();
}
CSceneViewport* CWorldEditor::Viewport() const
{
return ui->MainViewport;
}
// ************ PUBLIC SLOTS ************
void CWorldEditor::EditorTick(float)
{
// Update new link line
UpdateNewLinkLine();
}
void CWorldEditor::NotifyNodeAboutToBeDeleted(CSceneNode *pNode)
{
INodeEditor::NotifyNodeAboutToBeDeleted(pNode);
if (ui->MainViewport->HoverNode() == pNode)
ui->MainViewport->ResetHover();
}
bool CWorldEditor::Save()
{
if (!mpArea)
return true;
bool SaveAreaSuccess = mpArea->Entry()->Save();
bool SaveEGMCSuccess = mpArea->PoiToWorldMap() ? mpArea->PoiToWorldMap()->Entry()->Save() : true;
bool SaveWorldSuccess = mpWorld->Entry()->Save();
if (SaveAreaSuccess)
mpArea->ClearExtraDependencies();
if (SaveAreaSuccess || SaveEGMCSuccess || SaveWorldSuccess)
gpEdApp->NotifyAssetsModified();
if (SaveAreaSuccess && SaveEGMCSuccess && SaveWorldSuccess)
{
UndoStack().setClean();
setWindowModified(false);
return true;
}
else
{
UICommon::ErrorMsg(this, "Area failed to save!");
return false;
}
}
void CWorldEditor::Cut()
{
if (!mpSelection->IsEmpty())
{
Copy();
UndoStack().push(new CDeleteSelectionCommand(this, "Cut"));
}
}
void CWorldEditor::Copy()
{
if (!mpSelection->IsEmpty())
{
CNodeCopyMimeData *pMimeData = new CNodeCopyMimeData(this);
qApp->clipboard()->setMimeData(pMimeData);
}
}
void CWorldEditor::Paste()
{
if (const CNodeCopyMimeData *pkMimeData =
qobject_cast<const CNodeCopyMimeData*>(qApp->clipboard()->mimeData()))
{
if (pkMimeData->Game() == CurrentGame())
{
CVector3f PastePoint;
if (ui->MainViewport->underMouse() && !ui->MainViewport->IsMouseInputActive())
PastePoint = ui->MainViewport->HoverPoint();
else
{
CRay Ray = ui->MainViewport->Camera().CastRay(CVector2f(0.f, 0.f));
SRayIntersection Intersect = ui->MainViewport->SceneRayCast(Ray);
if (Intersect.Hit)
PastePoint = Intersect.HitPoint;
else
PastePoint = Ray.PointOnRay(10.f);
}
CPasteNodesCommand *pCmd = new CPasteNodesCommand(this, mpScriptSidebar->CreateTab()->SpawnLayer(), PastePoint);
UndoStack().push(pCmd);
}
}
}
void CWorldEditor::OpenProject()
{
UICommon::OpenProject();
}
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::ExportGame()
{
QString IsoPath = UICommon::OpenFileDialog(this, "Select ISO", "*.iso *.gcm *.tgc *.wbfs");
if (IsoPath.isEmpty()) return;
QString ExportDir = UICommon::OpenDirDialog(this, "Select output export directory");
if (ExportDir.isEmpty()) return;
CExportGameDialog ExportDialog(IsoPath, ExportDir, this);
if (ExportDialog.HasValidDisc()) ExportDialog.exec();
if (ExportDialog.ExportSucceeded())
{
int OpenChoice = QMessageBox::information(this, "Export complete", "Export finished successfully! Open new project?", QMessageBox::Yes, QMessageBox::No);
if (OpenChoice == QMessageBox::Yes)
gpEdApp->OpenProject(ExportDialog.ProjectPath());
}
}
void CWorldEditor:: CloseProject()
{
gpEdApp->CloseProject();
SET_WINDOWTITLE_APPVARS( QString("%APP_FULL_NAME%") );
}
void CWorldEditor::About()
{
CAboutDialog Dialog(this);
Dialog.exec();
}
void CWorldEditor::ChangeEditMode(int Mode)
{
// This function is connected to the edit mode QButtonGroup.
ChangeEditMode((EWorldEditorMode) Mode);
}
void CWorldEditor::ChangeEditMode(EWorldEditorMode Mode)
{
mpEditModeButtonGroup->blockSignals(true);
mpEditModeButtonGroup->button(Mode)->setChecked(true);
mpEditModeButtonGroup->blockSignals(false);
switch (Mode)
{
case eWEM_EditWorldInfo:
SetSidebar(mpWorldInfoSidebar);
break;
case eWEM_EditScript:
SetSidebar(mpScriptSidebar);
break;
case eWEM_EditPOIMappings:
SetSidebar(mpPoiMapSidebar);
break;
default:
ASSERT(false);
break;
}
}
void CWorldEditor::SetRenderingMergedWorld(bool RenderMerged)
{
Viewport()->SetRenderMergedWorld(RenderMerged);
}
void CWorldEditor::OpenProjectSettings()
{
CProjectSettingsDialog *pDialog = gpEdApp->ProjectDialog();
pDialog->show();
pDialog->raise();
}
void CWorldEditor::OnActiveProjectChanged(CGameProject *pProj)
{
ui->ActionProjectSettings->setEnabled( pProj != nullptr );
ui->ActionCloseProject->setEnabled( pProj != nullptr );
mpPoiMapAction->setVisible( pProj != nullptr && pProj->Game() >= EGame::EchoesDemo && pProj->Game() <= EGame::Corruption );
mpQuickplayAction->setVisible( pProj != nullptr && NDolphinIntegration::IsQuickplaySupported(pProj) );
ResetCamera();
UpdateWindowTitle();
// Update tweak editor
// We update this here to ensure we can update the menu item correctly without risking
// that this function runs before the tweak editor has a chance to update its tweak list.
mpTweakEditor->OnProjectChanged(pProj);
ui->ActionEditTweaks->setEnabled( mpTweakEditor->HasTweaks() );
// Default bloom to Fake Bloom for Metroid Prime 3; disable for other games
bool AllowBloom = (CurrentGame() == EGame::CorruptionProto || CurrentGame() == EGame::Corruption);
AllowBloom ? SetFakeBloom() : SetNoBloom();
ui->menuBloom->setEnabled(AllowBloom);
// Update recent projects list
UpdateOpenRecentActions();
// Reset editor mode
ChangeEditMode(eWEM_EditWorldInfo);
}
void CWorldEditor::OnLinksModified(const QList<CScriptObject*>& rkInstances)
{
foreach (CScriptObject *pInstance, rkInstances)
{
CScriptNode *pNode = mScene.NodeForInstance(pInstance);
pNode->LinksModified();
}
if (!rkInstances.isEmpty())
emit InstanceLinksModified(rkInstances);
}
void CWorldEditor::OnPropertyModified(IProperty *pProp)
{
bool ShouldUpdateSelection = false;
for (CSelectionIterator It(mpSelection); It; ++It)
{
CSceneNode* pNode = *It;
if (pNode && pNode->NodeType() == ENodeType::Script)
{
CScriptNode* pScript = static_cast<CScriptNode*>(pNode);
pScript->PropertyModified(pProp);
// If this is the name, update other parts of the UI to reflect the new value.
if ( pProp->Name() == "Name" )
{
UpdateStatusBar();
UpdateSelectionUI();
}
else if (pProp->Name() == "Position" ||
pProp->Name() == "Rotation" ||
pProp->Name() == "Scale")
{
mpSelection->UpdateBounds();
}
// Emit signal so other widgets can react to the property change
emit PropertyModified(pProp, pScript->Instance());
}
// If this is a model/character, then we'll treat this as a modified selection. This is to make sure the selection bounds updates.
if (pProp->Type() == EPropertyType::Asset)
{
CAssetProperty *pAsset = TPropCast<CAssetProperty>(pProp);
const CResTypeFilter& rkFilter = pAsset->GetTypeFilter();
if (rkFilter.Accepts(EResourceType::Model) || rkFilter.Accepts(EResourceType::AnimSet) || rkFilter.Accepts(EResourceType::Character))
ShouldUpdateSelection = true;
}
else if (pProp->Type() == EPropertyType::AnimationSet)
ShouldUpdateSelection = true;
}
if (ShouldUpdateSelection)
{
SelectionModified();
}
}
void CWorldEditor::SetSelectionActive(bool Active)
{
// Gather list of selected objects that actually have Active properties
QVector<CScriptObject*> Objects;
for (CSelectionIterator It(mpSelection); It; ++It)
{
if (It->NodeType() == ENodeType::Script)
{
CScriptNode* pScript = static_cast<CScriptNode*>(*It);
CScriptObject* pInst = pScript->Instance();
Objects << pInst;
}
}
if (!Objects.isEmpty())
{
UndoStack().beginMacro("Toggle Active");
while (!Objects.isEmpty())
{
QVector<CScriptObject*> CommandObjects;
CScriptTemplate* pTemplate = Objects[0]->Template();
CBoolProperty* pActiveProperty = pTemplate->ActiveProperty();
for (int ObjIdx = 0; ObjIdx < Objects.size(); ObjIdx++)
{
if (Objects[ObjIdx]->Template() == pTemplate)
{
CommandObjects << Objects[ObjIdx];
Objects.removeAt(ObjIdx);
ObjIdx--;
}
}
if (pActiveProperty)
{
CPropertyModel* pModel = qobject_cast<CPropertyModel*>(
mpScriptSidebar->ModifyTab()->PropertyView()->model()
);
CEditScriptPropertyCommand* pCommand = new CEditScriptPropertyCommand(
pActiveProperty,
CommandObjects,
pModel
);
pCommand->SaveOldData();
foreach (CScriptObject* pInstance, CommandObjects)
pInstance->SetActive(Active);
pCommand->SaveNewData();
UndoStack().push(pCommand);
}
}
UndoStack().endMacro();
}
}
void CWorldEditor::SetSelectionInstanceNames(const QString& rkNewName, bool IsDone)
{
// todo: this only supports one node at a time because a macro prevents us from merging undo commands
// this is fine right now because this function is only ever called with a selection of one node, but probably want to fix in the future
/*if (mpSelection->Size() == 1 && mpSelection->Front()->NodeType() == eScriptNode)
{
CScriptNode *pNode = static_cast<CScriptNode*>(mpSelection->Front());
CScriptObject *pInst = pNode->Instance();
if (pName)
{
TString NewName = TO_TSTRING(rkNewName);
IPropertyValue *pOld = pName->RawValue()->Clone();
pInst->SetName(NewName);
UndoStack().push(new CEditScriptPropertyCommand(pName, this, pOld, IsDone, "Edit Instance Name"));
}
}*/
}
void CWorldEditor::SetSelectionLayer(CScriptLayer *pLayer)
{
QList<CScriptNode*> ScriptNodes;
for (CSelectionIterator It(mpSelection); It; ++It)
{
if (It->NodeType() == ENodeType::Script)
ScriptNodes << static_cast<CScriptNode*>(*It);
}
if (!ScriptNodes.isEmpty())
UndoStack().push(new CChangeLayerCommand(this, ScriptNodes, pLayer));
}
void CWorldEditor::DeleteSelection()
{
if (HasAnyScriptNodesSelected())
{
CDeleteSelectionCommand *pCmd = new CDeleteSelectionCommand(this);
UndoStack().push(pCmd);
}
}
void CWorldEditor::UpdateOpenRecentActions()
{
QSettings Settings;
QStringList RecentProjectsList = Settings.value("WorldEditor/RecentProjectsList").toStringList();
// Bump the current project to the front
CGameProject *pProj = gpEdApp->ActiveProject();
if (pProj)
{
QString ProjPath = TO_QSTRING(pProj->ProjectPath());
RecentProjectsList.removeAll(ProjPath);
RecentProjectsList.prepend(ProjPath);
}
// Remove projects that don't exist anymore
foreach (const QString& rkProj, RecentProjectsList)
{
if (!FileUtil::Exists( TO_TSTRING(rkProj) ) || rkProj.contains('\\') )
RecentProjectsList.removeAll(rkProj);
}
Settings.setValue("WorldEditor/RecentProjectsList", RecentProjectsList);
// Set up the menu actions
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::UpdateWindowTitle()
{
QString WindowTitle = "%APP_FULL_NAME%";
CGameProject *pProj = gpEdApp->ActiveProject();
if (pProj)
{
WindowTitle += " - " + TO_QSTRING( pProj->Name() );
if (mpWorld)
{
WindowTitle += " - " + TO_QSTRING(mpWorld->InGameName());
if (mpArea && CurrentGame() < EGame::DKCReturns)
WindowTitle += " - " + TO_QSTRING( mpWorld->AreaInGameName(mpArea->WorldIndex()) );
}
}
WindowTitle += "[*]";
SET_WINDOWTITLE_APPVARS(WindowTitle);
}
void CWorldEditor::UpdateStatusBar()
{
// Would be cool to do more frequent status bar updates with more info. Unfortunately, this causes lag.
QString StatusText = "";
if (!mGizmoHovering)
{
if (ui->MainViewport->underMouse())
{
CSceneNode *pHoverNode = ui->MainViewport->HoverNode();
if (pHoverNode && mpSelection->IsAllowedType(pHoverNode))
StatusText = TO_QSTRING(pHoverNode->Name());
}
}
if (ui->statusbar->currentMessage() != StatusText)
ui->statusbar->showMessage(StatusText);
}
void CWorldEditor::UpdateGizmoUI()
{
// Update transform XYZ spin boxes
if (!ui->TransformSpinBox->IsBeingEdited())
{
CVector3f SpinBoxValue = CVector3f::skZero;
// If the gizmo is transforming, use the total transform amount
// Otherwise, use the first selected node transform, or 0 if no selection
if (mShowGizmo)
{
switch (mGizmo.Mode())
{
case CGizmo::EGizmoMode::Translate:
if (mGizmoTransforming && mGizmo.HasTransformed())
SpinBoxValue = mGizmo.TotalTranslation();
else if (!mpSelection->IsEmpty())
SpinBoxValue = mpSelection->Front()->AbsolutePosition();
break;
case CGizmo::EGizmoMode::Rotate:
if (mGizmoTransforming && mGizmo.HasTransformed())
SpinBoxValue = mGizmo.TotalRotation();
else if (!mpSelection->IsEmpty())
SpinBoxValue = mpSelection->Front()->AbsoluteRotation().ToEuler();
break;
case CGizmo::EGizmoMode::Scale:
if (mGizmoTransforming && mGizmo.HasTransformed())
SpinBoxValue = mGizmo.TotalScale();
else if (!mpSelection->IsEmpty())
SpinBoxValue = mpSelection->Front()->AbsoluteScale();
break;
default: break;
}
}
else if (!mpSelection->IsEmpty()) SpinBoxValue = mpSelection->Front()->AbsolutePosition();
ui->TransformSpinBox->blockSignals(true);
ui->TransformSpinBox->SetValue(SpinBoxValue);
ui->TransformSpinBox->blockSignals(false);
}
// Update gizmo
if (!mGizmoTransforming)
{
// Set gizmo transform
if (!mpSelection->IsEmpty())
{
mGizmo.SetPosition(mpSelection->Front()->AbsolutePosition());
mGizmo.SetLocalRotation(mpSelection->Front()->AbsoluteRotation());
}
}
}
void CWorldEditor::UpdateSelectionUI()
{
// Update selection info text
QString SelectionText;
if (mpSelection->Size() == 1)
SelectionText = TO_QSTRING(mpSelection->Front()->Name());
else if (mpSelection->Size() > 1)
SelectionText = QString("%1 objects selected").arg(mpSelection->Size());
QFontMetrics Metrics(ui->SelectionInfoLabel->font());
SelectionText = Metrics.elidedText(SelectionText, Qt::ElideRight, ui->SelectionInfoFrame->width() - 10);
if (ui->SelectionInfoLabel->text() != SelectionText)
ui->SelectionInfoLabel->setText(SelectionText);
// Update gizmo stuff
UpdateGizmoUI();
}
void CWorldEditor::UpdateCursor()
{
if (ui->MainViewport->IsCursorVisible() && !mPickMode)
{
CSceneNode *pHoverNode = ui->MainViewport->HoverNode();
if (ui->MainViewport->IsHoveringGizmo())
ui->MainViewport->SetCursorState(Qt::SizeAllCursor);
else if ((pHoverNode) && mpSelection->IsAllowedType(pHoverNode))
ui->MainViewport->SetCursorState(Qt::PointingHandCursor);
else
ui->MainViewport->SetCursorState(Qt::ArrowCursor);
}
}
void CWorldEditor::UpdateNewLinkLine()
{
// Check if there is a sender+receiver
if (mpLinkDialog->isVisible() && mpLinkDialog->Sender() && mpLinkDialog->Receiver() && !mpLinkDialog->IsPicking())
{
CVector3f Start = mScene.NodeForInstance(mpLinkDialog->Sender())->CenterPoint();
CVector3f End = mScene.NodeForInstance(mpLinkDialog->Receiver())->CenterPoint();
ui->MainViewport->SetLinkLineEnabled(true);
ui->MainViewport->SetLinkLine(Start, End);
}
// Otherwise check whether there's just a sender or just a receiver
else
{
CScriptObject *pSender = nullptr;
CScriptObject *pReceiver = nullptr;
if (mpLinkDialog->isVisible())
{
if (mpLinkDialog->Sender() && !mpLinkDialog->IsPickingSender())
pSender = mpLinkDialog->Sender();
if (mpLinkDialog->Receiver() && !mpLinkDialog->IsPickingReceiver())
pReceiver = mpLinkDialog->Receiver();
}
else if (mIsMakingLink && mpNewLinkSender)
pSender = mpNewLinkSender;
else if (mpScriptSidebar->ModifyTab()->IsPicking() && mpScriptSidebar->ModifyTab()->EditNode()->NodeType() == ENodeType::Script)
pSender = static_cast<CScriptNode*>(mpScriptSidebar->ModifyTab()->EditNode())->Instance();
// No sender and no receiver = no line
if (!pSender && !pReceiver)
ui->MainViewport->SetLinkLineEnabled(false);
// Yes sender and yes receiver = yes line
else if (pSender && pReceiver)
{
ui->MainViewport->SetLinkLineEnabled(true);
ui->MainViewport->SetLinkLine( mScene.NodeForInstance(pSender)->CenterPoint(), mScene.NodeForInstance(pReceiver)->CenterPoint() );
}
// Compensate for missing sender or missing receiver
else
{
bool IsPicking = (mIsMakingLink || mpLinkDialog->IsPicking() || mpScriptSidebar->ModifyTab()->IsPicking());
if (ui->MainViewport->underMouse() && !ui->MainViewport->IsMouseInputActive() && IsPicking)
{
CSceneNode *pHoverNode = ui->MainViewport->HoverNode();
CScriptObject *pInst = (pSender ? pSender : pReceiver);
CVector3f Start = mScene.NodeForInstance(pInst)->CenterPoint();
CVector3f End = (pHoverNode && pHoverNode->NodeType() == ENodeType::Script ? pHoverNode->CenterPoint() : ui->MainViewport->HoverPoint());
ui->MainViewport->SetLinkLineEnabled(true);
ui->MainViewport->SetLinkLine(Start, End);
}
else
ui->MainViewport->SetLinkLineEnabled(false);
}
}
}
void CWorldEditor::LaunchQuickplay()
{
CVector3f CameraPosition = Viewport()->Camera().Position();
LaunchQuickplayFromLocation(CameraPosition, false);
}
void CWorldEditor::LaunchQuickplayFromLocation(CVector3f Location, bool ForceAsSpawnPosition)
{
// This function should not be called if a level is not open in a project.
ASSERT( gpEdApp->ActiveProject() != nullptr );
ASSERT( mpWorld && mpArea );
// Fill in parameters and start running
SQuickplayParameters Parameters = mQuickplayParms;
Parameters.BootWorldAssetID = mpWorld->ID().ToLong();
Parameters.BootAreaAssetID = mpArea->ID().ToLong();
Parameters.SpawnTransform = Viewport()->Camera().GetCameraTransform();
Parameters.SpawnTransform.SetTranslation(Location);
if (ForceAsSpawnPosition)
{
Parameters.Features.SetFlag(EQuickplayFeature::JumpToArea);
Parameters.Features.SetFlag(EQuickplayFeature::SetSpawnPosition);
}
NDolphinIntegration::LaunchQuickplay(this, gpEdApp->ActiveProject(), Parameters);
}
// ************ PROTECTED ************
QAction* CWorldEditor::AddEditModeButton(QIcon Icon, QString ToolTip, EWorldEditorMode Mode)
{
ASSERT(mpEditModeButtonGroup->button(Mode) == nullptr);
QPushButton *pButton = new QPushButton(Icon, "", this);
pButton->setCheckable(true);
pButton->setToolTip(ToolTip);
pButton->setIconSize(QSize(24, 24));
QAction *pAction = ui->EditModeToolBar->addWidget(pButton);
mpEditModeButtonGroup->addButton(pButton, Mode);
return pAction;
}
void CWorldEditor::SetSidebar(CWorldEditorSidebar *pSidebar)
{
if (mpCurSidebar == pSidebar)
return;
if (mpCurSidebar)
{
mpCurSidebar->SidebarClose();
mpRightSidebarLayout->removeWidget(mpCurSidebar);
mpCurSidebar->setHidden(true);
}
mpCurSidebar = pSidebar;
if (mpCurSidebar)
{
mpCurSidebar->SidebarOpen();
mpRightSidebarLayout->addWidget(mpCurSidebar);
mpCurSidebar->setHidden(false);
}
}
void CWorldEditor::GizmoModeChanged(CGizmo::EGizmoMode mode)
{
ui->TransformSpinBox->SetSingleStep( (mode == CGizmo::EGizmoMode::Rotate ? 1.0 : 0.1) );
ui->TransformSpinBox->SetDefaultValue( (mode == CGizmo::EGizmoMode::Scale ? 1.0 : 0.0) );
}
// ************ PRIVATE SLOTS ************
void CWorldEditor::OnClipboardDataModified()
{
const QMimeData *pkClipboardMimeData = qApp->clipboard()->mimeData();
const CNodeCopyMimeData *pkMimeData = qobject_cast<const CNodeCopyMimeData*>(pkClipboardMimeData);
bool ValidMimeData = (pkMimeData && pkMimeData->Game() == CurrentGame());
ui->ActionPaste->setEnabled(ValidMimeData);
}
void CWorldEditor::OnSelectionModified()
{
ui->TransformSpinBox->setEnabled(!mpSelection->IsEmpty());
bool HasScriptNode = HasAnyScriptNodesSelected();
ui->ActionCut->setEnabled(HasScriptNode);
ui->ActionCopy->setEnabled(HasScriptNode);
ui->ActionDelete->setEnabled(HasScriptNode);
UpdateCameraOrbit();
}
void CWorldEditor::OnLinkButtonToggled(bool Enabled)
{
if (Enabled)
{
EnterPickMode(ENodeType::Script, true, false, false);
connect(this, SIGNAL(PickModeClick(SRayIntersection,QMouseEvent*)), this, SLOT(OnLinkClick(SRayIntersection)));
connect(this, SIGNAL(PickModeExited()), this, SLOT(OnLinkEnd()));
mIsMakingLink = true;
mpNewLinkSender = nullptr;
mpNewLinkReceiver = nullptr;
}
else
{
if (mIsMakingLink)
ExitPickMode();
}
}
void CWorldEditor::OnLinkClick(const SRayIntersection& rkIntersect)
{
if (!mpNewLinkSender)
{
mpNewLinkSender = static_cast<CScriptNode*>(rkIntersect.pNode)->Instance();
}
else
{
mpNewLinkReceiver = static_cast<CScriptNode*>(rkIntersect.pNode)->Instance();
mpLinkDialog->NewLink(mpNewLinkSender, mpNewLinkReceiver);
mpLinkDialog->show();
ExitPickMode();
}
}
void CWorldEditor::OnLinkEnd()
{
disconnect(this, SIGNAL(PickModeClick(SRayIntersection,QMouseEvent*)), this, SLOT(OnLinkClick(SRayIntersection)));
disconnect(this, SIGNAL(PickModeExited()), this, SLOT(OnLinkEnd()));
ui->ActionLink->setChecked(false);
mIsMakingLink = false;
mpNewLinkSender = nullptr;
mpNewLinkReceiver = nullptr;
}
void CWorldEditor::OnUnlinkClicked()
{
QList<CScriptNode*> SelectedScriptNodes;
for (CSelectionIterator It(mpSelection); It; ++It)
{
if (It->NodeType() == ENodeType::Script)
SelectedScriptNodes << static_cast<CScriptNode*>(*It);
}
if (!SelectedScriptNodes.isEmpty())
{
CConfirmUnlinkDialog Dialog(this);
Dialog.exec();
if (Dialog.UserChoice() != CConfirmUnlinkDialog::EChoice::Cancel)
{
UndoStack().beginMacro("Unlink");
bool UnlinkIncoming = (Dialog.UserChoice() != CConfirmUnlinkDialog::EChoice::OutgoingOnly);
bool UnlinkOutgoing = (Dialog.UserChoice() != CConfirmUnlinkDialog::EChoice::IncomingOnly);
foreach (CScriptNode *pNode, SelectedScriptNodes)
{
CScriptObject *pInst = pNode->Instance();
if (UnlinkIncoming)
{
QVector<uint32> LinkIndices;
for (uint32 iLink = 0; iLink < pInst->NumLinks(ELinkType::Incoming); iLink++)
LinkIndices << iLink;
CDeleteLinksCommand *pCmd = new CDeleteLinksCommand(this, pInst, ELinkType::Incoming, LinkIndices);
UndoStack().push(pCmd);
}
if (UnlinkOutgoing)
{
QVector<uint32> LinkIndices;
for (uint32 iLink = 0; iLink < pInst->NumLinks(ELinkType::Outgoing); iLink++)
LinkIndices << iLink;
CDeleteLinksCommand *pCmd = new CDeleteLinksCommand(this, pInst, ELinkType::Outgoing, LinkIndices);
UndoStack().push(pCmd);
}
}
UndoStack().endMacro();
}
}
}
void CWorldEditor::OnPickModeEnter(QCursor Cursor)
{
ui->MainViewport->SetCursorState(Cursor);
}
void CWorldEditor::OnPickModeExit()
{
UpdateCursor();
}
void CWorldEditor::UpdateCameraOrbit()
{
CCamera *pCamera = &ui->MainViewport->Camera();
if (!mpSelection->IsEmpty())
pCamera->SetOrbit(mpSelection->Bounds());
else if (mpArea)
pCamera->SetOrbit(mpArea->AABox(), 1.2f);
else
pCamera->ResetOrbit();
}
void CWorldEditor::OnCameraSpeedChange(double Speed)
{
static const double skDefaultSpeed = 1.0;
ui->MainViewport->Camera().SetMoveSpeed(skDefaultSpeed * Speed);
ui->CamSpeedSpinBox->blockSignals(true);
ui->CamSpeedSpinBox->setValue(Speed);
ui->CamSpeedSpinBox->blockSignals(false);
}
void CWorldEditor::OnTransformSpinBoxModified(CVector3f Value)
{
if (mpSelection->IsEmpty()) return;
switch (mGizmo.Mode())
{
// Use absolute position/rotation, but relative scale. (This way spinbox doesn't show preview multiplier)
case CGizmo::EGizmoMode::Translate:
{
CVector3f Delta = Value - mpSelection->Front()->AbsolutePosition();
UndoStack().push(new CTranslateNodeCommand(this, mpSelection->SelectedNodeList(), Delta, mTranslateSpace));
break;
}
case CGizmo::EGizmoMode::Rotate:
{
CQuaternion Delta = CQuaternion::FromEuler(Value) * mpSelection->Front()->AbsoluteRotation().Inverse();
UndoStack().push(new CRotateNodeCommand(this, mpSelection->SelectedNodeList(), true, mGizmo.Position(), mGizmo.Rotation(), Delta, mRotateSpace));
break;
}
case CGizmo::EGizmoMode::Scale:
{
CVector3f Delta = Value / mpSelection->Front()->AbsoluteScale();
UndoStack().push(new CScaleNodeCommand(this, mpSelection->SelectedNodeList(), true, mGizmo.Position(), Delta));
break;
}
default: break;
}
UpdateGizmoUI();
}
void CWorldEditor::OnTransformSpinBoxEdited(CVector3f)
{
if (mpSelection->IsEmpty()) return;
if (mGizmo.Mode() == CGizmo::EGizmoMode::Translate) UndoStack().push(CTranslateNodeCommand::End());
else if (mGizmo.Mode() == CGizmo::EGizmoMode::Rotate) UndoStack().push(CRotateNodeCommand::End());
else if (mGizmo.Mode() == CGizmo::EGizmoMode::Scale) UndoStack().push(CScaleNodeCommand::End());
UpdateGizmoUI();
}
void CWorldEditor::SelectAllTriggered()
{
FNodeFlags NodeFlags = CScene::NodeFlagsForShowFlags(ui->MainViewport->ShowFlags());
NodeFlags &= ~(ENodeType::Model | ENodeType::Static | ENodeType::Collision);
SelectAll(NodeFlags);
}
void CWorldEditor::InvertSelectionTriggered()
{
FNodeFlags NodeFlags = CScene::NodeFlagsForShowFlags(ui->MainViewport->ShowFlags());
NodeFlags &= ~(ENodeType::Model | ENodeType::Static | ENodeType::Collision);
InvertSelection(NodeFlags);
}
void CWorldEditor::ToggleDrawWorld()
{
ui->MainViewport->SetShowWorld(ui->ActionDrawWorld->isChecked());
}
void CWorldEditor::ToggleDrawObjects()
{
ui->MainViewport->SetShowFlag(EShowFlag::ObjectGeometry, ui->ActionDrawObjects->isChecked());
}
void CWorldEditor::ToggleDrawCollision()
{
ui->MainViewport->SetShowFlag(EShowFlag::WorldCollision, ui->ActionDrawCollision->isChecked());
}
void CWorldEditor::ToggleDrawObjectCollision()
{
ui->MainViewport->SetShowFlag(EShowFlag::ObjectCollision, ui->ActionDrawObjectCollision->isChecked());
}
void CWorldEditor::ToggleDrawLights()
{
ui->MainViewport->SetShowFlag(EShowFlag::Lights, ui->ActionDrawLights->isChecked());
}
void CWorldEditor::ToggleDrawSky()
{
ui->MainViewport->SetShowFlag(EShowFlag::Sky, ui->ActionDrawSky->isChecked());
}
void CWorldEditor::ToggleGameMode()
{
ui->MainViewport->SetGameMode(ui->ActionGameMode->isChecked());
}
void CWorldEditor::ToggleDisableAlpha()
{
ui->MainViewport->Renderer()->ToggleAlphaDisabled(ui->ActionDisableAlpha->isChecked());
}
void CWorldEditor::SetNoLighting()
{
CGraphics::sLightMode = CGraphics::ELightingMode::None;
ui->ActionNoLighting->setChecked(true);
ui->ActionBasicLighting->setChecked(false);
ui->ActionWorldLighting->setChecked(false);
}
void CWorldEditor::SetBasicLighting()
{
CGraphics::sLightMode = CGraphics::ELightingMode::Basic;
ui->ActionNoLighting->setChecked(false);
ui->ActionBasicLighting->setChecked(true);
ui->ActionWorldLighting->setChecked(false);
}
void CWorldEditor::SetWorldLighting()
{
CGraphics::sLightMode = CGraphics::ELightingMode::World;
ui->ActionNoLighting->setChecked(false);
ui->ActionBasicLighting->setChecked(false);
ui->ActionWorldLighting->setChecked(true);
}
void CWorldEditor::SetNoBloom()
{
ui->MainViewport->Renderer()->SetBloom(EBloomMode::NoBloom);
ui->ActionNoBloom->setChecked(true);
ui->ActionBloomMaps->setChecked(false);
ui->ActionFakeBloom->setChecked(false);
ui->ActionBloom->setChecked(false);
}
void CWorldEditor::SetBloomMaps()
{
ui->MainViewport->Renderer()->SetBloom(EBloomMode::BloomMaps);
ui->ActionNoBloom->setChecked(false);
ui->ActionBloomMaps->setChecked(true);
ui->ActionFakeBloom->setChecked(false);
ui->ActionBloom->setChecked(false);
}
void CWorldEditor::SetFakeBloom()
{
ui->MainViewport->Renderer()->SetBloom(EBloomMode::FakeBloom);
ui->ActionNoBloom->setChecked(false);
ui->ActionBloomMaps->setChecked(false);
ui->ActionFakeBloom->setChecked(true);
ui->ActionBloom->setChecked(false);
}
void CWorldEditor::SetBloom()
{
ui->MainViewport->Renderer()->SetBloom(EBloomMode::Bloom);
ui->ActionNoBloom->setChecked(false);
ui->ActionBloomMaps->setChecked(false);
ui->ActionFakeBloom->setChecked(false);
ui->ActionBloom->setChecked(true);
}
void CWorldEditor::IncrementGizmo()
{
mGizmo.IncrementSize();
}
void CWorldEditor::DecrementGizmo()
{
mGizmo.DecrementSize();
}
void CWorldEditor::EditLayers()
{
// Launch layer editor
CLayerEditor Editor(this);
Editor.SetArea(mpArea);
Editor.exec();
}