2015-07-26 21:39:49 +00:00
|
|
|
#include "CWorldEditor.h"
|
|
|
|
#include "ui_CWorldEditor.h"
|
|
|
|
#include "CEditorGLWidget.h"
|
|
|
|
#include <gtc/matrix_transform.hpp>
|
|
|
|
#include <Core/CDrawUtil.h>
|
|
|
|
#include <iostream>
|
|
|
|
#include <QOpenGLContext>
|
|
|
|
#include <QFontMetrics>
|
2015-08-20 01:01:58 +00:00
|
|
|
#include <QComboBox>
|
2015-07-26 21:39:49 +00:00
|
|
|
#include <Core/Log.h>
|
2015-07-29 13:51:59 +00:00
|
|
|
#include "WDraggableSpinBox.h"
|
2015-07-26 21:39:49 +00:00
|
|
|
|
|
|
|
#include "WorldEditor/CLayerEditor.h"
|
|
|
|
#include "WorldEditor/WModifyTab.h"
|
|
|
|
#include "WorldEditor/WInstancesTab.h"
|
|
|
|
|
|
|
|
CWorldEditor::CWorldEditor(QWidget *parent) :
|
|
|
|
QMainWindow(parent),
|
|
|
|
ui(new Ui::CWorldEditor)
|
|
|
|
{
|
|
|
|
Log::Write("Creating World Editor");
|
|
|
|
ui->setupUi(this);
|
|
|
|
|
|
|
|
mpRenderer = new CRenderer();
|
|
|
|
mpRenderer->SetClearColor(CColor::skBlack);
|
|
|
|
QSize ViewSize = ui->MainViewport->size();
|
|
|
|
mpRenderer->SetViewportSize(ViewSize.width(), ViewSize.height());
|
|
|
|
|
|
|
|
mpSceneManager = new CSceneManager();
|
|
|
|
|
|
|
|
mpArea = nullptr;
|
|
|
|
mpWorld = nullptr;
|
|
|
|
mpHoverNode = nullptr;
|
|
|
|
mDrawSky = true;
|
2015-08-16 04:29:37 +00:00
|
|
|
mShowGizmo = false;
|
2015-08-20 01:01:58 +00:00
|
|
|
mGizmoHovering = false;
|
|
|
|
mGizmoTransforming = false;
|
2015-08-24 01:02:14 +00:00
|
|
|
mGizmoUIOutdated = true;
|
2015-07-26 21:39:49 +00:00
|
|
|
|
|
|
|
mFrameCount = 0;
|
|
|
|
mFPSTimer.Start();
|
|
|
|
|
|
|
|
// Create blank title bar with some space to allow for dragging the dock
|
|
|
|
QWidget *pOldTitleBar = ui->MainDock->titleBarWidget();
|
|
|
|
|
|
|
|
QWidget *pNewTitleBar = new QWidget(ui->MainDock);
|
|
|
|
QVBoxLayout *pTitleLayout = new QVBoxLayout(pNewTitleBar);
|
|
|
|
pTitleLayout->setSpacing(10);
|
|
|
|
pNewTitleBar->setLayout(pTitleLayout);
|
|
|
|
ui->MainDock->setTitleBarWidget(pNewTitleBar);
|
|
|
|
|
|
|
|
delete pOldTitleBar;
|
|
|
|
|
2015-07-29 13:51:59 +00:00
|
|
|
// Initialize UI stuff
|
2015-07-26 21:39:49 +00:00
|
|
|
ui->ModifyTabContents->SetEditor(this);
|
|
|
|
ui->InstancesTabContents->SetEditor(this, mpSceneManager);
|
|
|
|
ui->MainDock->installEventFilter(this);
|
2015-07-29 13:51:59 +00:00
|
|
|
ui->CamSpeedSpinBox->SetDefaultValue(1.0);
|
|
|
|
ResetHover();
|
|
|
|
|
2015-08-20 01:01:58 +00:00
|
|
|
mTransformSpace = eWorldTransform;
|
|
|
|
|
|
|
|
QComboBox *pTransformCombo = new QComboBox(this);
|
|
|
|
pTransformCombo->setMinimumWidth(75);
|
|
|
|
pTransformCombo->addItem("World");
|
|
|
|
pTransformCombo->addItem("Local");
|
|
|
|
ui->MainToolBar->insertWidget(0, pTransformCombo);
|
|
|
|
|
2015-08-16 04:29:37 +00:00
|
|
|
// Initialize offscreen actions
|
|
|
|
addAction(ui->ActionIncrementGizmo);
|
|
|
|
addAction(ui->ActionDecrementGizmo);
|
|
|
|
|
2015-07-29 13:51:59 +00:00
|
|
|
// Connect signals and slots
|
2015-08-20 01:01:58 +00:00
|
|
|
connect(pTransformCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(SetTransformSpace(int)));
|
2015-07-29 13:51:59 +00:00
|
|
|
connect(ui->CamSpeedSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnCameraSpeedChange(double)));
|
2015-07-26 21:39:49 +00:00
|
|
|
connect(ui->MainViewport, SIGNAL(PreRender()), this, SLOT(ViewportPreRender()));
|
|
|
|
connect(ui->MainViewport, SIGNAL(Render(CCamera&)), this, SLOT(ViewportRender(CCamera&)));
|
|
|
|
connect(ui->MainViewport, SIGNAL(ViewportResized(int,int)), this, SLOT(SetViewportSize(int,int)));
|
|
|
|
connect(ui->MainViewport, SIGNAL(frameSwapped()), this, SLOT(ViewportPostRender()));
|
|
|
|
connect(ui->MainViewport, SIGNAL(MouseClick(QMouseEvent*)), this, SLOT(ViewportMouseClick(QMouseEvent*)));
|
2015-08-20 01:01:58 +00:00
|
|
|
connect(ui->MainViewport, SIGNAL(MouseRelease(QMouseEvent*)), this, SLOT(ViewportMouseRelease(QMouseEvent*)));
|
2015-07-26 21:39:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CWorldEditor::~CWorldEditor()
|
|
|
|
{
|
|
|
|
delete ui;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CWorldEditor::eventFilter(QObject *pObj, QEvent *pEvent)
|
|
|
|
{
|
|
|
|
if (pObj == ui->MainDock)
|
|
|
|
{
|
|
|
|
if (pEvent->type() == QEvent::Resize)
|
|
|
|
{
|
|
|
|
UpdateSelectionUI();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::SetArea(CWorld *pWorld, CGameArea *pArea)
|
|
|
|
{
|
|
|
|
ResetHover();
|
|
|
|
ClearSelection();
|
|
|
|
ui->ModifyTabContents->ClearUI();
|
|
|
|
ui->ModifyTabContents->ClearCachedEditors();
|
|
|
|
ui->InstancesTabContents->SetMaster(nullptr);
|
|
|
|
ui->InstancesTabContents->SetArea(pArea);
|
|
|
|
|
|
|
|
// Clear old area - hack until better world/area loader is implemented
|
|
|
|
if ((mpArea) && (pArea != mpArea))
|
|
|
|
mpArea->ClearScriptLayers();
|
|
|
|
|
|
|
|
// Load new area
|
|
|
|
mpArea = pArea;
|
|
|
|
mpWorld = pWorld;
|
|
|
|
mAreaToken = CToken(pArea);
|
|
|
|
mWorldToken = CToken(pWorld);
|
|
|
|
|
|
|
|
mpSceneManager->SetActiveWorld(pWorld);
|
|
|
|
mpSceneManager->SetActiveArea(pArea);
|
|
|
|
|
|
|
|
// Snap camera to location of area
|
|
|
|
CTransform4f AreaTransform = pArea->GetTransform();
|
|
|
|
CVector3f AreaPosition(AreaTransform[0][3], AreaTransform[1][3], AreaTransform[2][3]);
|
|
|
|
ui->MainViewport->Camera().Snap(AreaPosition);
|
|
|
|
|
2015-07-28 16:22:08 +00:00
|
|
|
// Default bloom to Fake Bloom for Metroid Prime 3; disable for other games
|
2015-07-26 21:39:49 +00:00
|
|
|
if (mpWorld->Version() == eCorruption)
|
|
|
|
{
|
|
|
|
ui->menuBloom->setEnabled(true);
|
2015-07-28 16:22:08 +00:00
|
|
|
on_ActionFakeBloom_triggered();
|
2015-07-26 21:39:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
else
|
|
|
|
{
|
|
|
|
ui->menuBloom->setEnabled(false);
|
|
|
|
on_ActionNoBloom_triggered();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Set up sidebar tabs
|
|
|
|
CMasterTemplate *pMaster = CMasterTemplate::GetMasterForGame(mpWorld->Version());
|
|
|
|
ui->InstancesTabContents->SetMaster(pMaster);
|
|
|
|
}
|
|
|
|
|
2015-08-24 01:02:14 +00:00
|
|
|
void CWorldEditor::ViewportRayCast()
|
2015-07-26 21:39:49 +00:00
|
|
|
{
|
|
|
|
if (!ui->MainViewport->IsMouseInputActive())
|
|
|
|
{
|
2015-08-24 01:02:14 +00:00
|
|
|
// Cast ray
|
|
|
|
CVector2f mouseCoords = ui->MainViewport->MouseDeviceCoordinates();
|
|
|
|
CCamera camera = ui->MainViewport->Camera();
|
|
|
|
CRay ray = camera.CastRay(mouseCoords);
|
|
|
|
|
2015-08-20 01:01:58 +00:00
|
|
|
if (!mGizmoTransforming)
|
|
|
|
{
|
|
|
|
// Gizmo hover check
|
|
|
|
if (mShowGizmo && !mSelectedNodes.empty())
|
2015-08-24 01:02:14 +00:00
|
|
|
mGizmoHovering = mGizmo.CheckSelectedAxes(ray);
|
2015-08-20 01:01:58 +00:00
|
|
|
else
|
|
|
|
{
|
|
|
|
mGizmoHovering = false;
|
|
|
|
mGizmo.ResetSelectedAxes();
|
|
|
|
}
|
2015-08-17 18:10:42 +00:00
|
|
|
|
2015-08-20 01:01:58 +00:00
|
|
|
// Scene ray check
|
2015-08-24 01:02:14 +00:00
|
|
|
SRayIntersection Result = mpSceneManager->SceneRayCast(ray);
|
2015-07-26 21:39:49 +00:00
|
|
|
|
2015-08-20 01:01:58 +00:00
|
|
|
if (Result.Hit)
|
|
|
|
{
|
|
|
|
if (mpHoverNode)
|
|
|
|
mpHoverNode->SetMouseHovering(false);
|
2015-07-26 21:39:49 +00:00
|
|
|
|
2015-08-20 01:01:58 +00:00
|
|
|
mpHoverNode = Result.pNode;
|
|
|
|
mpHoverNode->SetMouseHovering(true);
|
2015-07-26 21:39:49 +00:00
|
|
|
|
2015-08-24 01:02:14 +00:00
|
|
|
mHoverPoint = ray.PointOnRay(Result.Distance);
|
2015-08-20 01:01:58 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
ResetHover();
|
2015-07-26 21:39:49 +00:00
|
|
|
}
|
|
|
|
else
|
2015-08-20 01:01:58 +00:00
|
|
|
{
|
2015-08-24 01:02:14 +00:00
|
|
|
bool transformed = mGizmo.TransformFromInput(ray, ui->MainViewport->Camera());
|
2015-08-20 01:01:58 +00:00
|
|
|
|
2015-08-24 01:02:14 +00:00
|
|
|
if (transformed)
|
2015-08-20 01:01:58 +00:00
|
|
|
{
|
2015-08-24 01:02:14 +00:00
|
|
|
switch (mGizmo.Mode())
|
|
|
|
{
|
|
|
|
case CGizmo::eTranslate:
|
|
|
|
{
|
|
|
|
CVector3f delta = mGizmo.DeltaTranslation();
|
|
|
|
|
|
|
|
for (auto it = mSelectedNodes.begin(); it != mSelectedNodes.end(); it++)
|
|
|
|
{
|
|
|
|
(*it)->Translate(delta, mTransformSpace);
|
|
|
|
(*it)->BuildLightList(this->mpArea);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2015-08-20 01:01:58 +00:00
|
|
|
|
2015-08-24 01:02:14 +00:00
|
|
|
case CGizmo::eRotate:
|
2015-08-20 01:01:58 +00:00
|
|
|
{
|
2015-08-24 01:02:14 +00:00
|
|
|
CQuaternion delta = mGizmo.DeltaRotation();
|
|
|
|
|
|
|
|
for (auto it = mSelectedNodes.begin(); it != mSelectedNodes.end(); it++)
|
|
|
|
(*it)->Rotate(delta, mTransformSpace);
|
|
|
|
|
|
|
|
break;
|
2015-08-20 01:01:58 +00:00
|
|
|
}
|
2015-08-24 01:02:14 +00:00
|
|
|
}
|
|
|
|
|
2015-08-20 01:01:58 +00:00
|
|
|
RecalculateSelectionBounds();
|
2015-08-24 01:02:14 +00:00
|
|
|
mGizmoUIOutdated = true;
|
2015-08-20 01:01:58 +00:00
|
|
|
}
|
|
|
|
}
|
2015-07-26 21:39:49 +00:00
|
|
|
}
|
|
|
|
else
|
2015-08-17 18:10:42 +00:00
|
|
|
{
|
2015-08-20 01:01:58 +00:00
|
|
|
if (!mGizmoTransforming)
|
|
|
|
{
|
|
|
|
mGizmoHovering = false;
|
|
|
|
mGizmo.ResetSelectedAxes();
|
|
|
|
}
|
2015-07-26 21:39:49 +00:00
|
|
|
ResetHover();
|
2015-08-17 18:10:42 +00:00
|
|
|
}
|
2015-07-26 21:39:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
CRenderer* CWorldEditor::Renderer()
|
|
|
|
{
|
|
|
|
return mpRenderer;
|
|
|
|
}
|
|
|
|
|
|
|
|
CSceneManager* CWorldEditor::Scene()
|
|
|
|
{
|
|
|
|
return mpSceneManager;
|
|
|
|
}
|
|
|
|
|
|
|
|
CGameArea* CWorldEditor::ActiveArea()
|
|
|
|
{
|
|
|
|
return mpArea;
|
|
|
|
}
|
|
|
|
|
|
|
|
// ************ SELECTION ************
|
|
|
|
void CWorldEditor::SelectNode(CSceneNode *pNode)
|
|
|
|
{
|
|
|
|
if (!pNode->IsSelected())
|
|
|
|
{
|
|
|
|
pNode->SetSelected(true);
|
|
|
|
mSelectedNodes.push_back(pNode);
|
|
|
|
mSelectionAABox.ExpandBounds(pNode->AABox());
|
|
|
|
|
|
|
|
if (pNode->NodeType() == eScriptNode)
|
|
|
|
{
|
|
|
|
CScriptNode *pScript = static_cast<CScriptNode*>(pNode);
|
|
|
|
if (pScript->HasPreviewVolume())
|
|
|
|
mSelectionAABox.ExpandBounds(pScript->PreviewVolumeAABox());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
UpdateSelectionUI();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::DeselectNode(CSceneNode *pNode)
|
|
|
|
{
|
|
|
|
if (pNode->IsSelected())
|
|
|
|
{
|
|
|
|
pNode->SetSelected(false);
|
|
|
|
|
|
|
|
for (auto it = mSelectedNodes.begin(); it != mSelectedNodes.end(); it++)
|
|
|
|
{
|
|
|
|
if (*it == pNode)
|
|
|
|
{
|
|
|
|
mSelectedNodes.erase(it);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
RecalculateSelectionBounds();
|
|
|
|
UpdateSelectionUI();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::ClearSelection()
|
|
|
|
{
|
|
|
|
for (auto it = mSelectedNodes.begin(); it != mSelectedNodes.end(); it++)
|
|
|
|
(*it)->SetSelected(false);
|
|
|
|
|
|
|
|
mSelectedNodes.clear();
|
|
|
|
mSelectionAABox = CAABox::skInfinite;
|
|
|
|
UpdateSelectionUI();
|
|
|
|
}
|
|
|
|
|
|
|
|
// ************ SLOTS ************
|
|
|
|
void CWorldEditor::ViewportMouseDrag(QMouseEvent *pEvent)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::ViewportMouseClick(QMouseEvent *pEvent)
|
|
|
|
{
|
2015-08-20 01:01:58 +00:00
|
|
|
bool AltPressed = ((pEvent->modifiers() & Qt::AltModifier) != 0);
|
|
|
|
bool CtrlPressed = ((pEvent->modifiers() & Qt::ControlModifier) != 0);
|
|
|
|
|
|
|
|
if (mGizmoHovering && !AltPressed && !CtrlPressed)
|
2015-07-26 21:39:49 +00:00
|
|
|
{
|
2015-08-20 01:01:58 +00:00
|
|
|
mGizmoTransforming = true;
|
|
|
|
mGizmo.StartTransform();
|
|
|
|
}
|
|
|
|
}
|
2015-07-26 21:39:49 +00:00
|
|
|
|
2015-08-20 01:01:58 +00:00
|
|
|
void CWorldEditor::ViewportMouseRelease(QMouseEvent *pEvent)
|
|
|
|
{
|
|
|
|
if (pEvent->button() == Qt::LeftButton)
|
|
|
|
{
|
|
|
|
// Gizmo transform stop
|
|
|
|
if (mGizmoTransforming)
|
2015-07-26 21:39:49 +00:00
|
|
|
{
|
2015-08-24 01:02:14 +00:00
|
|
|
mGizmo.EndTransform();
|
2015-08-20 01:01:58 +00:00
|
|
|
mGizmoTransforming = false;
|
2015-08-24 01:02:14 +00:00
|
|
|
mGizmoUIOutdated = true;
|
2015-07-26 21:39:49 +00:00
|
|
|
}
|
|
|
|
|
2015-08-20 01:01:58 +00:00
|
|
|
// Object selection/deselection
|
|
|
|
else if (!ui->MainViewport->IsMouseInputActive())
|
2015-07-26 21:39:49 +00:00
|
|
|
{
|
2015-08-20 01:01:58 +00:00
|
|
|
bool ValidNode = ((mpHoverNode) && (mpHoverNode->NodeType() != eStaticNode));
|
|
|
|
bool AltPressed = ((pEvent->modifiers() & Qt::AltModifier) != 0);
|
|
|
|
bool CtrlPressed = ((pEvent->modifiers() & Qt::ControlModifier) != 0);
|
2015-07-26 21:39:49 +00:00
|
|
|
|
2015-08-20 01:01:58 +00:00
|
|
|
// Alt pressed - deselect object
|
|
|
|
if (AltPressed)
|
|
|
|
{
|
|
|
|
// No valid node selected - do nothing
|
|
|
|
if (!ValidNode)
|
|
|
|
return;
|
2015-07-26 21:39:49 +00:00
|
|
|
|
2015-08-20 01:01:58 +00:00
|
|
|
DeselectNode(mpHoverNode);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ctrl pressed - add object to selection
|
|
|
|
else if (CtrlPressed)
|
|
|
|
{
|
|
|
|
// Add hover node to selection
|
|
|
|
if (ValidNode)
|
|
|
|
SelectNode(mpHoverNode);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Neither pressed
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// If the gizmo isn't under the mouse, clear existing selection + select object (if applicable)
|
|
|
|
if (!mGizmoHovering)
|
|
|
|
{
|
|
|
|
ClearSelection();
|
|
|
|
|
|
|
|
if (ValidNode)
|
|
|
|
SelectNode(mpHoverNode);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
UpdateSelectionUI();
|
|
|
|
}
|
2015-07-26 21:39:49 +00:00
|
|
|
}
|
|
|
|
|
2015-08-20 01:01:58 +00:00
|
|
|
// todo: context menu creation on right-click goes here
|
2015-07-26 21:39:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ************ SLOTS ************
|
|
|
|
void CWorldEditor::ViewportPreRender()
|
|
|
|
{
|
|
|
|
// Perform raycast
|
|
|
|
if (ui->MainViewport->underMouse())
|
2015-08-24 01:02:14 +00:00
|
|
|
ViewportRayCast();
|
2015-07-26 21:39:49 +00:00
|
|
|
else
|
|
|
|
ResetHover();
|
|
|
|
|
|
|
|
// Start frame
|
|
|
|
mFrameTimer.Start();
|
|
|
|
mpRenderer->BeginFrame();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::ViewportRender(CCamera& Camera)
|
|
|
|
{
|
|
|
|
mpSceneManager->AddSceneToRenderer(mpRenderer);
|
|
|
|
|
|
|
|
if (mDrawSky)
|
|
|
|
{
|
|
|
|
CModel *pSky = mpSceneManager->GetActiveSkybox();
|
|
|
|
if (pSky) mpRenderer->RenderSky(pSky, Camera.Position());
|
|
|
|
}
|
|
|
|
|
2015-08-15 04:04:56 +00:00
|
|
|
mpRenderer->RenderBuckets(Camera);
|
|
|
|
mpRenderer->RenderBloom();
|
2015-08-16 04:29:37 +00:00
|
|
|
|
|
|
|
if (mShowGizmo && (mSelectedNodes.size() > 0))
|
|
|
|
{
|
2015-08-20 01:01:58 +00:00
|
|
|
mpRenderer->ClearDepthBuffer();
|
|
|
|
|
2015-08-16 04:29:37 +00:00
|
|
|
Camera.LoadMatrices();
|
2015-08-24 01:02:14 +00:00
|
|
|
mGizmo.UpdateForCamera(Camera);
|
2015-08-16 04:29:37 +00:00
|
|
|
mGizmo.AddToRenderer(mpRenderer);
|
|
|
|
|
|
|
|
mpRenderer->RenderBuckets(Camera);
|
2015-08-24 01:02:14 +00:00
|
|
|
mpRenderer->ClearDepthBuffer();
|
2015-08-16 04:29:37 +00:00
|
|
|
}
|
|
|
|
|
2015-07-26 21:39:49 +00:00
|
|
|
mpRenderer->EndFrame();
|
|
|
|
mFrameTimer.Stop();
|
|
|
|
mFrameCount++;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::ViewportPostRender()
|
|
|
|
{
|
|
|
|
// Update UI with raycast results
|
|
|
|
UpdateCursor();
|
|
|
|
UpdateStatusBar();
|
2015-08-20 01:01:58 +00:00
|
|
|
|
2015-08-24 01:02:14 +00:00
|
|
|
if (mGizmoUIOutdated) UpdateGizmoUI();
|
2015-07-26 21:39:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::SetViewportSize(int Width, int Height)
|
|
|
|
{
|
|
|
|
mpRenderer->SetViewportSize(Width, Height);
|
|
|
|
}
|
|
|
|
|
2015-08-20 01:01:58 +00:00
|
|
|
void CWorldEditor::SetTransformSpace(int space)
|
|
|
|
{
|
|
|
|
switch (space)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
mTransformSpace = eWorldTransform;
|
2015-08-24 01:02:14 +00:00
|
|
|
mGizmo.SetRotation(CQuaternion::skIdentity);
|
2015-08-20 01:01:58 +00:00
|
|
|
break;
|
|
|
|
case 1:
|
|
|
|
mTransformSpace = eLocalTransform;
|
|
|
|
if (!mSelectedNodes.empty())
|
2015-08-24 01:02:14 +00:00
|
|
|
mGizmo.SetRotation(mSelectedNodes.front()->AbsoluteRotation());
|
2015-08-20 01:01:58 +00:00
|
|
|
break;
|
|
|
|
}
|
2015-08-24 01:02:14 +00:00
|
|
|
|
|
|
|
mGizmo.SetTransformSpace(mTransformSpace);
|
2015-08-20 01:01:58 +00:00
|
|
|
}
|
|
|
|
|
2015-07-26 21:39:49 +00:00
|
|
|
// ************ PRIVATE ************
|
|
|
|
void CWorldEditor::RecalculateSelectionBounds()
|
|
|
|
{
|
|
|
|
mSelectionAABox = CAABox::skInfinite;
|
|
|
|
|
|
|
|
for (auto it = mSelectedNodes.begin(); it != mSelectedNodes.end(); it++)
|
|
|
|
{
|
|
|
|
mSelectionAABox.ExpandBounds( (*it)->AABox() );
|
|
|
|
|
|
|
|
if ((*it)->NodeType() == eScriptNode)
|
|
|
|
{
|
|
|
|
CScriptNode *pScript = static_cast<CScriptNode*>(*it);
|
|
|
|
if (pScript->HasPreviewVolume())
|
|
|
|
mSelectionAABox.ExpandBounds(pScript->PreviewVolumeAABox());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::ResetHover()
|
|
|
|
{
|
|
|
|
if (mpHoverNode) mpHoverNode->SetMouseHovering(false);
|
|
|
|
mpHoverNode = nullptr;
|
|
|
|
mHoverPoint = CVector3f::skZero;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::UpdateCursor()
|
|
|
|
{
|
|
|
|
if (ui->MainViewport->IsCursorVisible())
|
|
|
|
{
|
2015-08-17 18:10:42 +00:00
|
|
|
if (mGizmoHovering)
|
|
|
|
ui->MainViewport->SetCursorState(Qt::SizeAllCursor);
|
|
|
|
else if ((mpHoverNode) && (mpHoverNode->NodeType() != eStaticNode))
|
2015-07-26 21:39:49 +00:00
|
|
|
ui->MainViewport->SetCursorState(Qt::PointingHandCursor);
|
|
|
|
else
|
|
|
|
ui->MainViewport->SetCursorState(Qt::ArrowCursor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::UpdateStatusBar()
|
|
|
|
{
|
|
|
|
// Would be cool to do more frequent status bar updates with more info. Unfortunately, this causes lag.
|
|
|
|
QString StatusText = "";
|
|
|
|
|
2015-08-17 18:10:42 +00:00
|
|
|
if (!mGizmoHovering && mpHoverNode)
|
2015-07-26 21:39:49 +00:00
|
|
|
{
|
|
|
|
if (mpHoverNode->NodeType() != eStaticNode)
|
|
|
|
StatusText = QString::fromStdString(mpHoverNode->Name());
|
|
|
|
}
|
|
|
|
|
|
|
|
if (ui->statusbar->currentMessage() != StatusText)
|
|
|
|
ui->statusbar->showMessage(StatusText);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::UpdateSelectionUI()
|
|
|
|
{
|
|
|
|
// Update sidebar
|
|
|
|
ui->ModifyTabContents->GenerateUI(mSelectedNodes);
|
|
|
|
|
|
|
|
// Update selection info text
|
|
|
|
QString SelectionText;
|
|
|
|
|
|
|
|
if (mSelectedNodes.size() == 1)
|
|
|
|
SelectionText = QString::fromStdString(mSelectedNodes.front()->Name());
|
|
|
|
else if (mSelectedNodes.size() > 1)
|
|
|
|
SelectionText = QString("%1 objects selected").arg(mSelectedNodes.size());
|
|
|
|
|
|
|
|
QFontMetrics Metrics(ui->SelectionInfoLabel->font());
|
|
|
|
SelectionText = Metrics.elidedText(SelectionText, Qt::ElideRight, ui->SelectionInfoFrame->width() - 10);
|
|
|
|
ui->SelectionInfoLabel->setText(SelectionText);
|
2015-07-29 13:51:59 +00:00
|
|
|
|
2015-08-24 01:02:14 +00:00
|
|
|
// Update gizmo stuff
|
|
|
|
UpdateGizmoUI();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::UpdateGizmoUI()
|
|
|
|
{
|
|
|
|
// Update transform XYZ spin boxes
|
|
|
|
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::eTranslate:
|
|
|
|
if (mGizmoTransforming && mGizmo.HasTransformed())
|
|
|
|
spinBoxValue = mGizmo.TotalTranslation();
|
|
|
|
else if (!mSelectedNodes.empty())
|
|
|
|
spinBoxValue = mSelectedNodes.front()->AbsolutePosition();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CGizmo::eRotate:
|
|
|
|
if (mGizmoTransforming && mGizmo.HasTransformed())
|
|
|
|
spinBoxValue = mGizmo.TotalRotation();
|
|
|
|
else if (!mSelectedNodes.empty())
|
|
|
|
spinBoxValue = mSelectedNodes.front()->AbsoluteRotation().ToEuler();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CGizmo::eScale:
|
|
|
|
if (mGizmoTransforming && mGizmo.HasTransformed())
|
|
|
|
spinBoxValue = mGizmo.TotalScale();
|
|
|
|
else if (!mSelectedNodes.empty())
|
|
|
|
spinBoxValue = mSelectedNodes.front()->AbsoluteScale();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (!mSelectedNodes.empty()) spinBoxValue = mSelectedNodes.front()->AbsolutePosition();
|
|
|
|
|
|
|
|
ui->XSpinBox->setValue(spinBoxValue.x);
|
|
|
|
ui->YSpinBox->setValue(spinBoxValue.y);
|
|
|
|
ui->ZSpinBox->setValue(spinBoxValue.z);
|
2015-08-16 04:29:37 +00:00
|
|
|
|
|
|
|
// Update gizmo
|
2015-08-20 01:01:58 +00:00
|
|
|
if (!mGizmoTransforming)
|
|
|
|
{
|
2015-08-24 01:02:14 +00:00
|
|
|
if (!mSelectedNodes.empty())
|
|
|
|
mGizmo.SetPosition(mSelectedNodes.front()->AbsolutePosition());
|
2015-08-20 01:01:58 +00:00
|
|
|
|
|
|
|
if ((mTransformSpace == eLocalTransform) && !mSelectedNodes.empty())
|
2015-08-24 01:02:14 +00:00
|
|
|
mGizmo.SetRotation(mSelectedNodes.front()->AbsoluteRotation());
|
2015-08-20 01:01:58 +00:00
|
|
|
else
|
2015-08-24 01:02:14 +00:00
|
|
|
mGizmo.SetRotation(CQuaternion::skIdentity);
|
2015-08-20 01:01:58 +00:00
|
|
|
}
|
2015-08-24 01:02:14 +00:00
|
|
|
|
|
|
|
mGizmoUIOutdated = false;
|
2015-07-26 21:39:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ************ ACTIONS ************
|
2015-07-29 13:51:59 +00:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
2015-07-26 21:39:49 +00:00
|
|
|
// These functions are from "Go to slot" in the designer
|
|
|
|
void CWorldEditor::on_ActionDrawWorld_triggered()
|
|
|
|
{
|
|
|
|
mpSceneManager->SetWorld(ui->ActionDrawWorld->isChecked());
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::on_ActionDrawCollision_triggered()
|
|
|
|
{
|
|
|
|
mpSceneManager->SetCollision(ui->ActionDrawCollision->isChecked());
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::on_ActionDrawObjects_triggered()
|
|
|
|
{
|
|
|
|
mpSceneManager->SetObjects(ui->ActionDrawObjects->isChecked());
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::on_ActionDrawLights_triggered()
|
|
|
|
{
|
|
|
|
mpSceneManager->SetLights(ui->ActionDrawLights->isChecked());
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::on_ActionDrawSky_triggered()
|
|
|
|
{
|
|
|
|
mDrawSky = ui->ActionDrawSky->isChecked();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::on_ActionNoLighting_triggered()
|
|
|
|
{
|
|
|
|
CGraphics::sLightMode = CGraphics::NoLighting;
|
|
|
|
ui->ActionNoLighting->setChecked(true);
|
|
|
|
ui->ActionBasicLighting->setChecked(false);
|
|
|
|
ui->ActionWorldLighting->setChecked(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::on_ActionBasicLighting_triggered()
|
|
|
|
{
|
|
|
|
CGraphics::sLightMode = CGraphics::BasicLighting;
|
|
|
|
ui->ActionNoLighting->setChecked(false);
|
|
|
|
ui->ActionBasicLighting->setChecked(true);
|
|
|
|
ui->ActionWorldLighting->setChecked(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::on_ActionWorldLighting_triggered()
|
|
|
|
{
|
|
|
|
CGraphics::sLightMode = CGraphics::WorldLighting;
|
|
|
|
ui->ActionNoLighting->setChecked(false);
|
|
|
|
ui->ActionBasicLighting->setChecked(false);
|
|
|
|
ui->ActionWorldLighting->setChecked(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::on_ActionNoBloom_triggered()
|
|
|
|
{
|
|
|
|
mpRenderer->SetBloom(CRenderer::eNoBloom);
|
|
|
|
ui->ActionNoBloom->setChecked(true);
|
|
|
|
ui->ActionBloomMaps->setChecked(false);
|
2015-07-28 16:22:08 +00:00
|
|
|
ui->ActionFakeBloom->setChecked(false);
|
2015-07-26 21:39:49 +00:00
|
|
|
ui->ActionBloom->setChecked(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::on_ActionBloomMaps_triggered()
|
|
|
|
{
|
|
|
|
mpRenderer->SetBloom(CRenderer::eBloomMaps);
|
|
|
|
ui->ActionNoBloom->setChecked(false);
|
|
|
|
ui->ActionBloomMaps->setChecked(true);
|
2015-07-28 16:22:08 +00:00
|
|
|
ui->ActionFakeBloom->setChecked(false);
|
|
|
|
ui->ActionBloom->setChecked(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::on_ActionFakeBloom_triggered()
|
|
|
|
{
|
|
|
|
mpRenderer->SetBloom(CRenderer::eFakeBloom);
|
|
|
|
ui->ActionNoBloom->setChecked(false);
|
|
|
|
ui->ActionBloomMaps->setChecked(false);
|
|
|
|
ui->ActionFakeBloom->setChecked(true);
|
2015-07-26 21:39:49 +00:00
|
|
|
ui->ActionBloom->setChecked(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::on_ActionBloom_triggered()
|
|
|
|
{
|
|
|
|
mpRenderer->SetBloom(CRenderer::eBloom);
|
|
|
|
ui->ActionNoBloom->setChecked(false);
|
|
|
|
ui->ActionBloomMaps->setChecked(false);
|
2015-07-28 16:22:08 +00:00
|
|
|
ui->ActionFakeBloom->setChecked(false);
|
2015-07-26 21:39:49 +00:00
|
|
|
ui->ActionBloom->setChecked(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::on_ActionZoomOnSelection_triggered()
|
|
|
|
{
|
|
|
|
static const float skDistScale = 2.5f;
|
|
|
|
static const float skAreaDistScale = 0.8f;
|
|
|
|
|
|
|
|
CCamera& Camera = ui->MainViewport->Camera();
|
|
|
|
CVector3f CamDir = Camera.GetDirection();
|
|
|
|
CVector3f NewPos;
|
|
|
|
|
|
|
|
// Zoom on selection
|
|
|
|
if (mSelectedNodes.size() != 0)
|
|
|
|
{
|
|
|
|
CVector3f Min = mSelectionAABox.Min();
|
|
|
|
CVector3f Max = mSelectionAABox.Max();
|
|
|
|
float Dist = ((Max.x - Min.x) + (Max.y - Min.y) + (Max.z - Min.z)) / 3.f;
|
|
|
|
//float Dist = mSelectionAABox.Min().Distance(mSelectionAABox.Max());
|
|
|
|
NewPos = mSelectionAABox.Center() + (CamDir * -(Dist * skDistScale));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Zoom on area
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CAABox AreaBox = mpArea->AABox();
|
|
|
|
CVector3f Min = AreaBox.Min();
|
|
|
|
CVector3f Max = AreaBox.Max();
|
|
|
|
float Dist = ((Max.x - Min.x) + (Max.y - Min.y) + (Max.z - Min.z)) / 3.f;
|
|
|
|
//float Dist = AreaBox.Min().Distance(AreaBox.Max());
|
|
|
|
NewPos = AreaBox.Center() + (CamDir * -(Dist * skAreaDistScale));
|
|
|
|
}
|
|
|
|
|
|
|
|
Camera.SetPosition(NewPos);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::on_ActionDisableBackfaceCull_triggered()
|
|
|
|
{
|
|
|
|
mpRenderer->ToggleBackfaceCull(!ui->ActionDisableBackfaceCull->isChecked());
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::on_ActionDisableAlpha_triggered()
|
|
|
|
{
|
|
|
|
mpRenderer->ToggleAlphaDisabled(ui->ActionDisableAlpha->isChecked());
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::on_ActionEditLayers_triggered()
|
|
|
|
{
|
|
|
|
// Launch layer editor
|
|
|
|
CLayerEditor Editor(this);
|
|
|
|
Editor.SetArea(mpArea);
|
|
|
|
Editor.exec();
|
|
|
|
}
|
2015-08-16 04:29:37 +00:00
|
|
|
|
|
|
|
void CWorldEditor::on_ActionSelectObjects_triggered()
|
|
|
|
{
|
|
|
|
mShowGizmo = false;
|
2015-08-24 01:02:14 +00:00
|
|
|
mGizmoUIOutdated = true;
|
2015-08-16 04:29:37 +00:00
|
|
|
ui->ActionSelectObjects->setChecked(true);
|
|
|
|
ui->ActionTranslate->setChecked(false);
|
|
|
|
ui->ActionRotate->setChecked(false);
|
|
|
|
ui->ActionScale->setChecked(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::on_ActionTranslate_triggered()
|
|
|
|
{
|
|
|
|
mShowGizmo = true;
|
2015-08-24 01:02:14 +00:00
|
|
|
mGizmoUIOutdated = true;
|
2015-08-16 04:29:37 +00:00
|
|
|
mGizmo.SetMode(CGizmo::eTranslate);
|
|
|
|
ui->ActionSelectObjects->setChecked(false);
|
|
|
|
ui->ActionTranslate->setChecked(true);
|
|
|
|
ui->ActionRotate->setChecked(false);
|
|
|
|
ui->ActionScale->setChecked(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::on_ActionRotate_triggered()
|
|
|
|
{
|
|
|
|
mShowGizmo = true;
|
2015-08-24 01:02:14 +00:00
|
|
|
mGizmoUIOutdated = true;
|
2015-08-16 04:29:37 +00:00
|
|
|
mGizmo.SetMode(CGizmo::eRotate);
|
|
|
|
ui->ActionSelectObjects->setChecked(false);
|
|
|
|
ui->ActionTranslate->setChecked(false);
|
|
|
|
ui->ActionRotate->setChecked(true);
|
|
|
|
ui->ActionScale->setChecked(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::on_ActionScale_triggered()
|
|
|
|
{
|
|
|
|
mShowGizmo = true;
|
2015-08-24 01:02:14 +00:00
|
|
|
mGizmoUIOutdated = true;
|
2015-08-16 04:29:37 +00:00
|
|
|
mGizmo.SetMode(CGizmo::eScale);
|
|
|
|
ui->ActionSelectObjects->setChecked(false);
|
|
|
|
ui->ActionTranslate->setChecked(false);
|
|
|
|
ui->ActionRotate->setChecked(false);
|
|
|
|
ui->ActionScale->setChecked(true);
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::on_ActionIncrementGizmo_triggered()
|
|
|
|
{
|
|
|
|
mGizmo.IncrementSize();
|
|
|
|
}
|
|
|
|
|
|
|
|
void CWorldEditor::on_ActionDecrementGizmo_triggered()
|
|
|
|
{
|
|
|
|
mGizmo.DecrementSize();
|
|
|
|
}
|