Split off lots of editor functionality into new abstract INodeEditor class and viewport functionality into CBasicViewport class; added viewport subclasses and undo/redo system in the World Editor
This commit is contained in:
parent
281a605586
commit
dbf002d12a
|
@ -1,4 +1,6 @@
|
|||
#include "Math.h"
|
||||
#include <Common/CMatrix4f.h>
|
||||
#include <gtc/matrix_transform.hpp>
|
||||
|
||||
namespace Math
|
||||
{
|
||||
|
@ -336,4 +338,10 @@ std::pair<bool,float> RayTriangleIntersection(const CRay& Ray,
|
|||
return std::pair<bool,float>(true, t);
|
||||
}
|
||||
|
||||
CMatrix4f PerspectiveMatrix(float fov, float aspect, float near, float far)
|
||||
{
|
||||
// todo: don't use glm
|
||||
return CMatrix4f::FromGlmMat4(glm::perspective(fov, aspect, near, far)).Transpose();
|
||||
}
|
||||
|
||||
} // End namespace
|
||||
|
|
|
@ -32,6 +32,8 @@ std::pair<bool,float> RayTriangleIntersection(const CRay& Ray, const CVector3f&
|
|||
const CVector3f& PointB, const CVector3f& PointC,
|
||||
bool AllowBackfaces = false);
|
||||
|
||||
CMatrix4f PerspectiveMatrix(float fov, float aspect, float near, float far);
|
||||
|
||||
// Constants
|
||||
static const float skPi = 3.14159265358979323846f;
|
||||
static const float skHalfPi = skPi / 2.f;
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
#include "CCamera.h"
|
||||
#include "CGraphics.h"
|
||||
#include <Common/CQuaternion.h>
|
||||
|
||||
#include <Common/Math.h>
|
||||
#include <gtc/matrix_transform.hpp>
|
||||
|
||||
#define HALF_PI 1.570796371f
|
||||
|
@ -170,21 +170,25 @@ CVector3f CCamera::Position() const
|
|||
return mPosition;
|
||||
}
|
||||
|
||||
CVector3f CCamera::GetDirection() const
|
||||
CVector3f CCamera::Direction() const
|
||||
{
|
||||
return mDirection;
|
||||
}
|
||||
|
||||
float CCamera::GetYaw() const
|
||||
float CCamera::Yaw() const
|
||||
{
|
||||
return mYaw;
|
||||
}
|
||||
|
||||
float CCamera::GetPitch() const
|
||||
float CCamera::Pitch() const
|
||||
{
|
||||
return mPitch;
|
||||
}
|
||||
|
||||
float CCamera::FieldOfView() const
|
||||
{
|
||||
return 55.f;
|
||||
}
|
||||
|
||||
const CMatrix4f& CCamera::ViewMatrix()
|
||||
{
|
||||
|
@ -298,7 +302,6 @@ void CCamera::CalculateView()
|
|||
|
||||
void CCamera::CalculateProjection()
|
||||
{
|
||||
// todo: don't use glm
|
||||
mCachedProjectionMatrix = CMatrix4f::FromGlmMat4(glm::perspective(55.f, mAspectRatio, 0.1f, 4096.f)).Transpose();
|
||||
mCachedProjectionMatrix = Math::PerspectiveMatrix(55.f, mAspectRatio, 0.1f, 4096.f);
|
||||
mProjectionOutdated = false;
|
||||
}
|
||||
|
|
|
@ -49,9 +49,10 @@ public:
|
|||
|
||||
// Getters
|
||||
CVector3f Position() const;
|
||||
CVector3f GetDirection() const;
|
||||
float GetYaw() const;
|
||||
float GetPitch() const;
|
||||
CVector3f Direction() const;
|
||||
float Yaw() const;
|
||||
float Pitch() const;
|
||||
float FieldOfView() const;
|
||||
const CMatrix4f& ViewMatrix();
|
||||
const CMatrix4f& RotationOnlyViewMatrix();
|
||||
const CMatrix4f& ProjectionMatrix();
|
||||
|
|
|
@ -30,7 +30,7 @@ void CRenderBucket::Sort(CCamera& Camera)
|
|||
CCamera *pCamera;
|
||||
bool operator()(SRenderablePtr left, SRenderablePtr right) {
|
||||
CVector3f cPos = pCamera->Position();
|
||||
CVector3f cDir = pCamera->GetDirection();
|
||||
CVector3f cDir = pCamera->Direction();
|
||||
|
||||
CVector3f distL = left.AABox.ClosestPointAlongVector(cDir) - cPos;
|
||||
float dotL = distL.Dot(cDir);
|
||||
|
|
|
@ -126,7 +126,7 @@ void CRenderer::RenderBuckets(CCamera& Camera)
|
|||
{
|
||||
if (!mInitialized) Init();
|
||||
mSceneFramebuffer.Bind();
|
||||
Camera.LoadMatrices();
|
||||
//Camera.LoadMatrices();
|
||||
|
||||
// Set backface culling
|
||||
if (mOptions & eEnableBackfaceCull) glEnable(GL_CULL_FACE);
|
||||
|
|
|
@ -200,8 +200,11 @@ void CSceneManager::SetActiveWorld(CWorld* _world)
|
|||
|
||||
void CSceneManager::ClearScene()
|
||||
{
|
||||
if (mpAreaRootNode)
|
||||
{
|
||||
mpAreaRootNode->Unparent();
|
||||
delete mpAreaRootNode;
|
||||
}
|
||||
|
||||
mModelNodes.clear();
|
||||
mStaticNodes.clear();
|
||||
|
|
|
@ -72,7 +72,6 @@ SOURCES += \
|
|||
Resource/factory/CWorldLoader.cpp \
|
||||
Resource/CStringTable.cpp \
|
||||
Resource/factory/CStringLoader.cpp \
|
||||
UI/CEditorGLWidget.cpp \
|
||||
Core/CGraphics.cpp \
|
||||
Resource/CFont.cpp \
|
||||
Resource/factory/CFontLoader.cpp \
|
||||
|
@ -135,7 +134,17 @@ SOURCES += \
|
|||
UI/WIntegralSpinBox.cpp \
|
||||
UI/CAboutDialog.cpp \
|
||||
UI/CGizmo.cpp \
|
||||
Common/CPlane.cpp
|
||||
Common/CPlane.cpp \
|
||||
UI/undo/CTranslateNodeCommand.cpp \
|
||||
UI/undo/CClearSelectionCommand.cpp \
|
||||
UI/undo/CSelectNodeCommand.cpp \
|
||||
UI/undo/CDeselectNodeCommand.cpp \
|
||||
UI/CBasicViewport.cpp \
|
||||
UI/INodeEditor.cpp \
|
||||
UI/CSceneViewport.cpp \
|
||||
UI/undo/CRotateNodeCommand.cpp \
|
||||
UI/undo/CScaleNodeCommand.cpp \
|
||||
UI/CModelEditorViewport.cpp
|
||||
|
||||
HEADERS += \
|
||||
Common/AnimUtil.h \
|
||||
|
@ -208,7 +217,6 @@ HEADERS += \
|
|||
Resource/SDependency.h \
|
||||
Resource/CStringTable.h \
|
||||
Resource/factory/CStringLoader.h \
|
||||
UI/CEditorGLWidget.h \
|
||||
Core/CGraphics.h \
|
||||
Resource/CFont.h \
|
||||
Resource/factory/CFontLoader.h \
|
||||
|
@ -286,7 +294,19 @@ HEADERS += \
|
|||
Core/IRenderable.h \
|
||||
Core/SRenderablePtr.h \
|
||||
Common/ETransformSpace.h \
|
||||
Common/CPlane.h
|
||||
Common/CPlane.h \
|
||||
UI/undo/CTranslateNodeCommand.h \
|
||||
UI/undo/EUndoCommand.h \
|
||||
UI/undo/CClearSelectionCommand.h \
|
||||
UI/undo/CSelectNodeCommand.h \
|
||||
UI/undo/CDeselectNodeCommand.h \
|
||||
UI/undo/UndoCommands.h \
|
||||
UI/CBasicViewport.h \
|
||||
UI/INodeEditor.h \
|
||||
UI/CSceneViewport.h \
|
||||
UI/undo/CRotateNodeCommand.h \
|
||||
UI/undo/CScaleNodeCommand.h \
|
||||
UI/CModelEditorViewport.h
|
||||
|
||||
FORMS += \
|
||||
UI/CWorldEditorWindow.ui \
|
||||
|
|
|
@ -108,6 +108,12 @@ void CScriptNode::AddToRenderer(CRenderer *pRenderer)
|
|||
|
||||
if (mHasVolumePreview)
|
||||
mpVolumePreviewNode->AddToRenderer(pRenderer);
|
||||
|
||||
if (mpInstance->ObjectTypeID() == 0xC)
|
||||
{
|
||||
CGraphics::sMVPBlock.ViewMatrix = Transform().Inverse().ToMatrix4f();
|
||||
CGraphics::UpdateMVPBlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,49 +1,31 @@
|
|||
#include "CBasicViewport.h"
|
||||
#include <Core/CDrawUtil.h>
|
||||
#include <Core/CGraphics.h>
|
||||
#include <Common/Math.h>
|
||||
#include <GL/glew.h>
|
||||
#include <gtc/matrix_transform.hpp>
|
||||
#include <gtx/transform.hpp>
|
||||
#include <Core/CGraphics.h>
|
||||
#include <Core/CRenderer.h>
|
||||
#include <QTimer>
|
||||
#include "CEditorGLWidget.h"
|
||||
#include <iostream>
|
||||
#include <Core/CGraphics.h>
|
||||
#include <Resource/factory/CTextureDecoder.h>
|
||||
#include <Common/CTimer.h>
|
||||
#include <Common/CVector4f.h>
|
||||
#include <QOpenGLContext>
|
||||
#include <QPainter>
|
||||
#include <QOpenGLPaintDevice>
|
||||
|
||||
QTimer CEditorGLWidget::sRefreshTimer;
|
||||
|
||||
CEditorGLWidget::CEditorGLWidget(QWidget *pParent) :
|
||||
QOpenGLWidget(pParent)
|
||||
CBasicViewport::CBasicViewport(QWidget *pParent) :
|
||||
QOpenGLWidget(pParent),
|
||||
mLastDrawTime(CTimer::GlobalTime()),
|
||||
mKeysPressed(0),
|
||||
mButtonsPressed(0),
|
||||
mCursorState(Qt::ArrowCursor),
|
||||
mCursorVisible(true)
|
||||
{
|
||||
setMouseTracking(true);
|
||||
mLastDrawTime = CTimer::GlobalTime();
|
||||
mKeysPressed = 0;
|
||||
mButtonsPressed = 0;
|
||||
mCursorState = Qt::ArrowCursor;
|
||||
mCursorVisible = true;
|
||||
mCamera.SetAspectRatio((float) width() / height());
|
||||
|
||||
connect(&sRefreshTimer, SIGNAL(timeout()), this, SLOT(update()));
|
||||
|
||||
if (!sRefreshTimer.isActive())
|
||||
sRefreshTimer.start(0);
|
||||
}
|
||||
|
||||
CEditorGLWidget::~CEditorGLWidget()
|
||||
CBasicViewport::~CBasicViewport()
|
||||
{
|
||||
}
|
||||
|
||||
void CEditorGLWidget::initializeGL()
|
||||
void CBasicViewport::initializeGL()
|
||||
{
|
||||
// Initialize CGraphics
|
||||
CGraphics::Initialize();
|
||||
|
||||
// Setting various GL flags
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glEnable(GL_PRIMITIVE_RESTART);
|
||||
glPrimitiveRestartIndex(0xFFFF);
|
||||
glDepthFunc(GL_LEQUAL);
|
||||
|
@ -55,44 +37,33 @@ void CEditorGLWidget::initializeGL()
|
|||
CMaterial::KillCachedMaterial();
|
||||
CShader::KillCachedShader();
|
||||
|
||||
// Initialize renderer
|
||||
emit ViewportResized(width(), height());
|
||||
// Initialize size
|
||||
OnResize();
|
||||
}
|
||||
|
||||
void CEditorGLWidget::paintGL()
|
||||
void CBasicViewport::paintGL()
|
||||
{
|
||||
double DeltaTime = CTimer::GlobalTime() - mLastDrawTime;
|
||||
mLastDrawTime = CTimer::GlobalTime();
|
||||
// Prep render
|
||||
glViewport(0, 0, width(), height());
|
||||
glLineWidth(1.f);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
||||
// Camera movement is processed here in order to sync it with the paint event
|
||||
// This way movement happens exactly once per frame - no more, no less
|
||||
ProcessInput(DeltaTime);
|
||||
// Actual rendering is intended to be handled by subclassing CBasicViewport and
|
||||
// reimplementing Render().
|
||||
Paint();
|
||||
|
||||
// Pre-render signal allows for per-frame operations to be performed before the draw happens
|
||||
emit PreRender();
|
||||
|
||||
// We emit a signal to indicate it's time to render the viewport instead of doing the rendering here.
|
||||
// This allows the editor GL widget class to be reused among multiple editors with different rendering needs.
|
||||
emit Render(mCamera);
|
||||
|
||||
// Post-render signal allows for the frame to be completed with post-processing
|
||||
emit PostRender();
|
||||
// Finally, draw XYZ axes in the corner
|
||||
// DrawAxes();
|
||||
}
|
||||
|
||||
void CEditorGLWidget::resizeGL(int w, int h)
|
||||
void CBasicViewport::resizeGL(int w, int h)
|
||||
{
|
||||
mCamera.SetAspectRatio((float) w / h);
|
||||
glViewport(0, 0, w, h);
|
||||
emit ViewportResized(w, h);
|
||||
OnResize();
|
||||
}
|
||||
|
||||
void CEditorGLWidget::mouseMoveEvent(QMouseEvent *pEvent)
|
||||
{
|
||||
if ((!IsMouseInputActive()) && (mButtonsPressed & eLeftButton))
|
||||
emit MouseDrag(pEvent);
|
||||
}
|
||||
|
||||
void CEditorGLWidget::mousePressEvent(QMouseEvent *pEvent)
|
||||
void CBasicViewport::mousePressEvent(QMouseEvent *pEvent)
|
||||
{
|
||||
setFocus();
|
||||
|
||||
|
@ -100,7 +71,11 @@ void CEditorGLWidget::mousePressEvent(QMouseEvent *pEvent)
|
|||
if (pEvent->button() == Qt::RightButton) mButtonsPressed |= eRightButton;
|
||||
|
||||
if (IsMouseInputActive())
|
||||
{
|
||||
SetCursorVisible(false);
|
||||
mMouseMoved = false;
|
||||
mMoveTimer.Restart();
|
||||
}
|
||||
|
||||
// Left click only activates if mouse input is inactive to prevent the user from
|
||||
// clicking on things and creating selection rectangles while the cursor is hidden
|
||||
|
@ -109,13 +84,13 @@ void CEditorGLWidget::mousePressEvent(QMouseEvent *pEvent)
|
|||
if (pEvent->button() == Qt::LeftButton)
|
||||
mButtonsPressed |= eLeftButton;
|
||||
|
||||
emit MouseClick(pEvent);
|
||||
OnMouseClick(pEvent);
|
||||
}
|
||||
|
||||
mLastMousePos = pEvent->globalPos();
|
||||
}
|
||||
|
||||
void CEditorGLWidget::mouseReleaseEvent(QMouseEvent *pEvent)
|
||||
void CBasicViewport::mouseReleaseEvent(QMouseEvent *pEvent)
|
||||
{
|
||||
bool fromMouseInput = IsMouseInputActive();
|
||||
if (pEvent->button() == Qt::LeftButton) mButtonsPressed &= ~eLeftButton;
|
||||
|
@ -126,12 +101,23 @@ void CEditorGLWidget::mouseReleaseEvent(QMouseEvent *pEvent)
|
|||
if (!IsMouseInputActive())
|
||||
SetCursorVisible(true);
|
||||
|
||||
// Emit mouse release event if we didn't just exit mouse input (or regardless on left click)
|
||||
// Run mouse release if we didn't just exit mouse input (or regardless on left click)
|
||||
if (!fromMouseInput || (pEvent->button() == Qt::LeftButton))
|
||||
emit MouseRelease(pEvent);
|
||||
OnMouseRelease(pEvent);
|
||||
}
|
||||
|
||||
void CEditorGLWidget::keyPressEvent(QKeyEvent *pEvent)
|
||||
void CBasicViewport::mouseMoveEvent(QMouseEvent *pEvent)
|
||||
{
|
||||
// todo: draggable selection rectangle
|
||||
}
|
||||
|
||||
void CBasicViewport::wheelEvent(QWheelEvent *pEvent)
|
||||
{
|
||||
// Maybe track a "wheel delta" member variable and let CCamera decide what to do with it?
|
||||
mCamera.Zoom(pEvent->angleDelta().y() / 6000.f);
|
||||
}
|
||||
|
||||
void CBasicViewport::keyPressEvent(QKeyEvent *pEvent)
|
||||
{
|
||||
switch (pEvent->key())
|
||||
{
|
||||
|
@ -145,7 +131,7 @@ void CEditorGLWidget::keyPressEvent(QKeyEvent *pEvent)
|
|||
}
|
||||
}
|
||||
|
||||
void CEditorGLWidget::keyReleaseEvent(QKeyEvent *pEvent)
|
||||
void CBasicViewport::keyReleaseEvent(QKeyEvent *pEvent)
|
||||
{
|
||||
switch (pEvent->key())
|
||||
{
|
||||
|
@ -159,13 +145,7 @@ void CEditorGLWidget::keyReleaseEvent(QKeyEvent *pEvent)
|
|||
}
|
||||
}
|
||||
|
||||
void CEditorGLWidget::wheelEvent(QWheelEvent *pEvent)
|
||||
{
|
||||
// Maybe track a "wheel delta" member variable and let CCamera decide what to do with it?
|
||||
mCamera.Zoom(pEvent->angleDelta().y() / 6000.f);
|
||||
}
|
||||
|
||||
void CEditorGLWidget::focusOutEvent(QFocusEvent*)
|
||||
void CBasicViewport::focusOutEvent(QFocusEvent*)
|
||||
{
|
||||
// When the widget loses focus, release all input.
|
||||
mButtonsPressed = 0;
|
||||
|
@ -173,7 +153,14 @@ void CEditorGLWidget::focusOutEvent(QFocusEvent*)
|
|||
SetCursorVisible(true);
|
||||
}
|
||||
|
||||
void CEditorGLWidget::SetCursorState(const QCursor &Cursor)
|
||||
void CBasicViewport::contextMenuEvent(QContextMenuEvent *pEvent)
|
||||
{
|
||||
// Only allow context menu if we aren't exiting mouse input mode.
|
||||
if (!mMouseMoved && (mMoveTimer.Time() < 0.5))
|
||||
ContextMenu(pEvent);
|
||||
}
|
||||
|
||||
void CBasicViewport::SetCursorState(const QCursor &Cursor)
|
||||
{
|
||||
mCursorState = Cursor;
|
||||
|
||||
|
@ -181,7 +168,7 @@ void CEditorGLWidget::SetCursorState(const QCursor &Cursor)
|
|||
setCursor(Cursor);
|
||||
}
|
||||
|
||||
void CEditorGLWidget::SetCursorVisible(bool visible)
|
||||
void CBasicViewport::SetCursorVisible(bool visible)
|
||||
{
|
||||
mCursorVisible = visible;
|
||||
|
||||
|
@ -191,35 +178,35 @@ void CEditorGLWidget::SetCursorVisible(bool visible)
|
|||
setCursor(Qt::BlankCursor);
|
||||
}
|
||||
|
||||
bool CEditorGLWidget::IsCursorVisible()
|
||||
bool CBasicViewport::IsCursorVisible()
|
||||
{
|
||||
return mCursorVisible;
|
||||
}
|
||||
|
||||
bool CEditorGLWidget::IsMouseInputActive()
|
||||
bool CBasicViewport::IsMouseInputActive()
|
||||
{
|
||||
static const int skMoveButtons = eMiddleButton | eRightButton;
|
||||
return ((mButtonsPressed & skMoveButtons) != 0);
|
||||
}
|
||||
|
||||
bool CEditorGLWidget::IsKeyboardInputActive()
|
||||
bool CBasicViewport::IsKeyboardInputActive()
|
||||
{
|
||||
static const int skMoveKeys = eQKey | eWKey | eEKey | eAKey | eSKey | eDKey;
|
||||
return ((mKeysPressed & skMoveKeys) != 0);
|
||||
}
|
||||
|
||||
CCamera& CEditorGLWidget::Camera()
|
||||
CCamera& CBasicViewport::Camera()
|
||||
{
|
||||
return mCamera;
|
||||
}
|
||||
|
||||
CRay CEditorGLWidget::CastRay()
|
||||
CRay CBasicViewport::CastRay()
|
||||
{
|
||||
CVector2f MouseCoords = MouseDeviceCoordinates();
|
||||
return mCamera.CastRay(MouseCoords);
|
||||
}
|
||||
|
||||
CVector2f CEditorGLWidget::MouseDeviceCoordinates()
|
||||
CVector2f CBasicViewport::MouseDeviceCoordinates()
|
||||
{
|
||||
QPoint MousePos = QCursor::pos();
|
||||
QPoint ThisPos = this->mapToGlobal(pos());
|
||||
|
@ -232,10 +219,18 @@ CVector2f CEditorGLWidget::MouseDeviceCoordinates()
|
|||
return Device;
|
||||
}
|
||||
|
||||
|
||||
// ************ PRIVATE ************
|
||||
void CEditorGLWidget::ProcessInput(double DeltaTime)
|
||||
double CBasicViewport::LastRenderDuration()
|
||||
{
|
||||
return mFrameTimer.Time();
|
||||
}
|
||||
|
||||
// ************ PUBLIC SLOTS ************
|
||||
void CBasicViewport::ProcessInput()
|
||||
{
|
||||
// Process camera input
|
||||
double DeltaTime = CTimer::GlobalTime() - mLastDrawTime;
|
||||
mLastDrawTime = CTimer::GlobalTime();
|
||||
|
||||
if (IsMouseInputActive())
|
||||
{
|
||||
float XMovement = (QCursor::pos().x() - mLastMousePos.x()) * 0.01f;
|
||||
|
@ -245,9 +240,42 @@ void CEditorGLWidget::ProcessInput(double DeltaTime)
|
|||
{
|
||||
mCamera.ProcessMouseInput((EKeyInputs) mKeysPressed, (EMouseInputs) mButtonsPressed, XMovement, YMovement);
|
||||
QCursor::setPos(mLastMousePos);
|
||||
mMouseMoved = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (IsKeyboardInputActive())
|
||||
mCamera.ProcessKeyInput((EKeyInputs) mKeysPressed, DeltaTime);
|
||||
|
||||
// Check user input
|
||||
CheckUserInput();
|
||||
}
|
||||
|
||||
void CBasicViewport::Render()
|
||||
{
|
||||
mFrameTimer.Start();
|
||||
update();
|
||||
mFrameTimer.Stop();
|
||||
}
|
||||
|
||||
// ************ PRIVATE ************
|
||||
void CBasicViewport::ProcessInput(double DeltaTime)
|
||||
{
|
||||
}
|
||||
|
||||
void CBasicViewport::DrawAxes()
|
||||
{
|
||||
// Draw 64x64 axes in lower-left corner with 8px margins
|
||||
glViewport(8, height() - 72, 64, 64);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glClear(GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
CGraphics::sMVPBlock.ViewMatrix = CTransform4f::TranslationMatrix(CVector3f(0,2,0)).ToMatrix4f() * mCamera.RotationOnlyViewMatrix();
|
||||
CGraphics::sMVPBlock.ProjectionMatrix = Math::PerspectiveMatrix(mCamera.FieldOfView(), 1.f, 0.1f, 4096.f);
|
||||
CGraphics::UpdateMVPBlock();
|
||||
|
||||
glLineWidth(2.f);
|
||||
CDrawUtil::DrawLine(CVector3f(0,0,0), CVector3f(1,0,0), CColor::skRed); // X
|
||||
CDrawUtil::DrawLine(CVector3f(0,0,0), CVector3f(0,1,0), CColor::skGreen); // Y
|
||||
CDrawUtil::DrawLine(CVector3f(0,0,0), CVector3f(0,0,1), CColor::skBlue); // Z
|
||||
}
|
|
@ -11,34 +11,44 @@
|
|||
#include <Core/CRenderer.h>
|
||||
#include <Resource/CFont.h>
|
||||
#include <Common/CRay.h>
|
||||
#include <Common/CTimer.h>
|
||||
|
||||
class CEditorGLWidget : public QOpenGLWidget
|
||||
class CBasicViewport : public QOpenGLWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
static QTimer sRefreshTimer;
|
||||
protected:
|
||||
// Render
|
||||
CCamera mCamera;
|
||||
QPoint mLastMousePos;
|
||||
CTimer mFrameTimer;
|
||||
double mLastDrawTime;
|
||||
QPoint mLeftClickPoint;
|
||||
int mButtonsPressed; // int container for EMouseInputs flags
|
||||
int mKeysPressed; // int container for EKeyInputs flags
|
||||
|
||||
// Cursor settings
|
||||
QCursor mCursorState;
|
||||
bool mCursorVisible;
|
||||
|
||||
// Input
|
||||
QPoint mLastMousePos;
|
||||
bool mMouseMoved;
|
||||
CTimer mMoveTimer;
|
||||
int mButtonsPressed; // int container for EMouseInputs flags
|
||||
int mKeysPressed; // int container for EKeyInputs flags
|
||||
|
||||
public:
|
||||
explicit CEditorGLWidget(QWidget *pParent = 0);
|
||||
~CEditorGLWidget();
|
||||
explicit CBasicViewport(QWidget *pParent = 0);
|
||||
~CBasicViewport();
|
||||
void initializeGL();
|
||||
void paintGL();
|
||||
void resizeGL(int w, int h);
|
||||
void mouseMoveEvent(QMouseEvent *pEvent);
|
||||
void mousePressEvent(QMouseEvent *pEvent);
|
||||
void mouseReleaseEvent(QMouseEvent *pEvent);
|
||||
void mouseMoveEvent(QMouseEvent *pEvent);
|
||||
void wheelEvent(QWheelEvent *pEvent);
|
||||
void keyPressEvent(QKeyEvent *pEvent);
|
||||
void keyReleaseEvent(QKeyEvent *pEvent);
|
||||
void wheelEvent(QWheelEvent *pEvent);
|
||||
void focusOutEvent(QFocusEvent *pEvent);
|
||||
void contextMenuEvent(QContextMenuEvent *pEvent);
|
||||
|
||||
void SetCursorState(const QCursor& Cursor);
|
||||
void SetCursorVisible(bool visible);
|
||||
bool IsCursorVisible();
|
||||
|
@ -47,18 +57,23 @@ public:
|
|||
CCamera& Camera();
|
||||
CRay CastRay();
|
||||
CVector2f MouseDeviceCoordinates();
|
||||
double LastRenderDuration();
|
||||
|
||||
signals:
|
||||
void ViewportResized(int w, int h);
|
||||
void PreRender();
|
||||
void Render(CCamera& Camera);
|
||||
void PostRender();
|
||||
void MouseClick(QMouseEvent *pEvent);
|
||||
void MouseRelease(QMouseEvent *pEvent);
|
||||
void MouseDrag(QMouseEvent *pEvent);
|
||||
public slots:
|
||||
void ProcessInput();
|
||||
void Render();
|
||||
|
||||
protected slots:
|
||||
virtual void CheckUserInput() {}
|
||||
virtual void Paint() {}
|
||||
virtual void ContextMenu(QContextMenuEvent *pEvent) {}
|
||||
virtual void OnResize() {}
|
||||
virtual void OnMouseClick(QMouseEvent *pEvent) {}
|
||||
virtual void OnMouseRelease(QMouseEvent *pEvent) {}
|
||||
|
||||
private:
|
||||
void ProcessInput(double DeltaTime);
|
||||
void DrawAxes();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -476,7 +476,7 @@ bool CGizmo::TransformFromInput(const CRay& ray, CCamera& camera)
|
|||
|
||||
mDeltaScale = mTotalScale / oldScale;
|
||||
|
||||
if (!mHasTransformed && (scaleAmount != 0.f))
|
||||
if (!mHasTransformed && (scaleAmount != 1.f))
|
||||
mHasTransformed = true;
|
||||
|
||||
return true;
|
||||
|
@ -491,6 +491,11 @@ void CGizmo::EndTransform()
|
|||
mIsTransforming = false;
|
||||
}
|
||||
|
||||
bool CGizmo::IsTransforming()
|
||||
{
|
||||
return mIsTransforming;
|
||||
}
|
||||
|
||||
bool CGizmo::HasTransformed()
|
||||
{
|
||||
return mHasTransformed;
|
||||
|
@ -501,6 +506,11 @@ CGizmo::EGizmoMode CGizmo::Mode()
|
|||
return mMode;
|
||||
}
|
||||
|
||||
ETransformSpace CGizmo::TransformSpace()
|
||||
{
|
||||
return mTransformSpace;
|
||||
}
|
||||
|
||||
CVector3f CGizmo::Position()
|
||||
{
|
||||
return mPosition;
|
||||
|
|
|
@ -41,7 +41,7 @@ class CGizmo : public IRenderable
|
|||
public:
|
||||
enum EGizmoMode
|
||||
{
|
||||
eTranslate, eRotate, eScale
|
||||
eTranslate, eRotate, eScale, eOff
|
||||
};
|
||||
|
||||
enum EGizmoAxes
|
||||
|
@ -68,6 +68,7 @@ private:
|
|||
CVector2f mWrapOffset;
|
||||
bool mEnableCursorWrap;
|
||||
|
||||
// Transform
|
||||
CTransform4f mTransform;
|
||||
CTransform4f mBillboardTransform;
|
||||
CTransform4f mScaledTransform;
|
||||
|
@ -79,6 +80,7 @@ private:
|
|||
bool mFlipScaleY;
|
||||
bool mFlipScaleZ;
|
||||
|
||||
// Delta transform
|
||||
CVector3f mDeltaTranslation;
|
||||
CVector3f mTotalTranslation;
|
||||
CQuaternion mDeltaRotation;
|
||||
|
@ -87,15 +89,16 @@ private:
|
|||
CVector3f mDeltaScale;
|
||||
CVector3f mTotalScale;
|
||||
|
||||
// Transform helpers
|
||||
CPlane mTranslatePlane;
|
||||
CVector3f mTranslateOffset;
|
||||
float mRotateOffset;
|
||||
float mScaleOffset;
|
||||
bool mSetOffset;
|
||||
|
||||
CVector3f mHitPoint;
|
||||
CVector3f mMoveDir;
|
||||
|
||||
// Model parts
|
||||
struct SModelPart
|
||||
{
|
||||
EGizmoAxes modelAxes;
|
||||
|
@ -133,9 +136,11 @@ public:
|
|||
void StartTransform();
|
||||
bool TransformFromInput(const CRay& ray, CCamera& camera);
|
||||
void EndTransform();
|
||||
bool IsTransforming();
|
||||
bool HasTransformed();
|
||||
|
||||
EGizmoMode Mode();
|
||||
ETransformSpace TransformSpace();
|
||||
CVector3f Position();
|
||||
CVector3f DeltaTranslation();
|
||||
CVector3f TotalTranslation();
|
||||
|
|
|
@ -0,0 +1,95 @@
|
|||
#include "CModelEditorViewport.h"
|
||||
#include <Core/CDrawUtil.h>
|
||||
|
||||
CModelEditorViewport::CModelEditorViewport(QWidget *pParent)
|
||||
: CBasicViewport(pParent),
|
||||
mMode(eDrawMesh),
|
||||
mpActiveMaterial(nullptr),
|
||||
mpModelNode(nullptr)
|
||||
{
|
||||
mpRenderer = new CRenderer();
|
||||
mpRenderer->SetViewportSize(width(), height());
|
||||
mpRenderer->SetClearColor(CColor::skBlack);
|
||||
mpRenderer->ToggleGrid(true);
|
||||
}
|
||||
|
||||
CModelEditorViewport::~CModelEditorViewport()
|
||||
{
|
||||
delete mpRenderer;
|
||||
}
|
||||
|
||||
void CModelEditorViewport::SetNode(CModelNode *pNode)
|
||||
{
|
||||
mpModelNode = pNode;
|
||||
}
|
||||
|
||||
void CModelEditorViewport::SetActiveMaterial(CMaterial *pMat)
|
||||
{
|
||||
mpActiveMaterial = pMat;
|
||||
}
|
||||
|
||||
void CModelEditorViewport::SetDrawMode(EDrawMode mode)
|
||||
{
|
||||
mMode = mode;
|
||||
}
|
||||
|
||||
void CModelEditorViewport::SetClearColor(CColor color)
|
||||
{
|
||||
mpRenderer->SetClearColor(color);
|
||||
}
|
||||
|
||||
void CModelEditorViewport::Paint()
|
||||
{
|
||||
mpRenderer->BeginFrame();
|
||||
mCamera.LoadMatrices();
|
||||
|
||||
if (!mpModelNode->Model())
|
||||
CDrawUtil::DrawGrid();
|
||||
|
||||
else if (mMode == eDrawMesh)
|
||||
{
|
||||
CDrawUtil::DrawGrid();
|
||||
mpModelNode->AddToRenderer(mpRenderer);
|
||||
mpRenderer->RenderBuckets(mCamera);
|
||||
}
|
||||
|
||||
else if (mMode == eDrawSphere)
|
||||
{
|
||||
if (!mpActiveMaterial) return;
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
CGraphics::sVertexBlock.COLOR0_Amb = CGraphics::skDefaultAmbientColor.ToVector4f();
|
||||
CGraphics::sMVPBlock.ModelMatrix = CMatrix4f::skIdentity;
|
||||
CGraphics::UpdateMVPBlock();
|
||||
CGraphics::SetDefaultLighting();
|
||||
CGraphics::UpdateLightBlock(); // Note: vertex block is updated by the material
|
||||
mpActiveMaterial->SetCurrent(eEnableUVScroll | eEnableBackfaceCull | eEnableOccluders);
|
||||
|
||||
CDrawUtil::DrawSphere(true);
|
||||
}
|
||||
|
||||
else if (mMode == eDrawSquare)
|
||||
{
|
||||
if (!mpActiveMaterial) return;
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
CGraphics::SetDefaultLighting();
|
||||
CGraphics::UpdateLightBlock();
|
||||
CGraphics::sVertexBlock.COLOR0_Amb = CGraphics::skDefaultAmbientColor.ToVector4f();
|
||||
|
||||
CGraphics::sMVPBlock.ModelMatrix = CMatrix4f::skIdentity;
|
||||
CGraphics::sMVPBlock.ViewMatrix = CMatrix4f::skIdentity;
|
||||
CGraphics::sMVPBlock.ProjectionMatrix = CMatrix4f::skIdentity;
|
||||
CGraphics::UpdateMVPBlock();
|
||||
|
||||
mpActiveMaterial->SetCurrent(eEnableUVScroll | eEnableOccluders);
|
||||
CDrawUtil::DrawSquare();
|
||||
}
|
||||
|
||||
mpRenderer->EndFrame();
|
||||
}
|
||||
|
||||
void CModelEditorViewport::OnResize()
|
||||
{
|
||||
mpRenderer->SetViewportSize(width(), height());
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
#ifndef CMODELEDITORVIEWPORT_H
|
||||
#define CMODELEDITORVIEWPORT_H
|
||||
|
||||
#include "CBasicViewport.h"
|
||||
|
||||
class CModelEditorViewport : public CBasicViewport
|
||||
{
|
||||
public:
|
||||
enum EDrawMode {
|
||||
eDrawMesh, eDrawSphere, eDrawSquare
|
||||
};
|
||||
|
||||
private:
|
||||
EDrawMode mMode;
|
||||
CModelNode *mpModelNode;
|
||||
CMaterial *mpActiveMaterial;
|
||||
CRenderer *mpRenderer;
|
||||
|
||||
public:
|
||||
CModelEditorViewport(QWidget *pParent = 0);
|
||||
~CModelEditorViewport();
|
||||
void SetNode(CModelNode *pNode);
|
||||
void SetActiveMaterial(CMaterial *pMat);
|
||||
void SetDrawMode(EDrawMode mode);
|
||||
void SetClearColor(CColor color);
|
||||
void Paint();
|
||||
void OnResize();
|
||||
};
|
||||
|
||||
#endif // CMODELEDITORVIEWPORT_H
|
|
@ -33,15 +33,13 @@ CModelEditorWindow::CModelEditorWindow(QWidget *parent) :
|
|||
mpCurrentPass = nullptr;
|
||||
mIgnoreSignals = false;
|
||||
|
||||
mpRenderer = new CRenderer();
|
||||
mpRenderer->ToggleGrid(true);
|
||||
mpRenderer->SetClearColor(CColor(0.3f, 0.3f, 0.3f, 1.f));
|
||||
ui->Viewport->SetNode(mpCurrentModelNode);
|
||||
ui->Viewport->SetClearColor(CColor(0.3f, 0.3f, 0.3f, 1.f));
|
||||
|
||||
CCamera& Camera = ui->PreviewGLWidget->Camera();
|
||||
Camera.Snap(CVector3f(0, 3, 1));
|
||||
Camera.SetFree();
|
||||
Camera.SetMoveSpeed(0.5f);
|
||||
mDrawMode = eDrawMesh;
|
||||
CCamera& camera = ui->Viewport->Camera();
|
||||
camera.Snap(CVector3f(0, 3, 1));
|
||||
camera.SetFree();
|
||||
camera.SetMoveSpeed(0.5f);
|
||||
|
||||
// UI initialization
|
||||
UpdateAnimParamUI(-1);
|
||||
|
@ -54,8 +52,8 @@ CModelEditorWindow::CModelEditorWindow(QWidget *parent) :
|
|||
ui->ClearColorPicker->setColor(QColor(76, 76, 76, 255));
|
||||
|
||||
// Viewport Signal/Slot setup
|
||||
connect(ui->PreviewGLWidget, SIGNAL(ViewportResized(int,int)), this, SLOT(SetViewportSize(int,int)));
|
||||
connect(ui->PreviewGLWidget, SIGNAL(Render(CCamera&)), this, SLOT(PaintViewport(CCamera&)));
|
||||
connect(&mRefreshTimer, SIGNAL(timeout()), this, SLOT(RefreshViewport()));
|
||||
mRefreshTimer.start(0);
|
||||
|
||||
// Editor UI Signal/Slot setup
|
||||
ui->SetSelectionComboBox->setProperty ("ModelEditorWidgetType", eSetSelectComboBox);
|
||||
|
@ -139,10 +137,15 @@ CModelEditorWindow::CModelEditorWindow(QWidget *parent) :
|
|||
CModelEditorWindow::~CModelEditorWindow()
|
||||
{
|
||||
delete mpCurrentModelNode;
|
||||
delete mpRenderer;
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void CModelEditorWindow::RefreshViewport()
|
||||
{
|
||||
ui->Viewport->ProcessInput();
|
||||
ui->Viewport->Render();
|
||||
}
|
||||
|
||||
void CModelEditorWindow::SetActiveModel(CModel *pModel)
|
||||
{
|
||||
mpCurrentModelNode->SetModel(pModel);
|
||||
|
@ -194,6 +197,7 @@ void CModelEditorWindow::SetActiveMaterial(int MatIndex)
|
|||
|
||||
u32 SetIndex = ui->SetSelectionComboBox->currentIndex();
|
||||
mpCurrentMat = mpCurrentModel->GetMaterialByIndex(SetIndex, MatIndex);
|
||||
ui->Viewport->SetActiveMaterial(mpCurrentMat);
|
||||
if (!mpCurrentMat) return;
|
||||
//mpCurrentMat->SetTint(CColor(1.f, 0.5f, 0.5f, 1.f));
|
||||
|
||||
|
@ -572,66 +576,6 @@ void CModelEditorWindow::UpdateUI(int Value)
|
|||
}
|
||||
}
|
||||
|
||||
void CModelEditorWindow::PaintViewport(CCamera& Camera)
|
||||
{
|
||||
mpRenderer->BeginFrame();
|
||||
|
||||
Camera.LoadMatrices();
|
||||
|
||||
if (!mpCurrentModel)
|
||||
{
|
||||
CDrawUtil::DrawGrid();
|
||||
}
|
||||
|
||||
else if (mDrawMode == eDrawMesh)
|
||||
{
|
||||
CDrawUtil::DrawGrid();
|
||||
mpCurrentModelNode->AddToRenderer(mpRenderer);
|
||||
mpRenderer->RenderBuckets(Camera);
|
||||
}
|
||||
|
||||
else if (mDrawMode == eDrawSphere)
|
||||
{
|
||||
if (!mpCurrentMat) return;
|
||||
glEnable(GL_CULL_FACE);
|
||||
|
||||
CGraphics::sVertexBlock.COLOR0_Amb = CGraphics::skDefaultAmbientColor.ToVector4f();
|
||||
CGraphics::sMVPBlock.ModelMatrix = CMatrix4f::skIdentity;
|
||||
CGraphics::UpdateMVPBlock();
|
||||
CGraphics::SetDefaultLighting();
|
||||
CGraphics::UpdateLightBlock(); // Note: vertex block is updated by the material
|
||||
mpCurrentMat->SetCurrent(eEnableUVScroll | eEnableBackfaceCull | eEnableOccluders);
|
||||
|
||||
CDrawUtil::DrawSphere(true);
|
||||
}
|
||||
|
||||
else if (mDrawMode == eDrawSquare)
|
||||
{
|
||||
if (!mpCurrentMat) return;
|
||||
glDisable(GL_CULL_FACE);
|
||||
|
||||
CGraphics::SetDefaultLighting();
|
||||
CGraphics::UpdateLightBlock();
|
||||
CGraphics::sVertexBlock.COLOR0_Amb = CGraphics::skDefaultAmbientColor.ToVector4f();
|
||||
|
||||
CGraphics::sMVPBlock.ModelMatrix = CMatrix4f::skIdentity;
|
||||
CGraphics::sMVPBlock.ViewMatrix = CMatrix4f::skIdentity;
|
||||
CGraphics::sMVPBlock.ProjectionMatrix = CMatrix4f::skIdentity;
|
||||
CGraphics::UpdateMVPBlock();
|
||||
|
||||
mpCurrentMat->SetCurrent(eEnableUVScroll | eEnableOccluders);
|
||||
CDrawUtil::DrawSquare();
|
||||
}
|
||||
|
||||
mpRenderer->EndFrame();
|
||||
}
|
||||
|
||||
void CModelEditorWindow::SetViewportSize(int Width, int Height)
|
||||
{
|
||||
mViewportAspectRatio = (float) Width / (float) Height;
|
||||
mpRenderer->SetViewportSize(Width, Height);
|
||||
}
|
||||
|
||||
// ************ PRIVATE ************
|
||||
void CModelEditorWindow::ActivateMatEditUI(bool Active)
|
||||
{
|
||||
|
@ -793,23 +737,23 @@ void CModelEditorWindow::closeEvent(QCloseEvent*)
|
|||
|
||||
void CModelEditorWindow::on_MeshPreviewButton_clicked()
|
||||
{
|
||||
mDrawMode = eDrawMesh;
|
||||
ui->Viewport->SetDrawMode(CModelEditorViewport::eDrawMesh);
|
||||
}
|
||||
|
||||
void CModelEditorWindow::on_SpherePreviewButton_clicked()
|
||||
{
|
||||
mDrawMode = eDrawSphere;
|
||||
ui->Viewport->SetDrawMode(CModelEditorViewport::eDrawSphere);
|
||||
}
|
||||
|
||||
void CModelEditorWindow::on_FlatPreviewButton_clicked()
|
||||
{
|
||||
mDrawMode = eDrawSquare;
|
||||
ui->Viewport->SetDrawMode(CModelEditorViewport::eDrawSquare);
|
||||
}
|
||||
|
||||
void CModelEditorWindow::on_ClearColorPicker_colorChanged(const QColor &Color)
|
||||
{
|
||||
CColor NewColor((u8) Color.red(), (u8) Color.green(), (u8) Color.blue(), 255);
|
||||
mpRenderer->SetClearColor(NewColor);
|
||||
ui->Viewport->SetClearColor(NewColor);
|
||||
}
|
||||
|
||||
void CModelEditorWindow::on_actionImport_triggered()
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
#include <Resource/CFont.h>
|
||||
#include <Resource/model/CModel.h>
|
||||
#include <Scene/CModelNode.h>
|
||||
#include <QTimer>
|
||||
#include "CModelEditorViewport.h"
|
||||
|
||||
namespace Ui {
|
||||
class CModelEditorWindow;
|
||||
|
@ -18,12 +20,7 @@ class CModelEditorWindow : public QMainWindow
|
|||
{
|
||||
Q_OBJECT
|
||||
|
||||
enum EDrawMode {
|
||||
eDrawMesh, eDrawSphere, eDrawSquare
|
||||
};
|
||||
|
||||
Ui::CModelEditorWindow *ui;
|
||||
CRenderer *mpRenderer;
|
||||
CSceneManager *mpScene;
|
||||
QString mOutputFilename;
|
||||
CModel *mpCurrentModel;
|
||||
|
@ -32,8 +29,7 @@ class CModelEditorWindow : public QMainWindow
|
|||
CMaterial *mpCurrentMat;
|
||||
CMaterialPass *mpCurrentPass;
|
||||
bool mIgnoreSignals;
|
||||
EDrawMode mDrawMode;
|
||||
float mViewportAspectRatio;
|
||||
QTimer mRefreshTimer;
|
||||
|
||||
public:
|
||||
explicit CModelEditorWindow(QWidget *parent = 0);
|
||||
|
@ -42,6 +38,7 @@ public:
|
|||
void closeEvent(QCloseEvent *pEvent);
|
||||
|
||||
public slots:
|
||||
void RefreshViewport();
|
||||
void SetActiveMaterial(int MatIndex);
|
||||
void SetActivePass(int PassIndex);
|
||||
void UpdateMaterial();
|
||||
|
@ -52,8 +49,6 @@ public slots:
|
|||
void UpdateMaterial(QColor eColorProperty);
|
||||
void UpdateUI(int Value);
|
||||
void UpdateAnimParamUI(int Mode);
|
||||
void PaintViewport(CCamera& Camera);
|
||||
void SetViewportSize(int Width, int Height);
|
||||
|
||||
private:
|
||||
void ActivateMatEditUI(bool Active);
|
||||
|
|
|
@ -2124,7 +2124,7 @@
|
|||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="CEditorGLWidget" name="PreviewGLWidget" native="true">
|
||||
<widget class="CModelEditorViewport" name="Viewport" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Expanding">
|
||||
<horstretch>250</horstretch>
|
||||
|
@ -2480,6 +2480,11 @@
|
|||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>WDraggableSpinBox</class>
|
||||
<extends>QDoubleSpinBox</extends>
|
||||
<header>WDraggableSpinBox.h</header>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>WColorPicker</class>
|
||||
<extends>QWidget</extends>
|
||||
|
@ -2496,16 +2501,11 @@
|
|||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>CEditorGLWidget</class>
|
||||
<class>CModelEditorViewport</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>CEditorGLWidget.h</header>
|
||||
<header>CModelEditorViewport.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>WDraggableSpinBox</class>
|
||||
<extends>QDoubleSpinBox</extends>
|
||||
<header>WDraggableSpinBox.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources>
|
||||
<include location="../Icons.qrc"/>
|
||||
|
|
|
@ -0,0 +1,230 @@
|
|||
#include "CSceneViewport.h"
|
||||
#include "undo/UndoCommands.h"
|
||||
|
||||
CSceneViewport::CSceneViewport(QWidget *pParent)
|
||||
: CBasicViewport(pParent),
|
||||
mpEditor(nullptr),
|
||||
mpScene(nullptr),
|
||||
mDrawSky(true),
|
||||
mGizmoTransforming(false),
|
||||
mpHoverNode(nullptr),
|
||||
mHoverPoint(CVector3f::skZero)
|
||||
{
|
||||
mpRenderer = new CRenderer();
|
||||
mpRenderer->SetClearColor(CColor::skBlack);
|
||||
mpRenderer->SetViewportSize(width(), height());
|
||||
}
|
||||
|
||||
CSceneViewport::~CSceneViewport()
|
||||
{
|
||||
delete mpRenderer;
|
||||
}
|
||||
|
||||
void CSceneViewport::SetScene(INodeEditor *pEditor, CSceneManager *pScene)
|
||||
{
|
||||
mpEditor = pEditor;
|
||||
mpScene = pScene;
|
||||
}
|
||||
|
||||
void CSceneViewport::SetSkyEnabled(bool b)
|
||||
{
|
||||
mDrawSky = b;
|
||||
}
|
||||
|
||||
CRenderer* CSceneViewport::Renderer()
|
||||
{
|
||||
return mpRenderer;
|
||||
}
|
||||
|
||||
CSceneNode* CSceneViewport::HoverNode()
|
||||
{
|
||||
return mpHoverNode;
|
||||
}
|
||||
|
||||
CVector3f CSceneViewport::HoverPoint()
|
||||
{
|
||||
return mHoverPoint;
|
||||
}
|
||||
|
||||
void CSceneViewport::CheckGizmoInput(const CRay& ray)
|
||||
{
|
||||
CGizmo *pGizmo = mpEditor->Gizmo();
|
||||
|
||||
// Gizmo not transforming: Check for gizmo hover
|
||||
if (!pGizmo->IsTransforming())
|
||||
{
|
||||
if (mpEditor->IsGizmoVisible())
|
||||
mGizmoHovering = pGizmo->CheckSelectedAxes(ray);
|
||||
else
|
||||
mGizmoHovering = false;
|
||||
}
|
||||
|
||||
// Gizmo transforming: Run gizmo input with ray/mouse coords
|
||||
else if (mGizmoTransforming)
|
||||
{
|
||||
bool transformed = pGizmo->TransformFromInput(ray, mCamera);
|
||||
if (transformed) emit GizmoMoved();
|
||||
}
|
||||
|
||||
else mGizmoHovering = false;
|
||||
}
|
||||
|
||||
void CSceneViewport::SceneRayCast(const CRay& ray)
|
||||
{
|
||||
if (mpEditor->Gizmo()->IsTransforming())
|
||||
{
|
||||
ResetHover();
|
||||
return;
|
||||
}
|
||||
|
||||
SRayIntersection result = mpScene->SceneRayCast(ray);
|
||||
|
||||
if (result.Hit)
|
||||
{
|
||||
if (mpHoverNode)
|
||||
mpHoverNode->SetMouseHovering(false);
|
||||
|
||||
mpHoverNode = result.pNode;
|
||||
mpHoverNode->SetMouseHovering(true);
|
||||
mHoverPoint = ray.PointOnRay(result.Distance);
|
||||
}
|
||||
|
||||
else
|
||||
ResetHover();
|
||||
}
|
||||
|
||||
void CSceneViewport::ResetHover()
|
||||
{
|
||||
if (mpHoverNode) mpHoverNode->SetMouseHovering(false);
|
||||
mpHoverNode = nullptr;
|
||||
mHoverPoint = CVector3f::skZero;
|
||||
}
|
||||
|
||||
bool CSceneViewport::IsHoveringGizmo()
|
||||
{
|
||||
return mGizmoHovering;
|
||||
}
|
||||
|
||||
// ************ PROTECTED SLOTS ************
|
||||
void CSceneViewport::CheckUserInput()
|
||||
{
|
||||
if (!underMouse() || IsMouseInputActive())
|
||||
{
|
||||
ResetHover();
|
||||
mGizmoHovering = false;
|
||||
return;
|
||||
}
|
||||
|
||||
CRay ray = CastRay();
|
||||
CheckGizmoInput(ray);
|
||||
|
||||
if (!mpEditor->Gizmo()->IsTransforming())
|
||||
SceneRayCast(ray);
|
||||
}
|
||||
|
||||
void CSceneViewport::Paint()
|
||||
{
|
||||
if (!mpScene) return;
|
||||
|
||||
mpRenderer->BeginFrame();
|
||||
|
||||
if (mDrawSky)
|
||||
{
|
||||
CModel *pSky = mpScene->GetActiveSkybox();
|
||||
if (pSky) mpRenderer->RenderSky(pSky, mCamera);
|
||||
}
|
||||
|
||||
mCamera.LoadMatrices();
|
||||
mpScene->AddSceneToRenderer(mpRenderer);
|
||||
mpRenderer->RenderBuckets(mCamera);
|
||||
mpRenderer->RenderBloom();
|
||||
|
||||
if (mpEditor->IsGizmoVisible())
|
||||
{
|
||||
CGizmo *pGizmo = mpEditor->Gizmo();
|
||||
mCamera.LoadMatrices();
|
||||
|
||||
mpRenderer->ClearDepthBuffer();
|
||||
pGizmo->UpdateForCamera(mCamera);
|
||||
pGizmo->AddToRenderer(mpRenderer);
|
||||
mpRenderer->RenderBuckets(mCamera);
|
||||
}
|
||||
|
||||
mpRenderer->EndFrame();
|
||||
}
|
||||
|
||||
void CSceneViewport::ContextMenu(QContextMenuEvent *pEvent)
|
||||
{
|
||||
}
|
||||
|
||||
void CSceneViewport::OnResize()
|
||||
{
|
||||
mpRenderer->SetViewportSize(width(), height());
|
||||
}
|
||||
|
||||
void CSceneViewport::OnMouseClick(QMouseEvent *pEvent)
|
||||
{
|
||||
bool altPressed = ((pEvent->modifiers() & Qt::AltModifier) != 0);
|
||||
bool ctrlPressed = ((pEvent->modifiers() & Qt::ControlModifier) != 0);
|
||||
|
||||
if (mGizmoHovering && !altPressed && !ctrlPressed)
|
||||
{
|
||||
mGizmoTransforming = true;
|
||||
mpEditor->Gizmo()->StartTransform();
|
||||
mpEditor->BeginGizmoTransform();
|
||||
}
|
||||
}
|
||||
|
||||
void CSceneViewport::OnMouseRelease(QMouseEvent *pEvent)
|
||||
{
|
||||
if (pEvent->button() == Qt::LeftButton)
|
||||
{
|
||||
// Stop gizmo transform
|
||||
if (mGizmoTransforming)
|
||||
{
|
||||
CGizmo *pGizmo = mpEditor->Gizmo();
|
||||
pGizmo->EndTransform();
|
||||
mpEditor->EndGizmoTransform();
|
||||
mGizmoTransforming = false;
|
||||
}
|
||||
|
||||
// Object selection/deselection
|
||||
else
|
||||
{
|
||||
bool validNode = (mpHoverNode && (mpHoverNode->NodeType() != eStaticNode));
|
||||
bool altPressed = ((pEvent->modifiers() & Qt::AltModifier) != 0);
|
||||
bool ctrlPressed = ((pEvent->modifiers() & Qt::ControlModifier) != 0);
|
||||
|
||||
// Alt: Deselect
|
||||
if (altPressed)
|
||||
{
|
||||
if (!validNode)
|
||||
return;
|
||||
|
||||
mpEditor->DeselectNode(mpHoverNode);
|
||||
}
|
||||
|
||||
// Ctrl: Add to selection
|
||||
else if (ctrlPressed)
|
||||
{
|
||||
if (validNode)
|
||||
mpEditor->SelectNode(mpHoverNode);
|
||||
}
|
||||
|
||||
// Neither: clear selection + select
|
||||
else
|
||||
{
|
||||
if (!mGizmoHovering)
|
||||
{
|
||||
if (validNode)
|
||||
mpEditor->ClearAndSelectNode(mpHoverNode);
|
||||
else
|
||||
mpEditor->ClearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
mpEditor->UpdateSelectionUI();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
#ifndef CSCENEVIEWPORT_H
|
||||
#define CSCENEVIEWPORT_H
|
||||
|
||||
#include "CBasicViewport.h"
|
||||
#include "INodeEditor.h"
|
||||
|
||||
class CSceneViewport : public CBasicViewport
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
INodeEditor *mpEditor;
|
||||
CSceneManager *mpScene;
|
||||
CRenderer *mpRenderer;
|
||||
|
||||
// Render settings
|
||||
bool mDrawSky;
|
||||
|
||||
// Scene interaction
|
||||
bool mGizmoHovering;
|
||||
bool mGizmoTransforming;
|
||||
CSceneNode *mpHoverNode;
|
||||
CVector3f mHoverPoint;
|
||||
|
||||
public:
|
||||
CSceneViewport(QWidget *pParent = 0);
|
||||
~CSceneViewport();
|
||||
void SetScene(INodeEditor *pEditor, CSceneManager *pScene);
|
||||
void SetSkyEnabled(bool b);
|
||||
CRenderer* Renderer();
|
||||
CSceneNode* HoverNode();
|
||||
CVector3f HoverPoint();
|
||||
void CheckGizmoInput(const CRay& ray);
|
||||
void SceneRayCast(const CRay& ray);
|
||||
void ResetHover();
|
||||
bool IsHoveringGizmo();
|
||||
|
||||
signals:
|
||||
void GizmoMoved();
|
||||
|
||||
protected slots:
|
||||
void CheckUserInput();
|
||||
void Paint();
|
||||
void ContextMenu(QContextMenuEvent *pEvent);
|
||||
void OnResize();
|
||||
void OnMouseClick(QMouseEvent *pEvent);
|
||||
void OnMouseRelease(QMouseEvent *pEvent);
|
||||
};
|
||||
|
||||
#endif // CSCENEVIEWPORT_H
|
|
@ -1,6 +1,6 @@
|
|||
#include "CWorldEditor.h"
|
||||
#include "ui_CWorldEditor.h"
|
||||
#include "CEditorGLWidget.h"
|
||||
#include "CBasicViewport.h"
|
||||
#include <gtc/matrix_transform.hpp>
|
||||
#include <Core/CDrawUtil.h>
|
||||
#include <iostream>
|
||||
|
@ -10,36 +10,27 @@
|
|||
#include <Core/Log.h>
|
||||
#include "WDraggableSpinBox.h"
|
||||
#include "WVectorEditor.h"
|
||||
#include "undo/UndoCommands.h"
|
||||
|
||||
#include "WorldEditor/CLayerEditor.h"
|
||||
#include "WorldEditor/WModifyTab.h"
|
||||
#include "WorldEditor/WInstancesTab.h"
|
||||
|
||||
CWorldEditor::CWorldEditor(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
INodeEditor(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;
|
||||
mShowGizmo = false;
|
||||
mGizmoHovering = false;
|
||||
mGizmoTransforming = false;
|
||||
mGizmoUIOutdated = true;
|
||||
|
||||
mFrameCount = 0;
|
||||
mFPSTimer.Start();
|
||||
// Start refresh timer
|
||||
connect(&mRefreshTimer, SIGNAL(timeout()), this, SLOT(RefreshViewport()));
|
||||
mRefreshTimer.start(0);
|
||||
|
||||
// Create blank title bar with some space to allow for dragging the dock
|
||||
QWidget *pOldTitleBar = ui->MainDock->titleBarWidget();
|
||||
|
@ -53,38 +44,28 @@ CWorldEditor::CWorldEditor(QWidget *parent) :
|
|||
delete pOldTitleBar;
|
||||
|
||||
// Initialize UI stuff
|
||||
ui->MainViewport->SetScene(this, &mScene);
|
||||
ui->ModifyTabContents->SetEditor(this);
|
||||
ui->InstancesTabContents->SetEditor(this, mpSceneManager);
|
||||
ui->InstancesTabContents->SetEditor(this, &mScene);
|
||||
ui->MainDock->installEventFilter(this);
|
||||
ui->TransformSpinBox->SetOrientation(Qt::Horizontal);
|
||||
ui->TransformSpinBox->layout()->setContentsMargins(0,0,0,0);
|
||||
ui->CamSpeedSpinBox->SetDefaultValue(1.0);
|
||||
ResetHover();
|
||||
|
||||
mTranslateSpace = eWorldTransform;
|
||||
mRotateSpace = eWorldTransform;
|
||||
|
||||
mpTransformSpaceComboBox = new QComboBox(this);
|
||||
mpTransformSpaceComboBox->setMinimumWidth(75);
|
||||
mpTransformSpaceComboBox->addItem("World");
|
||||
mpTransformSpaceComboBox->addItem("Local");
|
||||
ui->MainToolBar->insertWidget(0, mpTransformSpaceComboBox);
|
||||
mpTransformCombo->setMinimumWidth(75);
|
||||
ui->MainToolBar->addActions(mGizmoActions);
|
||||
ui->MainToolBar->addWidget(mpTransformCombo);
|
||||
ui->menuEdit->addActions(mUndoActions);
|
||||
|
||||
// Initialize offscreen actions
|
||||
addAction(ui->ActionIncrementGizmo);
|
||||
addAction(ui->ActionDecrementGizmo);
|
||||
|
||||
// Connect signals and slots
|
||||
connect(ui->TransformSpinBox, SIGNAL(EditingDone(CVector3f)), this, SLOT(OnTransformSpinBoxEdited(CVector3f)));
|
||||
connect(ui->MainViewport, SIGNAL(GizmoMoved()), this, SLOT(OnGizmoMoved()));
|
||||
connect(ui->TransformSpinBox, SIGNAL(ValueChanged(CVector3f)), this, SLOT(OnTransformSpinBoxModified(CVector3f)));
|
||||
connect(mpTransformSpaceComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(SetTransformSpace(int)));
|
||||
connect(ui->TransformSpinBox, SIGNAL(EditingDone(CVector3f)), this, SLOT(OnTransformSpinBoxEdited(CVector3f)));
|
||||
connect(ui->CamSpeedSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnCameraSpeedChange(double)));
|
||||
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*)));
|
||||
connect(ui->MainViewport, SIGNAL(MouseRelease(QMouseEvent*)), this, SLOT(ViewportMouseRelease(QMouseEvent*)));
|
||||
}
|
||||
|
||||
CWorldEditor::~CWorldEditor()
|
||||
|
@ -107,7 +88,7 @@ bool CWorldEditor::eventFilter(QObject *pObj, QEvent *pEvent)
|
|||
|
||||
void CWorldEditor::SetArea(CWorld *pWorld, CGameArea *pArea)
|
||||
{
|
||||
ResetHover();
|
||||
ui->MainViewport->ResetHover();
|
||||
ClearSelection();
|
||||
ui->ModifyTabContents->ClearUI();
|
||||
ui->ModifyTabContents->ClearCachedEditors();
|
||||
|
@ -124,8 +105,8 @@ void CWorldEditor::SetArea(CWorld *pWorld, CGameArea *pArea)
|
|||
mAreaToken = CToken(pArea);
|
||||
mWorldToken = CToken(pWorld);
|
||||
|
||||
mpSceneManager->SetActiveWorld(pWorld);
|
||||
mpSceneManager->SetActiveArea(pArea);
|
||||
mScene.SetActiveWorld(pWorld);
|
||||
mScene.SetActiveArea(pArea);
|
||||
|
||||
// Snap camera to location of area
|
||||
CTransform4f AreaTransform = pArea->GetTransform();
|
||||
|
@ -150,350 +131,21 @@ void CWorldEditor::SetArea(CWorld *pWorld, CGameArea *pArea)
|
|||
ui->InstancesTabContents->SetMaster(pMaster);
|
||||
}
|
||||
|
||||
void CWorldEditor::ViewportRayCast()
|
||||
{
|
||||
if (!ui->MainViewport->IsMouseInputActive())
|
||||
{
|
||||
// Cast ray
|
||||
CVector2f mouseCoords = ui->MainViewport->MouseDeviceCoordinates();
|
||||
CCamera camera = ui->MainViewport->Camera();
|
||||
CRay ray = camera.CastRay(mouseCoords);
|
||||
|
||||
if (!mGizmoTransforming)
|
||||
{
|
||||
// Gizmo hover check
|
||||
if (mShowGizmo && !mSelectedNodes.empty())
|
||||
mGizmoHovering = mGizmo.CheckSelectedAxes(ray);
|
||||
else
|
||||
{
|
||||
mGizmoHovering = false;
|
||||
mGizmo.ResetSelectedAxes();
|
||||
}
|
||||
|
||||
// Scene ray check
|
||||
SRayIntersection Result = mpSceneManager->SceneRayCast(ray);
|
||||
|
||||
if (Result.Hit)
|
||||
{
|
||||
if (mpHoverNode)
|
||||
mpHoverNode->SetMouseHovering(false);
|
||||
|
||||
mpHoverNode = Result.pNode;
|
||||
mpHoverNode->SetMouseHovering(true);
|
||||
|
||||
mHoverPoint = ray.PointOnRay(Result.Distance);
|
||||
}
|
||||
else
|
||||
ResetHover();
|
||||
}
|
||||
else
|
||||
{
|
||||
bool transformed = mGizmo.TransformFromInput(ray, ui->MainViewport->Camera());
|
||||
|
||||
if (transformed)
|
||||
{
|
||||
switch (mGizmo.Mode())
|
||||
{
|
||||
case CGizmo::eTranslate:
|
||||
{
|
||||
CVector3f delta = mGizmo.DeltaTranslation();
|
||||
|
||||
for (auto it = mSelectedNodes.begin(); it != mSelectedNodes.end(); it++)
|
||||
{
|
||||
(*it)->Translate(delta, mTranslateSpace);
|
||||
(*it)->BuildLightList(this->mpArea);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case CGizmo::eRotate:
|
||||
{
|
||||
CQuaternion delta = mGizmo.DeltaRotation();
|
||||
|
||||
for (auto it = mSelectedNodes.begin(); it != mSelectedNodes.end(); it++)
|
||||
(*it)->Rotate(delta, mRotateSpace);
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case CGizmo::eScale:
|
||||
{
|
||||
CVector3f delta = mGizmo.DeltaScale();
|
||||
|
||||
for (auto it = mSelectedNodes.begin(); it != mSelectedNodes.end(); it++)
|
||||
(*it)->Scale(delta);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RecalculateSelectionBounds();
|
||||
mGizmoUIOutdated = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!mGizmoTransforming)
|
||||
{
|
||||
mGizmoHovering = false;
|
||||
mGizmo.ResetSelectedAxes();
|
||||
}
|
||||
ResetHover();
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
bool AltPressed = ((pEvent->modifiers() & Qt::AltModifier) != 0);
|
||||
bool CtrlPressed = ((pEvent->modifiers() & Qt::ControlModifier) != 0);
|
||||
|
||||
if (mGizmoHovering && !AltPressed && !CtrlPressed)
|
||||
{
|
||||
mGizmoTransforming = true;
|
||||
mGizmo.StartTransform();
|
||||
}
|
||||
}
|
||||
|
||||
void CWorldEditor::ViewportMouseRelease(QMouseEvent *pEvent)
|
||||
{
|
||||
if (pEvent->button() == Qt::LeftButton)
|
||||
{
|
||||
// Gizmo transform stop
|
||||
if (mGizmoTransforming)
|
||||
{
|
||||
mGizmo.EndTransform();
|
||||
mGizmoTransforming = false;
|
||||
mGizmoUIOutdated = true;
|
||||
}
|
||||
|
||||
// Object selection/deselection
|
||||
else if (!ui->MainViewport->IsMouseInputActive())
|
||||
{
|
||||
bool ValidNode = ((mpHoverNode) && (mpHoverNode->NodeType() != eStaticNode));
|
||||
bool AltPressed = ((pEvent->modifiers() & Qt::AltModifier) != 0);
|
||||
bool CtrlPressed = ((pEvent->modifiers() & Qt::ControlModifier) != 0);
|
||||
|
||||
// Alt pressed - deselect object
|
||||
if (AltPressed)
|
||||
{
|
||||
// No valid node selected - do nothing
|
||||
if (!ValidNode)
|
||||
return;
|
||||
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
// todo: context menu creation on right-click goes here
|
||||
}
|
||||
|
||||
// ************ SLOTS ************
|
||||
void CWorldEditor::ViewportPreRender()
|
||||
{
|
||||
// Perform raycast
|
||||
if (ui->MainViewport->underMouse())
|
||||
ViewportRayCast();
|
||||
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);
|
||||
}
|
||||
|
||||
Camera.LoadMatrices();
|
||||
mpRenderer->RenderBuckets(Camera);
|
||||
mpRenderer->RenderBloom();
|
||||
|
||||
if (mShowGizmo && (mSelectedNodes.size() > 0))
|
||||
{
|
||||
mpRenderer->ClearDepthBuffer();
|
||||
|
||||
Camera.LoadMatrices();
|
||||
mGizmo.UpdateForCamera(Camera);
|
||||
mGizmo.AddToRenderer(mpRenderer);
|
||||
|
||||
mpRenderer->RenderBuckets(Camera);
|
||||
mpRenderer->ClearDepthBuffer();
|
||||
}
|
||||
|
||||
mpRenderer->EndFrame();
|
||||
mFrameTimer.Stop();
|
||||
mFrameCount++;
|
||||
}
|
||||
|
||||
void CWorldEditor::ViewportPostRender()
|
||||
{
|
||||
// Update UI with raycast results
|
||||
UpdateCursor();
|
||||
UpdateStatusBar();
|
||||
|
||||
if (mGizmoUIOutdated) UpdateGizmoUI();
|
||||
}
|
||||
|
||||
void CWorldEditor::SetViewportSize(int Width, int Height)
|
||||
{
|
||||
mpRenderer->SetViewportSize(Width, Height);
|
||||
}
|
||||
|
||||
void CWorldEditor::SetTransformSpace(int space)
|
||||
{
|
||||
if (mGizmo.Mode() == CGizmo::eScale) return;
|
||||
ETransformSpace& transformSpace = (mGizmo.Mode() == CGizmo::eTranslate ? mTranslateSpace : mRotateSpace);
|
||||
|
||||
switch (space)
|
||||
{
|
||||
case 0:
|
||||
transformSpace = eWorldTransform;
|
||||
mGizmo.SetLocalRotation(CQuaternion::skIdentity);
|
||||
break;
|
||||
case 1:
|
||||
transformSpace = eLocalTransform;
|
||||
if (!mSelectedNodes.empty())
|
||||
mGizmo.SetLocalRotation(mSelectedNodes.front()->AbsoluteRotation());
|
||||
break;
|
||||
}
|
||||
|
||||
mGizmo.SetTransformSpace(transformSpace);
|
||||
}
|
||||
|
||||
// ************ 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())
|
||||
{
|
||||
if (mGizmoHovering)
|
||||
CSceneNode *pHoverNode = ui->MainViewport->HoverNode();
|
||||
|
||||
if (ui->MainViewport->IsHoveringGizmo())
|
||||
ui->MainViewport->SetCursorState(Qt::SizeAllCursor);
|
||||
else if ((mpHoverNode) && (mpHoverNode->NodeType() != eStaticNode))
|
||||
else if ((pHoverNode) && (pHoverNode->NodeType() != eStaticNode))
|
||||
ui->MainViewport->SetCursorState(Qt::PointingHandCursor);
|
||||
else
|
||||
ui->MainViewport->SetCursorState(Qt::ArrowCursor);
|
||||
|
@ -505,10 +157,15 @@ void CWorldEditor::UpdateStatusBar()
|
|||
// Would be cool to do more frequent status bar updates with more info. Unfortunately, this causes lag.
|
||||
QString StatusText = "";
|
||||
|
||||
if (!mGizmoHovering && mpHoverNode)
|
||||
if (!mGizmoHovering)
|
||||
{
|
||||
if (mpHoverNode->NodeType() != eStaticNode)
|
||||
StatusText = QString::fromStdString(mpHoverNode->Name());
|
||||
if (ui->MainViewport->underMouse())
|
||||
{
|
||||
CSceneNode *pHoverNode = ui->MainViewport->HoverNode();
|
||||
|
||||
if (pHoverNode && (pHoverNode->NodeType() != eStaticNode))
|
||||
StatusText = QString::fromStdString(pHoverNode->Name());
|
||||
}
|
||||
}
|
||||
|
||||
if (ui->statusbar->currentMessage() != StatusText)
|
||||
|
@ -518,15 +175,15 @@ void CWorldEditor::UpdateStatusBar()
|
|||
void CWorldEditor::UpdateSelectionUI()
|
||||
{
|
||||
// Update sidebar
|
||||
ui->ModifyTabContents->GenerateUI(mSelectedNodes);
|
||||
ui->ModifyTabContents->GenerateUI(mSelection);
|
||||
|
||||
// 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());
|
||||
if (mSelection.size() == 1)
|
||||
SelectionText = QString::fromStdString(mSelection.front()->Name());
|
||||
else if (mSelection.size() > 1)
|
||||
SelectionText = QString("%1 objects selected").arg(mSelection.size());
|
||||
|
||||
QFontMetrics Metrics(ui->SelectionInfoLabel->font());
|
||||
SelectionText = Metrics.elidedText(SelectionText, Qt::ElideRight, ui->SelectionInfoFrame->width() - 10);
|
||||
|
@ -552,26 +209,26 @@ void CWorldEditor::UpdateGizmoUI()
|
|||
case CGizmo::eTranslate:
|
||||
if (mGizmoTransforming && mGizmo.HasTransformed())
|
||||
spinBoxValue = mGizmo.TotalTranslation();
|
||||
else if (!mSelectedNodes.empty())
|
||||
spinBoxValue = mSelectedNodes.front()->AbsolutePosition();
|
||||
else if (!mSelection.empty())
|
||||
spinBoxValue = mSelection.front()->AbsolutePosition();
|
||||
break;
|
||||
|
||||
case CGizmo::eRotate:
|
||||
if (mGizmoTransforming && mGizmo.HasTransformed())
|
||||
spinBoxValue = mGizmo.TotalRotation();
|
||||
else if (!mSelectedNodes.empty())
|
||||
spinBoxValue = mSelectedNodes.front()->AbsoluteRotation().ToEuler();
|
||||
else if (!mSelection.empty())
|
||||
spinBoxValue = mSelection.front()->AbsoluteRotation().ToEuler();
|
||||
break;
|
||||
|
||||
case CGizmo::eScale:
|
||||
if (mGizmoTransforming && mGizmo.HasTransformed())
|
||||
spinBoxValue = mGizmo.TotalScale();
|
||||
else if (!mSelectedNodes.empty())
|
||||
spinBoxValue = mSelectedNodes.front()->AbsoluteScale();
|
||||
else if (!mSelection.empty())
|
||||
spinBoxValue = mSelection.front()->AbsoluteScale();
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (!mSelectedNodes.empty()) spinBoxValue = mSelectedNodes.front()->AbsolutePosition();
|
||||
else if (!mSelection.empty()) spinBoxValue = mSelection.front()->AbsolutePosition();
|
||||
|
||||
ui->TransformSpinBox->blockSignals(true);
|
||||
ui->TransformSpinBox->SetValue(spinBoxValue);
|
||||
|
@ -581,26 +238,37 @@ void CWorldEditor::UpdateGizmoUI()
|
|||
// Update gizmo
|
||||
if (!mGizmoTransforming)
|
||||
{
|
||||
if (!mSelectedNodes.empty())
|
||||
mGizmo.SetPosition(mSelectedNodes.front()->AbsolutePosition());
|
||||
|
||||
// Determine transform space
|
||||
ETransformSpace space;
|
||||
if (mGizmo.Mode() == CGizmo::eTranslate) space = mTranslateSpace;
|
||||
else if (mGizmo.Mode() == CGizmo::eRotate) space = mRotateSpace;
|
||||
else space = eLocalTransform;
|
||||
|
||||
// Set gizmo transform space
|
||||
mGizmo.SetTransformSpace(space);
|
||||
|
||||
if (!mSelectedNodes.empty())
|
||||
mGizmo.SetLocalRotation(mSelectedNodes.front()->AbsoluteRotation());
|
||||
// Set gizmo transform
|
||||
if (!mSelection.empty())
|
||||
{
|
||||
mGizmo.SetPosition(mSelection.front()->AbsolutePosition());
|
||||
mGizmo.SetLocalRotation(mSelection.front()->AbsoluteRotation());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mGizmoUIOutdated = false;
|
||||
void CWorldEditor::GizmoModeChanged(CGizmo::EGizmoMode mode)
|
||||
{
|
||||
ui->TransformSpinBox->SetSingleStep( (mode == CGizmo::eRotate ? 1.0 : 0.1) );
|
||||
ui->TransformSpinBox->SetDefaultValue( (mode == CGizmo::eScale ? 1.0 : 0.0) );
|
||||
}
|
||||
|
||||
// ************ ACTIONS ************
|
||||
void CWorldEditor::RefreshViewport()
|
||||
{
|
||||
if (!mGizmo.IsTransforming())
|
||||
mGizmo.ResetSelectedAxes();
|
||||
|
||||
// Process input + update UI
|
||||
ui->MainViewport->ProcessInput();
|
||||
UpdateCursor();
|
||||
UpdateStatusBar();
|
||||
UpdateGizmoUI();
|
||||
|
||||
// Render
|
||||
ui->MainViewport->Render();
|
||||
}
|
||||
|
||||
void CWorldEditor::OnCameraSpeedChange(double speed)
|
||||
{
|
||||
static const double skDefaultSpeed = 1.0;
|
||||
|
@ -613,23 +281,31 @@ void CWorldEditor::OnCameraSpeedChange(double speed)
|
|||
|
||||
void CWorldEditor::OnTransformSpinBoxModified(CVector3f value)
|
||||
{
|
||||
if (mSelection.empty()) return;
|
||||
|
||||
switch (mGizmo.Mode())
|
||||
{
|
||||
case CGizmo::eTranslate:
|
||||
for (auto it = mSelectedNodes.begin(); it != mSelectedNodes.end(); it++)
|
||||
(*it)->SetPosition(value);
|
||||
{
|
||||
CVector3f delta = value - mSelection.front()->AbsolutePosition();
|
||||
mUndoStack.push(new CTranslateNodeCommand(this, mSelection, delta, mTranslateSpace));
|
||||
break;
|
||||
}
|
||||
|
||||
case CGizmo::eRotate:
|
||||
for (auto it = mSelectedNodes.begin(); it != mSelectedNodes.end(); it++)
|
||||
(*it)->SetRotation(value);
|
||||
{
|
||||
CQuaternion delta = CQuaternion::FromEuler(value) * mSelection.front()->AbsoluteRotation().Inverse();
|
||||
mUndoStack.push(new CRotateNodeCommand(this, mSelection, CVector3f::skZero, delta, mRotateSpace));
|
||||
break;
|
||||
}
|
||||
|
||||
case CGizmo::eScale:
|
||||
for (auto it = mSelectedNodes.begin(); it != mSelectedNodes.end(); it++)
|
||||
(*it)->SetScale(value);
|
||||
{
|
||||
CVector3f delta = value / mSelection.front()->AbsoluteScale();
|
||||
mUndoStack.push(new CScaleNodeCommand(this, mSelection, CVector3f::skZero, delta));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RecalculateSelectionBounds();
|
||||
UpdateGizmoUI();
|
||||
|
@ -637,33 +313,42 @@ void CWorldEditor::OnTransformSpinBoxModified(CVector3f value)
|
|||
|
||||
void CWorldEditor::OnTransformSpinBoxEdited(CVector3f)
|
||||
{
|
||||
ui->TransformSpinBox->blockSignals(true);
|
||||
setFocus();
|
||||
ui->TransformSpinBox->blockSignals(false);
|
||||
if (mSelection.empty()) return;
|
||||
|
||||
if (mGizmo.Mode() == CGizmo::eTranslate) mUndoStack.push(CTranslateNodeCommand::End());
|
||||
else if (mGizmo.Mode() == CGizmo::eRotate) mUndoStack.push(CRotateNodeCommand::End());
|
||||
else if (mGizmo.Mode() == CGizmo::eScale) mUndoStack.push(CScaleNodeCommand::End());
|
||||
|
||||
UpdateGizmoUI();
|
||||
}
|
||||
|
||||
// These functions are from "Go to slot" in the designer
|
||||
void CWorldEditor::on_ActionDrawWorld_triggered()
|
||||
{
|
||||
mpSceneManager->SetWorld(ui->ActionDrawWorld->isChecked());
|
||||
mScene.SetWorld(ui->ActionDrawWorld->isChecked());
|
||||
}
|
||||
|
||||
void CWorldEditor::on_ActionDrawCollision_triggered()
|
||||
{
|
||||
mpSceneManager->SetCollision(ui->ActionDrawCollision->isChecked());
|
||||
mScene.SetCollision(ui->ActionDrawCollision->isChecked());
|
||||
}
|
||||
|
||||
void CWorldEditor::on_ActionDrawObjects_triggered()
|
||||
{
|
||||
mpSceneManager->SetObjects(ui->ActionDrawObjects->isChecked());
|
||||
mScene.SetObjects(ui->ActionDrawObjects->isChecked());
|
||||
}
|
||||
|
||||
void CWorldEditor::on_ActionDrawLights_triggered()
|
||||
{
|
||||
mpSceneManager->SetLights(ui->ActionDrawLights->isChecked());
|
||||
mScene.SetLights(ui->ActionDrawLights->isChecked());
|
||||
}
|
||||
|
||||
void CWorldEditor::on_ActionDrawSky_triggered()
|
||||
{
|
||||
mDrawSky = ui->ActionDrawSky->isChecked();
|
||||
ui->MainViewport->SetSkyEnabled(ui->ActionDrawSky->isChecked());
|
||||
}
|
||||
|
||||
void CWorldEditor::on_ActionNoLighting_triggered()
|
||||
|
@ -692,7 +377,7 @@ void CWorldEditor::on_ActionWorldLighting_triggered()
|
|||
|
||||
void CWorldEditor::on_ActionNoBloom_triggered()
|
||||
{
|
||||
mpRenderer->SetBloom(CRenderer::eNoBloom);
|
||||
ui->MainViewport->Renderer()->SetBloom(CRenderer::eNoBloom);
|
||||
ui->ActionNoBloom->setChecked(true);
|
||||
ui->ActionBloomMaps->setChecked(false);
|
||||
ui->ActionFakeBloom->setChecked(false);
|
||||
|
@ -701,7 +386,7 @@ void CWorldEditor::on_ActionNoBloom_triggered()
|
|||
|
||||
void CWorldEditor::on_ActionBloomMaps_triggered()
|
||||
{
|
||||
mpRenderer->SetBloom(CRenderer::eBloomMaps);
|
||||
ui->MainViewport->Renderer()->SetBloom(CRenderer::eBloomMaps);
|
||||
ui->ActionNoBloom->setChecked(false);
|
||||
ui->ActionBloomMaps->setChecked(true);
|
||||
ui->ActionFakeBloom->setChecked(false);
|
||||
|
@ -710,7 +395,7 @@ void CWorldEditor::on_ActionBloomMaps_triggered()
|
|||
|
||||
void CWorldEditor::on_ActionFakeBloom_triggered()
|
||||
{
|
||||
mpRenderer->SetBloom(CRenderer::eFakeBloom);
|
||||
ui->MainViewport->Renderer()->SetBloom(CRenderer::eFakeBloom);
|
||||
ui->ActionNoBloom->setChecked(false);
|
||||
ui->ActionBloomMaps->setChecked(false);
|
||||
ui->ActionFakeBloom->setChecked(true);
|
||||
|
@ -719,7 +404,7 @@ void CWorldEditor::on_ActionFakeBloom_triggered()
|
|||
|
||||
void CWorldEditor::on_ActionBloom_triggered()
|
||||
{
|
||||
mpRenderer->SetBloom(CRenderer::eBloom);
|
||||
ui->MainViewport->Renderer()->SetBloom(CRenderer::eBloom);
|
||||
ui->ActionNoBloom->setChecked(false);
|
||||
ui->ActionBloomMaps->setChecked(false);
|
||||
ui->ActionFakeBloom->setChecked(false);
|
||||
|
@ -732,17 +417,16 @@ void CWorldEditor::on_ActionZoomOnSelection_triggered()
|
|||
static const float skAreaDistScale = 0.8f;
|
||||
|
||||
CCamera& Camera = ui->MainViewport->Camera();
|
||||
CVector3f CamDir = Camera.GetDirection();
|
||||
CVector3f CamDir = Camera.Direction();
|
||||
CVector3f NewPos;
|
||||
|
||||
// Zoom on selection
|
||||
if (mSelectedNodes.size() != 0)
|
||||
if (mSelection.size() != 0)
|
||||
{
|
||||
CVector3f Min = mSelectionAABox.Min();
|
||||
CVector3f Max = mSelectionAABox.Max();
|
||||
CVector3f Min = mSelectionBounds.Min();
|
||||
CVector3f Max = mSelectionBounds.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));
|
||||
NewPos = mSelectionBounds.Center() + (CamDir * -(Dist * skDistScale));
|
||||
}
|
||||
|
||||
// Zoom on area
|
||||
|
@ -752,7 +436,6 @@ void CWorldEditor::on_ActionZoomOnSelection_triggered()
|
|||
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));
|
||||
}
|
||||
|
||||
|
@ -761,12 +444,12 @@ void CWorldEditor::on_ActionZoomOnSelection_triggered()
|
|||
|
||||
void CWorldEditor::on_ActionDisableBackfaceCull_triggered()
|
||||
{
|
||||
mpRenderer->ToggleBackfaceCull(!ui->ActionDisableBackfaceCull->isChecked());
|
||||
ui->MainViewport->Renderer()->ToggleBackfaceCull(!ui->ActionDisableBackfaceCull->isChecked());
|
||||
}
|
||||
|
||||
void CWorldEditor::on_ActionDisableAlpha_triggered()
|
||||
{
|
||||
mpRenderer->ToggleAlphaDisabled(ui->ActionDisableAlpha->isChecked());
|
||||
ui->MainViewport->Renderer()->ToggleAlphaDisabled(ui->ActionDisableAlpha->isChecked());
|
||||
}
|
||||
|
||||
void CWorldEditor::on_ActionEditLayers_triggered()
|
||||
|
@ -777,94 +460,6 @@ void CWorldEditor::on_ActionEditLayers_triggered()
|
|||
Editor.exec();
|
||||
}
|
||||
|
||||
void CWorldEditor::on_ActionSelectObjects_triggered()
|
||||
{
|
||||
mShowGizmo = false;
|
||||
mGizmoUIOutdated = true;
|
||||
ui->ActionSelectObjects->setChecked(true);
|
||||
ui->ActionTranslate->setChecked(false);
|
||||
ui->ActionRotate->setChecked(false);
|
||||
ui->ActionScale->setChecked(false);
|
||||
|
||||
// Set transform spin box settings
|
||||
ui->TransformSpinBox->SetSingleStep(0.1);
|
||||
ui->TransformSpinBox->SetDefaultValue(0.0);
|
||||
|
||||
// Set transform space combo box
|
||||
mpTransformSpaceComboBox->setEnabled(false);
|
||||
mpTransformSpaceComboBox->blockSignals(true);
|
||||
mpTransformSpaceComboBox->setCurrentIndex(0);
|
||||
mpTransformSpaceComboBox->blockSignals(false);
|
||||
}
|
||||
|
||||
void CWorldEditor::on_ActionTranslate_triggered()
|
||||
{
|
||||
mShowGizmo = true;
|
||||
mGizmoUIOutdated = true;
|
||||
mGizmo.SetMode(CGizmo::eTranslate);
|
||||
mGizmo.SetTransformSpace(mTranslateSpace);
|
||||
ui->ActionSelectObjects->setChecked(false);
|
||||
ui->ActionTranslate->setChecked(true);
|
||||
ui->ActionRotate->setChecked(false);
|
||||
ui->ActionScale->setChecked(false);
|
||||
|
||||
// Set transform spin box settings
|
||||
ui->TransformSpinBox->SetSingleStep(0.1);
|
||||
ui->TransformSpinBox->SetDefaultValue(0.0);
|
||||
|
||||
// Set transform space combo box
|
||||
int index = (mTranslateSpace == eWorldTransform ? 0 : 1);
|
||||
mpTransformSpaceComboBox->setEnabled(true);
|
||||
mpTransformSpaceComboBox->blockSignals(true);
|
||||
mpTransformSpaceComboBox->setCurrentIndex(index);
|
||||
mpTransformSpaceComboBox->blockSignals(false);
|
||||
}
|
||||
|
||||
void CWorldEditor::on_ActionRotate_triggered()
|
||||
{
|
||||
mShowGizmo = true;
|
||||
mGizmoUIOutdated = true;
|
||||
mGizmo.SetMode(CGizmo::eRotate);
|
||||
mGizmo.SetTransformSpace(mRotateSpace);
|
||||
ui->ActionSelectObjects->setChecked(false);
|
||||
ui->ActionTranslate->setChecked(false);
|
||||
ui->ActionRotate->setChecked(true);
|
||||
ui->ActionScale->setChecked(false);
|
||||
|
||||
// Set transform spin box settings
|
||||
ui->TransformSpinBox->SetSingleStep(1.0);
|
||||
ui->TransformSpinBox->SetDefaultValue(0.0);
|
||||
|
||||
// Set transform space combo box
|
||||
int index = (mRotateSpace == eWorldTransform ? 0 : 1);
|
||||
mpTransformSpaceComboBox->setEnabled(true);
|
||||
mpTransformSpaceComboBox->blockSignals(true);
|
||||
mpTransformSpaceComboBox->setCurrentIndex(index);
|
||||
mpTransformSpaceComboBox->blockSignals(false);
|
||||
}
|
||||
|
||||
void CWorldEditor::on_ActionScale_triggered()
|
||||
{
|
||||
mShowGizmo = true;
|
||||
mGizmoUIOutdated = true;
|
||||
mGizmo.SetMode(CGizmo::eScale);
|
||||
mGizmo.SetTransformSpace(eLocalTransform);
|
||||
ui->ActionSelectObjects->setChecked(false);
|
||||
ui->ActionTranslate->setChecked(false);
|
||||
ui->ActionRotate->setChecked(false);
|
||||
ui->ActionScale->setChecked(true);
|
||||
|
||||
// Set transform spin box settings
|
||||
ui->TransformSpinBox->SetSingleStep(0.1);
|
||||
ui->TransformSpinBox->SetDefaultValue(1.0);
|
||||
|
||||
// Set transform space combo box - force to local
|
||||
mpTransformSpaceComboBox->setEnabled(false);
|
||||
mpTransformSpaceComboBox->blockSignals(true);
|
||||
mpTransformSpaceComboBox->setCurrentIndex(1);
|
||||
mpTransformSpaceComboBox->blockSignals(false);
|
||||
}
|
||||
|
||||
void CWorldEditor::on_ActionIncrementGizmo_triggered()
|
||||
{
|
||||
mGizmo.IncrementSize();
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
#ifndef CWORLDEDITOR_H
|
||||
#define CWORLDEDITOR_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QList>
|
||||
#include "INodeEditor.h"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QList>
|
||||
#include <QMainWindow>
|
||||
#include <QTimer>
|
||||
#include <QUndoStack>
|
||||
|
||||
#include "CGizmo.h"
|
||||
#include <Common/CRay.h>
|
||||
|
@ -21,74 +25,38 @@ namespace Ui {
|
|||
class CWorldEditor;
|
||||
}
|
||||
|
||||
class CWorldEditor : public QMainWindow
|
||||
class CWorldEditor : public INodeEditor
|
||||
{
|
||||
Q_OBJECT
|
||||
CRenderer *mpRenderer;
|
||||
CSceneManager *mpSceneManager;
|
||||
CGizmo mGizmo;
|
||||
ETransformSpace mTranslateSpace;
|
||||
ETransformSpace mRotateSpace;
|
||||
CCamera mCamera;
|
||||
CGameArea *mpArea;
|
||||
Ui::CWorldEditor *ui;
|
||||
|
||||
CWorld *mpWorld;
|
||||
CGameArea *mpArea;
|
||||
CToken mAreaToken;
|
||||
CToken mWorldToken;
|
||||
CTimer mFrameTimer;
|
||||
bool mDrawSky;
|
||||
bool mShowGizmo;
|
||||
bool mGizmoHovering;
|
||||
bool mGizmoTransforming;
|
||||
bool mGizmoUIOutdated;
|
||||
|
||||
CVector3f mHoverPoint;
|
||||
CSceneNode *mpHoverNode;
|
||||
std::list<CSceneNode*> mSelectedNodes;
|
||||
CAABox mSelectionAABox;
|
||||
|
||||
QComboBox *mpTransformSpaceComboBox;
|
||||
|
||||
CTimer mFPSTimer;
|
||||
int mFrameCount;
|
||||
QTimer mRefreshTimer;
|
||||
|
||||
public:
|
||||
explicit CWorldEditor(QWidget *parent = 0);
|
||||
~CWorldEditor();
|
||||
bool eventFilter(QObject *pObj, QEvent *pEvent);
|
||||
void SetArea(CWorld *pWorld, CGameArea *pArea);
|
||||
void ViewportRayCast();
|
||||
CRenderer* Renderer();
|
||||
CSceneManager* Scene();
|
||||
CGameArea* ActiveArea();
|
||||
|
||||
// Selection
|
||||
void SelectNode(CSceneNode *pNode);
|
||||
void DeselectNode(CSceneNode *pNode);
|
||||
void ClearSelection();
|
||||
|
||||
public slots:
|
||||
void ViewportPreRender();
|
||||
void ViewportRender(CCamera& Camera);
|
||||
void ViewportPostRender();
|
||||
void ViewportMouseDrag(QMouseEvent *pEvent);
|
||||
void ViewportMouseClick(QMouseEvent *pEvent);
|
||||
void ViewportMouseRelease(QMouseEvent *pEvent);
|
||||
void SetViewportSize(int Width, int Height);
|
||||
void SetTransformSpace(int space);
|
||||
|
||||
private:
|
||||
Ui::CWorldEditor *ui;
|
||||
void RecalculateSelectionBounds();
|
||||
void ResetHover();
|
||||
void UpdateCursor();
|
||||
|
||||
// UI
|
||||
void OnSidebarResize();
|
||||
// Update UI
|
||||
void UpdateGizmoUI();
|
||||
void UpdateSelectionUI();
|
||||
void UpdateStatusBar();
|
||||
void UpdateGizmoUI();
|
||||
|
||||
protected:
|
||||
void GizmoModeChanged(CGizmo::EGizmoMode mode);
|
||||
|
||||
private:
|
||||
void UpdateCursor();
|
||||
void OnSidebarResize();
|
||||
|
||||
private slots:
|
||||
void RefreshViewport();
|
||||
void OnCameraSpeedChange(double speed);
|
||||
void OnTransformSpinBoxModified(CVector3f value);
|
||||
void OnTransformSpinBoxEdited(CVector3f value);
|
||||
|
@ -108,10 +76,6 @@ private slots:
|
|||
void on_ActionDisableBackfaceCull_triggered();
|
||||
void on_ActionDisableAlpha_triggered();
|
||||
void on_ActionEditLayers_triggered();
|
||||
void on_ActionSelectObjects_triggered();
|
||||
void on_ActionTranslate_triggered();
|
||||
void on_ActionRotate_triggered();
|
||||
void on_ActionScale_triggered();
|
||||
void on_ActionIncrementGizmo_triggered();
|
||||
void on_ActionDecrementGizmo_triggered();
|
||||
};
|
||||
|
|
|
@ -31,7 +31,7 @@
|
|||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="CEditorGLWidget" name="MainViewport" native="true">
|
||||
<widget class="CSceneViewport" name="MainViewport" native="true">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Minimum">
|
||||
<horstretch>0</horstretch>
|
||||
|
@ -245,8 +245,6 @@
|
|||
<property name="title">
|
||||
<string>Edit</string>
|
||||
</property>
|
||||
<addaction name="ActionUndo"/>
|
||||
<addaction name="ActionRedo"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuView">
|
||||
<property name="title">
|
||||
|
@ -475,10 +473,6 @@
|
|||
<addaction name="ActionLink"/>
|
||||
<addaction name="ActionUnlink"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="ActionSelectObjects"/>
|
||||
<addaction name="ActionTranslate"/>
|
||||
<addaction name="ActionRotate"/>
|
||||
<addaction name="ActionScale"/>
|
||||
</widget>
|
||||
<action name="ActionOpen">
|
||||
<property name="text">
|
||||
|
@ -490,60 +484,6 @@
|
|||
<string>Save</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="ActionTranslate">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../Icons.qrc">
|
||||
<normaloff>:/icons/EditorAssets/Translate.png</normaloff>:/icons/EditorAssets/Translate.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Translate</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Translate</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+W</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="ActionRotate">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../Icons.qrc">
|
||||
<normaloff>:/icons/EditorAssets/Rotate.png</normaloff>:/icons/EditorAssets/Rotate.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Rotate</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Rotate</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+E</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="ActionScale">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../Icons.qrc">
|
||||
<normaloff>:/icons/EditorAssets/Scale.png</normaloff>:/icons/EditorAssets/Scale.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Scale</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Scale</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+R</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionOpen_model_viewer">
|
||||
<property name="text">
|
||||
<string>Open Model Viewer</string>
|
||||
|
@ -573,22 +513,6 @@
|
|||
<string>Unlink</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="ActionUndo">
|
||||
<property name="text">
|
||||
<string>Undo</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Z</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="ActionRedo">
|
||||
<property name="text">
|
||||
<string>Redo</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Y</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="ActionDrawWorld">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
|
@ -753,27 +677,6 @@
|
|||
<string>Fake Bloom</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="ActionSelectObjects">
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../Icons.qrc">
|
||||
<normaloff>:/icons/EditorAssets/SelectMode.png</normaloff>:/icons/EditorAssets/SelectMode.png</iconset>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Select Objects</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Select Objects</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Q</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="ActionIncrementGizmo">
|
||||
<property name="text">
|
||||
<string>Increment Gizmo Size</string>
|
||||
|
@ -804,12 +707,6 @@
|
|||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>CEditorGLWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>CEditorGLWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>WDraggableSpinBox</class>
|
||||
<extends>QDoubleSpinBox</extends>
|
||||
|
@ -833,6 +730,12 @@
|
|||
<header>WVectorEditor.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
<customwidget>
|
||||
<class>CSceneViewport</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>CSceneViewport.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<tabstops>
|
||||
<tabstop>TabWidget</tabstop>
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
#include <Common/StringUtil.h>
|
||||
#include <Core/CGraphics.h>
|
||||
#include <gtc/matrix_transform.hpp>
|
||||
#include "CEditorGLWidget.h"
|
||||
#include "CBasicViewport.h"
|
||||
|
||||
CWorldEditorWindow::CWorldEditorWindow(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
|
@ -30,13 +30,13 @@ CWorldEditorWindow::CWorldEditorWindow(QWidget *parent) :
|
|||
mViewportKeysPressed = 0;
|
||||
mShouldDrawSky = true;
|
||||
|
||||
connect(ui->CentralGLWidget, SIGNAL(ViewportResized(int,int)), this, SLOT(SetViewportSize(int,int)));
|
||||
/*connect(ui->CentralGLWidget, SIGNAL(ViewportResized(int,int)), this, SLOT(SetViewportSize(int,int)));
|
||||
connect(ui->CentralGLWidget, SIGNAL(PaintViewport(double)), this, SLOT(PaintViewport(double)));
|
||||
connect(ui->CentralGLWidget, SIGNAL(MouseClicked(QMouseEvent*)), this, SLOT(OnViewportRayCast(QMouseEvent*)));
|
||||
connect(ui->CentralGLWidget, SIGNAL(MouseMoved(QMouseEvent*, float, float)), this, SLOT(OnViewportMouseMove(QMouseEvent*, float, float)));
|
||||
connect(ui->CentralGLWidget, SIGNAL(KeyPressed(QKeyEvent*)), this, SLOT(OnViewportKeyPress(QKeyEvent*)));
|
||||
connect(ui->CentralGLWidget, SIGNAL(KeyReleased(QKeyEvent*)), this, SLOT(OnViewportKeyRelease(QKeyEvent*)));
|
||||
connect(ui->CentralGLWidget, SIGNAL(WheelScroll(int)), this, SLOT(OnViewportWheelScroll(int)));
|
||||
connect(ui->CentralGLWidget, SIGNAL(WheelScroll(int)), this, SLOT(OnViewportWheelScroll(int)));*/
|
||||
}
|
||||
|
||||
CWorldEditorWindow::~CWorldEditorWindow()
|
||||
|
|
|
@ -28,7 +28,7 @@
|
|||
<number>0</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="CEditorGLWidget" name="CentralGLWidget" native="true"/>
|
||||
<widget class="QWidget" name="CentralGLWidget" native="true"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
|
@ -133,8 +133,8 @@
|
|||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>294</width>
|
||||
<height>654</height>
|
||||
<width>272</width>
|
||||
<height>330</height>
|
||||
</rect>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
|
@ -447,14 +447,6 @@
|
|||
</property>
|
||||
</action>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>CEditorGLWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header>CEditorGLWidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
|
|
@ -0,0 +1,272 @@
|
|||
#include "INodeEditor.h"
|
||||
#include "undo/UndoCommands.h"
|
||||
|
||||
INodeEditor::INodeEditor(QWidget *pParent)
|
||||
: QMainWindow(pParent),
|
||||
mShowGizmo(false),
|
||||
mGizmoHovering(false),
|
||||
mGizmoTransforming(false),
|
||||
mTranslateSpace(eWorldTransform),
|
||||
mRotateSpace(eWorldTransform)
|
||||
{
|
||||
// Create undo actions
|
||||
QAction *pUndoAction = mUndoStack.createUndoAction(this);
|
||||
QAction *pRedoAction = mUndoStack.createRedoAction(this);
|
||||
pUndoAction->setShortcut(QKeySequence("Ctrl+Z"));
|
||||
pRedoAction->setShortcut(QKeySequence("Ctrl+Y"));
|
||||
mUndoActions.push_back(pUndoAction);
|
||||
mUndoActions.push_back(pRedoAction);
|
||||
|
||||
// Create gizmo actions
|
||||
mGizmoActions.append(new QAction(QIcon(":/icons/EditorAssets/SelectMode.png"), "Select Objects", this));
|
||||
mGizmoActions.append(new QAction(QIcon(":/icons/EditorAssets/Translate.png"), "Translate", this));
|
||||
mGizmoActions.append(new QAction(QIcon(":/icons/EditorAssets/Rotate.png"), "Rotate", this));
|
||||
mGizmoActions.append(new QAction(QIcon(":/icons/EditorAssets/Scale.png"), "Scale", this));
|
||||
|
||||
mGizmoActions[0]->setShortcut(QKeySequence("Ctrl+Q"));
|
||||
mGizmoActions[1]->setShortcut(QKeySequence("Ctrl+W"));
|
||||
mGizmoActions[2]->setShortcut(QKeySequence("Ctrl+E"));
|
||||
mGizmoActions[3]->setShortcut(QKeySequence("Ctrl+R"));
|
||||
|
||||
mpGizmoGroup = new QActionGroup(this);
|
||||
|
||||
foreach (QAction *pAction, mGizmoActions)
|
||||
{
|
||||
pAction->setCheckable(true);
|
||||
mpGizmoGroup->addAction(pAction);
|
||||
}
|
||||
|
||||
mGizmoActions[0]->setChecked(true);
|
||||
|
||||
// Create transform combo box
|
||||
mpTransformCombo = new QComboBox(this);
|
||||
mpTransformCombo->addItem("World");
|
||||
mpTransformCombo->addItem("Local");
|
||||
|
||||
// Connect signals and slots
|
||||
connect(mGizmoActions[0], SIGNAL(triggered()), this, SLOT(OnSelectObjectsTriggered()));
|
||||
connect(mGizmoActions[1], SIGNAL(triggered()), this, SLOT(OnTranslateTriggered()));
|
||||
connect(mGizmoActions[2], SIGNAL(triggered()), this, SLOT(OnRotateTriggered()));
|
||||
connect(mGizmoActions[3], SIGNAL(triggered()), this, SLOT(OnScaleTriggered()));
|
||||
connect(mpTransformCombo, SIGNAL(currentIndexChanged(int)), this, SLOT(OnTransformSpaceChanged(int)));
|
||||
}
|
||||
|
||||
INodeEditor::~INodeEditor()
|
||||
{
|
||||
}
|
||||
|
||||
QUndoStack* INodeEditor::UndoStack()
|
||||
{
|
||||
return &mUndoStack;
|
||||
}
|
||||
|
||||
CSceneManager* INodeEditor::Scene()
|
||||
{
|
||||
return &mScene;
|
||||
}
|
||||
|
||||
CGizmo* INodeEditor::Gizmo()
|
||||
{
|
||||
return &mGizmo;
|
||||
}
|
||||
|
||||
bool INodeEditor::IsGizmoVisible()
|
||||
{
|
||||
return (mShowGizmo && !mSelection.empty());
|
||||
}
|
||||
|
||||
void INodeEditor::BeginGizmoTransform()
|
||||
{
|
||||
mGizmoTransforming = true;
|
||||
|
||||
foreach (QAction *pAction, mGizmoActions)
|
||||
pAction->setEnabled(false);
|
||||
}
|
||||
|
||||
void INodeEditor::EndGizmoTransform()
|
||||
{
|
||||
mGizmoTransforming = false;
|
||||
|
||||
foreach (QAction *pAction, mGizmoActions)
|
||||
pAction->setEnabled(true);
|
||||
|
||||
if (mGizmo.Mode() == CGizmo::eTranslate)
|
||||
mUndoStack.push(CTranslateNodeCommand::End());
|
||||
else if (mGizmo.Mode() == CGizmo::eRotate)
|
||||
mUndoStack.push(CRotateNodeCommand::End());
|
||||
else if (mGizmo.Mode() == CGizmo::eScale)
|
||||
mUndoStack.push(CScaleNodeCommand::End());
|
||||
}
|
||||
|
||||
ETransformSpace INodeEditor::CurrentTransformSpace()
|
||||
{
|
||||
switch (mGizmo.Mode())
|
||||
{
|
||||
case CGizmo::eTranslate: return mTranslateSpace;
|
||||
case CGizmo::eRotate: return mRotateSpace;
|
||||
case CGizmo::eScale: return eLocalTransform;
|
||||
default: return eWorldTransform;
|
||||
}
|
||||
}
|
||||
|
||||
void INodeEditor::RecalculateSelectionBounds()
|
||||
{
|
||||
mSelectionBounds = CAABox::skInfinite;
|
||||
|
||||
foreach (CSceneNode *pNode, mSelection)
|
||||
ExpandSelectionBounds(pNode);
|
||||
}
|
||||
|
||||
void INodeEditor::ExpandSelectionBounds(CSceneNode *pNode)
|
||||
{
|
||||
mSelectionBounds.ExpandBounds(pNode->AABox());
|
||||
|
||||
if (pNode->NodeType() == eScriptNode)
|
||||
{
|
||||
CScriptNode *pScript = static_cast<CScriptNode*>(pNode);
|
||||
|
||||
if (pScript->HasPreviewVolume())
|
||||
mSelectionBounds.ExpandBounds(pScript->PreviewVolumeAABox());
|
||||
}
|
||||
}
|
||||
|
||||
void INodeEditor::SelectNode(CSceneNode *pNode)
|
||||
{
|
||||
if (!pNode->IsSelected())
|
||||
mUndoStack.push(new CSelectNodeCommand(this, pNode, mSelection));
|
||||
}
|
||||
|
||||
void INodeEditor::DeselectNode(CSceneNode *pNode)
|
||||
{
|
||||
if (pNode->IsSelected())
|
||||
mUndoStack.push(new CDeselectNodeCommand(this, pNode, mSelection));
|
||||
}
|
||||
|
||||
void INodeEditor::ClearSelection()
|
||||
{
|
||||
if (!mSelection.empty())
|
||||
mUndoStack.push(new CClearSelectionCommand(this, mSelection));
|
||||
}
|
||||
|
||||
void INodeEditor::ClearAndSelectNode(CSceneNode *pNode)
|
||||
{
|
||||
if (mSelection.empty())
|
||||
mUndoStack.push(new CSelectNodeCommand(this, pNode, mSelection));
|
||||
|
||||
else if ((mSelection.size() == 1) && (mSelection.front() == pNode))
|
||||
return;
|
||||
|
||||
else
|
||||
{
|
||||
mUndoStack.beginMacro("Select");
|
||||
mUndoStack.push(new CClearSelectionCommand(this, mSelection));
|
||||
mUndoStack.push(new CSelectNodeCommand(this, pNode, mSelection));
|
||||
mUndoStack.endMacro();
|
||||
}
|
||||
}
|
||||
|
||||
// ************ PUBLIC SLOTS ************
|
||||
void INodeEditor::OnGizmoMoved()
|
||||
{
|
||||
switch (mGizmo.Mode())
|
||||
{
|
||||
case CGizmo::eTranslate:
|
||||
{
|
||||
CVector3f delta = mGizmo.DeltaTranslation();
|
||||
mUndoStack.push(new CTranslateNodeCommand(this, mSelection, delta, mTranslateSpace));
|
||||
break;
|
||||
}
|
||||
|
||||
case CGizmo::eRotate:
|
||||
{
|
||||
CQuaternion delta = mGizmo.DeltaRotation();
|
||||
mUndoStack.push(new CRotateNodeCommand(this, mSelection, CVector3f::skZero, delta, mRotateSpace));
|
||||
break;
|
||||
}
|
||||
|
||||
case CGizmo::eScale:
|
||||
{
|
||||
CVector3f delta = mGizmo.DeltaScale();
|
||||
mUndoStack.push(new CScaleNodeCommand(this, mSelection, CVector3f::skZero, delta));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
RecalculateSelectionBounds();
|
||||
UpdateGizmoUI();
|
||||
}
|
||||
|
||||
// ************ PRIVATE SLOTS ************
|
||||
void INodeEditor::OnSelectObjectsTriggered()
|
||||
{
|
||||
mGizmo.SetMode(CGizmo::eOff);
|
||||
mGizmo.SetTransformSpace(eWorldTransform);
|
||||
mShowGizmo = false;
|
||||
|
||||
mpTransformCombo->setEnabled(false);
|
||||
mpTransformCombo->blockSignals(true);
|
||||
mpTransformCombo->setCurrentIndex(0);
|
||||
mpTransformCombo->blockSignals(false);
|
||||
|
||||
GizmoModeChanged(CGizmo::eOff);
|
||||
UpdateGizmoUI();
|
||||
}
|
||||
|
||||
void INodeEditor::OnTranslateTriggered()
|
||||
{
|
||||
mGizmo.SetMode(CGizmo::eTranslate);
|
||||
mGizmo.SetTransformSpace(mTranslateSpace);
|
||||
mShowGizmo = true;
|
||||
|
||||
mpTransformCombo->setEnabled(true);
|
||||
mpTransformCombo->blockSignals(true);
|
||||
mpTransformCombo->setCurrentIndex( (mTranslateSpace == eWorldTransform) ? 0 : 1 );
|
||||
mpTransformCombo->blockSignals(false);
|
||||
|
||||
GizmoModeChanged(CGizmo::eTranslate);
|
||||
UpdateGizmoUI();
|
||||
}
|
||||
|
||||
void INodeEditor::OnRotateTriggered()
|
||||
{
|
||||
mGizmo.SetMode(CGizmo::eRotate);
|
||||
mGizmo.SetTransformSpace(mRotateSpace);
|
||||
mShowGizmo = true;
|
||||
|
||||
mpTransformCombo->setEnabled(true);
|
||||
mpTransformCombo->blockSignals(true);
|
||||
mpTransformCombo->setCurrentIndex( (mRotateSpace == eWorldTransform) ? 0 : 1 );
|
||||
mpTransformCombo->blockSignals(false);
|
||||
|
||||
GizmoModeChanged(CGizmo::eRotate);
|
||||
UpdateGizmoUI();
|
||||
}
|
||||
|
||||
void INodeEditor::OnScaleTriggered()
|
||||
{
|
||||
mGizmo.SetMode(CGizmo::eScale);
|
||||
mGizmo.SetTransformSpace(eLocalTransform);
|
||||
mShowGizmo = true;
|
||||
|
||||
mpTransformCombo->setEnabled(false);
|
||||
mpTransformCombo->blockSignals(true);
|
||||
mpTransformCombo->setCurrentIndex(1);
|
||||
mpTransformCombo->blockSignals(false);
|
||||
|
||||
GizmoModeChanged(CGizmo::eScale);
|
||||
UpdateGizmoUI();
|
||||
}
|
||||
|
||||
void INodeEditor::OnTransformSpaceChanged(int spaceIndex)
|
||||
{
|
||||
if ((mGizmo.Mode() == CGizmo::eScale) || (mGizmo.Mode() == CGizmo::eOff)) return;
|
||||
|
||||
ETransformSpace space = (spaceIndex == 0 ? eWorldTransform : eLocalTransform);
|
||||
|
||||
if (mGizmo.Mode() == CGizmo::eTranslate)
|
||||
mTranslateSpace = space;
|
||||
else
|
||||
mRotateSpace = space;
|
||||
|
||||
mGizmo.SetTransformSpace(space);
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
#ifndef INODEEDITOR_H
|
||||
#define INODEEDITOR_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include <QAction>
|
||||
#include <QActionGroup>
|
||||
#include <QComboBox>
|
||||
#include <QList>
|
||||
#include <QUndoStack>
|
||||
|
||||
#include "CGizmo.h"
|
||||
#include <Common/ETransformSpace.h>
|
||||
#include <Core/CSceneManager.h>
|
||||
|
||||
class INodeEditor : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
protected:
|
||||
// Undo stack
|
||||
QUndoStack mUndoStack;
|
||||
QList<QAction*> mUndoActions;
|
||||
|
||||
// Node management
|
||||
CSceneManager mScene;
|
||||
QList<CSceneNode*> mSelection;
|
||||
CAABox mSelectionBounds;
|
||||
|
||||
// Gizmo
|
||||
CGizmo mGizmo;
|
||||
bool mShowGizmo;
|
||||
bool mGizmoHovering;
|
||||
bool mGizmoTransforming;
|
||||
ETransformSpace mTranslateSpace;
|
||||
ETransformSpace mRotateSpace;
|
||||
|
||||
// Gizmo widgets
|
||||
QActionGroup *mpGizmoGroup;
|
||||
QList<QAction*> mGizmoActions;
|
||||
QComboBox *mpTransformCombo;
|
||||
|
||||
public:
|
||||
explicit INodeEditor(QWidget *pParent = 0);
|
||||
virtual ~INodeEditor();
|
||||
QUndoStack* UndoStack();
|
||||
CSceneManager* Scene();
|
||||
CGizmo* Gizmo();
|
||||
bool IsGizmoVisible();
|
||||
void BeginGizmoTransform();
|
||||
void EndGizmoTransform();
|
||||
|
||||
ETransformSpace CurrentTransformSpace();
|
||||
void RecalculateSelectionBounds();
|
||||
void ExpandSelectionBounds(CSceneNode *pNode);
|
||||
void SelectNode(CSceneNode *pNode);
|
||||
void DeselectNode(CSceneNode *pNode);
|
||||
void ClearSelection();
|
||||
void ClearAndSelectNode(CSceneNode *pNode);
|
||||
|
||||
virtual void UpdateGizmoUI() = 0;
|
||||
virtual void UpdateSelectionUI() = 0;
|
||||
|
||||
public slots:
|
||||
void OnGizmoMoved();
|
||||
|
||||
protected:
|
||||
virtual void GizmoModeChanged(CGizmo::EGizmoMode mode) {}
|
||||
|
||||
private slots:
|
||||
void OnSelectObjectsTriggered();
|
||||
void OnTranslateTriggered();
|
||||
void OnRotateTriggered();
|
||||
void OnScaleTriggered();
|
||||
void OnTransformSpaceChanged(int spaceIndex);
|
||||
};
|
||||
|
||||
#endif // INODEEDITOR_H
|
|
@ -154,7 +154,7 @@ void WPropertyEditor::CreateEditor()
|
|||
|
||||
pLineEdit->setText(QString::fromStdString(pStringCast->Get()));
|
||||
pLineEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
|
||||
pLineEdit->setCursorPosition(0);
|
||||
//pLineEdit->setCursorPosition(0);
|
||||
|
||||
mUI.EditorWidget = pLineEdit;
|
||||
break;
|
||||
|
|
|
@ -61,8 +61,6 @@ void WVectorEditor::SetOrientation(Qt::Orientation orientation)
|
|||
mpLayout->addItem(mpZLayout);
|
||||
mpLayout->setContentsMargins(5,5,5,5);
|
||||
setLayout(mpLayout);
|
||||
|
||||
emit
|
||||
}
|
||||
|
||||
void WVectorEditor::SetDefaultValue(double value)
|
||||
|
|
|
@ -38,7 +38,7 @@ void WModifyTab::SetEditor(CWorldEditor *pEditor)
|
|||
mpWorldEditor = pEditor;
|
||||
}
|
||||
|
||||
void WModifyTab::GenerateUI(std::list<CSceneNode*>& Selection)
|
||||
void WModifyTab::GenerateUI(QList<CSceneNode*>& Selection)
|
||||
{
|
||||
WPropertyEditor *pOldEditor = mpCurPropEditor;
|
||||
ClearUI();
|
||||
|
|
|
@ -33,7 +33,7 @@ public:
|
|||
explicit WModifyTab(QWidget *pParent = 0);
|
||||
~WModifyTab();
|
||||
void SetEditor(CWorldEditor *pEditor);
|
||||
void GenerateUI(std::list<CSceneNode*>& Selection);
|
||||
void GenerateUI(QList<CSceneNode*>& Selection);
|
||||
void ClearUI();
|
||||
void ClearCachedEditors();
|
||||
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
#include "CClearSelectionCommand.h"
|
||||
#include "../CWorldEditor.h"
|
||||
|
||||
CClearSelectionCommand::CClearSelectionCommand(INodeEditor *pEditor, QList<CSceneNode*>& selection)
|
||||
: QUndoCommand("Clear Selection"),
|
||||
mpEditor(pEditor),
|
||||
mSelectionState(selection),
|
||||
mpSelection(&selection)
|
||||
{
|
||||
}
|
||||
|
||||
CClearSelectionCommand::~CClearSelectionCommand()
|
||||
{
|
||||
}
|
||||
|
||||
void CClearSelectionCommand::undo()
|
||||
{
|
||||
mpSelection->reserve(mSelectionState.size());
|
||||
|
||||
foreach (CSceneNode *pNode, mSelectionState)
|
||||
{
|
||||
if (!pNode->IsSelected())
|
||||
{
|
||||
pNode->SetSelected(true);
|
||||
mpSelection->push_back(pNode);
|
||||
}
|
||||
}
|
||||
|
||||
mpEditor->RecalculateSelectionBounds();
|
||||
mpEditor->UpdateSelectionUI();
|
||||
}
|
||||
|
||||
void CClearSelectionCommand::redo()
|
||||
{
|
||||
foreach (CSceneNode *pNode, *mpSelection)
|
||||
if (pNode->IsSelected())
|
||||
pNode->SetSelected(false);
|
||||
|
||||
mpSelection->clear();
|
||||
mpEditor->RecalculateSelectionBounds();
|
||||
mpEditor->UpdateSelectionUI();
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#ifndef CCLEARSELECTIONCOMMAND_H
|
||||
#define CCLEARSELECTIONCOMMAND_H
|
||||
|
||||
#include <QUndoCommand>
|
||||
#include "../INodeEditor.h"
|
||||
#include <Scene/CSceneNode.h>
|
||||
|
||||
class CClearSelectionCommand : public QUndoCommand
|
||||
{
|
||||
INodeEditor *mpEditor;
|
||||
QList<CSceneNode*> mSelectionState;
|
||||
QList<CSceneNode*> *mpSelection;
|
||||
public:
|
||||
CClearSelectionCommand(INodeEditor *pEditor, QList<CSceneNode*>& selection);
|
||||
~CClearSelectionCommand();
|
||||
void undo();
|
||||
void redo();
|
||||
};
|
||||
|
||||
#endif // CCLEARSELECTIONCOMMAND_H
|
|
@ -0,0 +1,42 @@
|
|||
#include "CDeselectNodeCommand.h"
|
||||
#include "../CWorldEditor.h"
|
||||
|
||||
CDeselectNodeCommand::CDeselectNodeCommand(INodeEditor *pEditor, CSceneNode *pNode, QList<CSceneNode*>& selection)
|
||||
: QUndoCommand("Deselect"),
|
||||
mpEditor(pEditor),
|
||||
mpNode(pNode),
|
||||
mpSelection(&selection)
|
||||
{
|
||||
}
|
||||
|
||||
void CDeselectNodeCommand::undo()
|
||||
{
|
||||
if (!mpNode->IsSelected())
|
||||
{
|
||||
mpNode->SetSelected(true);
|
||||
mpSelection->push_back(mpNode);
|
||||
}
|
||||
|
||||
mpEditor->ExpandSelectionBounds(mpNode);
|
||||
mpEditor->UpdateSelectionUI();
|
||||
}
|
||||
|
||||
void CDeselectNodeCommand::redo()
|
||||
{
|
||||
if (mpNode->IsSelected())
|
||||
{
|
||||
mpNode->SetSelected(false);
|
||||
|
||||
for (auto it = mpSelection->begin(); it != mpSelection->end(); it++)
|
||||
{
|
||||
if (*it == mpNode)
|
||||
{
|
||||
mpSelection->erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mpEditor->RecalculateSelectionBounds();
|
||||
mpEditor->UpdateSelectionUI();
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef CDESELECTNODECOMMAND_H
|
||||
#define CDESELECTNODECOMMAND_H
|
||||
|
||||
#include <QUndoCommand>
|
||||
#include "../INodeEditor.h"
|
||||
#include <Scene/CSceneNode.h>
|
||||
|
||||
class CDeselectNodeCommand : public QUndoCommand
|
||||
{
|
||||
INodeEditor *mpEditor;
|
||||
CSceneNode *mpNode;
|
||||
QList<CSceneNode*> *mpSelection;
|
||||
public:
|
||||
CDeselectNodeCommand(INodeEditor *pEditor, CSceneNode *pNode, QList<CSceneNode*>& selection);
|
||||
void undo();
|
||||
void redo();
|
||||
};
|
||||
|
||||
#endif // CDESELECTNODECOMMAND_H
|
|
@ -0,0 +1,103 @@
|
|||
#include "CRotateNodeCommand.h"
|
||||
#include "EUndoCommand.h"
|
||||
#include "../CWorldEditor.h"
|
||||
|
||||
CRotateNodeCommand::CRotateNodeCommand()
|
||||
: QUndoCommand("Rotate"),
|
||||
mpEditor(nullptr),
|
||||
mCommandEnded(false)
|
||||
{
|
||||
}
|
||||
|
||||
CRotateNodeCommand::CRotateNodeCommand(INodeEditor *pEditor, const QList<CSceneNode*>& nodes, const CVector3f& pivot, const CQuaternion& delta, ETransformSpace transformSpace)
|
||||
: QUndoCommand("Rotate"),
|
||||
mpEditor(pEditor),
|
||||
mCommandEnded(false)
|
||||
{
|
||||
mNodeList.reserve(nodes.size());
|
||||
|
||||
foreach (CSceneNode *pNode, nodes)
|
||||
{
|
||||
SNodeRotate rotate;
|
||||
rotate.pNode = pNode;
|
||||
rotate.initialPos = pNode->LocalPosition();
|
||||
rotate.initialRot = pNode->LocalRotation();
|
||||
pNode->Rotate(delta, transformSpace);
|
||||
rotate.newPos = pNode->LocalPosition();
|
||||
rotate.newRot = pNode->LocalRotation();
|
||||
mNodeList.push_back(rotate);
|
||||
}
|
||||
}
|
||||
|
||||
CRotateNodeCommand::~CRotateNodeCommand()
|
||||
{
|
||||
}
|
||||
|
||||
int CRotateNodeCommand::id() const
|
||||
{
|
||||
return eRotateNodeCmd;
|
||||
}
|
||||
|
||||
bool CRotateNodeCommand::mergeWith(const QUndoCommand *other)
|
||||
{
|
||||
if (mCommandEnded) return false;
|
||||
|
||||
if (other->id() == eRotateNodeCmd)
|
||||
{
|
||||
const CRotateNodeCommand *pCmd = static_cast<const CRotateNodeCommand*>(other);
|
||||
|
||||
if (pCmd->mCommandEnded)
|
||||
{
|
||||
mCommandEnded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((mpEditor == pCmd->mpEditor) && (mNodeList.size() == pCmd->mNodeList.size()))
|
||||
{
|
||||
for (u32 iNode = 0; iNode < mNodeList.size(); iNode++)
|
||||
{
|
||||
mNodeList[iNode].newPos = pCmd->mNodeList[iNode].newPos;
|
||||
mNodeList[iNode].newRot = pCmd->mNodeList[iNode].newRot;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CRotateNodeCommand::undo()
|
||||
{
|
||||
if (!mpEditor) return;
|
||||
|
||||
foreach (SNodeRotate rotate, mNodeList)
|
||||
{
|
||||
rotate.pNode->SetPosition(rotate.initialPos);
|
||||
rotate.pNode->SetRotation(rotate.initialRot);
|
||||
}
|
||||
|
||||
mpEditor->RecalculateSelectionBounds();
|
||||
mpEditor->UpdateGizmoUI();
|
||||
}
|
||||
|
||||
void CRotateNodeCommand::redo()
|
||||
{
|
||||
if (!mpEditor) return;
|
||||
|
||||
foreach (SNodeRotate rotate, mNodeList)
|
||||
{
|
||||
rotate.pNode->SetPosition(rotate.newPos);
|
||||
rotate.pNode->SetRotation(rotate.newRot);
|
||||
}
|
||||
|
||||
mpEditor->RecalculateSelectionBounds();
|
||||
mpEditor->UpdateGizmoUI();
|
||||
}
|
||||
|
||||
CRotateNodeCommand* CRotateNodeCommand::End()
|
||||
{
|
||||
CRotateNodeCommand *pCmd = new CRotateNodeCommand();
|
||||
pCmd->mCommandEnded = true;
|
||||
return pCmd;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef CROTATENODECOMMAND_H
|
||||
#define CROTATENODECOMMAND_H
|
||||
|
||||
#include <QUndoCommand>
|
||||
#include <QList>
|
||||
#include <Scene/CSceneNode.h>
|
||||
#include "../INodeEditor.h"
|
||||
|
||||
class CRotateNodeCommand : public QUndoCommand
|
||||
{
|
||||
struct SNodeRotate
|
||||
{
|
||||
CSceneNode *pNode;
|
||||
CVector3f initialPos;
|
||||
CQuaternion initialRot;
|
||||
CVector3f newPos;
|
||||
CQuaternion newRot;
|
||||
};
|
||||
QList<SNodeRotate> mNodeList;
|
||||
INodeEditor *mpEditor;
|
||||
bool mCommandEnded;
|
||||
|
||||
public:
|
||||
CRotateNodeCommand();
|
||||
CRotateNodeCommand(INodeEditor *pEditor, const QList<CSceneNode*>& nodes, const CVector3f& pivot, const CQuaternion& delta, ETransformSpace transformSpace);
|
||||
~CRotateNodeCommand();
|
||||
int id() const;
|
||||
bool mergeWith(const QUndoCommand *other);
|
||||
void undo();
|
||||
void redo();
|
||||
static CRotateNodeCommand* End();
|
||||
};
|
||||
|
||||
#endif // CROTATENODECOMMAND_H
|
|
@ -0,0 +1,103 @@
|
|||
#include "CScaleNodeCommand.h"
|
||||
#include "EUndoCommand.h"
|
||||
#include "../CWorldEditor.h"
|
||||
|
||||
CScaleNodeCommand::CScaleNodeCommand()
|
||||
: QUndoCommand("Scale"),
|
||||
mpEditor(nullptr),
|
||||
mCommandEnded(false)
|
||||
{
|
||||
}
|
||||
|
||||
CScaleNodeCommand::CScaleNodeCommand(INodeEditor *pEditor, const QList<CSceneNode*>& nodes, const CVector3f& pivot, const CVector3f& delta)
|
||||
: QUndoCommand("Scale"),
|
||||
mpEditor(pEditor),
|
||||
mCommandEnded(false)
|
||||
{
|
||||
mNodeList.reserve(nodes.size());
|
||||
|
||||
foreach (CSceneNode *pNode, nodes)
|
||||
{
|
||||
SNodeScale scale;
|
||||
scale.pNode = pNode;
|
||||
scale.initialPos = pNode->LocalPosition();
|
||||
scale.initialScale = pNode->LocalScale();
|
||||
pNode->Scale(delta);
|
||||
scale.newPos = pNode->LocalPosition();
|
||||
scale.newScale = pNode->LocalScale();
|
||||
mNodeList.push_back(scale);
|
||||
}
|
||||
}
|
||||
|
||||
CScaleNodeCommand::~CScaleNodeCommand()
|
||||
{
|
||||
}
|
||||
|
||||
int CScaleNodeCommand::id() const
|
||||
{
|
||||
return eScaleNodeCmd;
|
||||
}
|
||||
|
||||
bool CScaleNodeCommand::mergeWith(const QUndoCommand *other)
|
||||
{
|
||||
if (mCommandEnded) return false;
|
||||
|
||||
if (other->id() == eScaleNodeCmd)
|
||||
{
|
||||
const CScaleNodeCommand *pCmd = static_cast<const CScaleNodeCommand*>(other);
|
||||
|
||||
if (pCmd->mCommandEnded)
|
||||
{
|
||||
mCommandEnded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((mpEditor == pCmd->mpEditor) && (mNodeList.size() == pCmd->mNodeList.size()))
|
||||
{
|
||||
for (u32 iNode = 0; iNode < mNodeList.size(); iNode++)
|
||||
{
|
||||
mNodeList[iNode].newPos = pCmd->mNodeList[iNode].newPos;
|
||||
mNodeList[iNode].newScale = pCmd->mNodeList[iNode].newScale;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CScaleNodeCommand::undo()
|
||||
{
|
||||
if (!mpEditor) return;
|
||||
|
||||
foreach (SNodeScale scale, mNodeList)
|
||||
{
|
||||
scale.pNode->SetPosition(scale.initialPos);
|
||||
scale.pNode->SetScale(scale.initialScale);
|
||||
}
|
||||
|
||||
mpEditor->RecalculateSelectionBounds();
|
||||
mpEditor->UpdateGizmoUI();
|
||||
}
|
||||
|
||||
void CScaleNodeCommand::redo()
|
||||
{
|
||||
if (!mpEditor) return;
|
||||
|
||||
foreach (SNodeScale scale, mNodeList)
|
||||
{
|
||||
scale.pNode->SetPosition(scale.newPos);
|
||||
scale.pNode->SetScale(scale.newScale);
|
||||
}
|
||||
|
||||
mpEditor->RecalculateSelectionBounds();
|
||||
mpEditor->UpdateGizmoUI();
|
||||
}
|
||||
|
||||
CScaleNodeCommand* CScaleNodeCommand::End()
|
||||
{
|
||||
CScaleNodeCommand *pCmd = new CScaleNodeCommand();
|
||||
pCmd->mCommandEnded = true;
|
||||
return pCmd;
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
#ifndef CSCALENODECOMMAND_H
|
||||
#define CSCALENODECOMMAND_H
|
||||
|
||||
#include <QUndoCommand>
|
||||
#include <QList>
|
||||
#include <Scene/CSceneNode.h>
|
||||
#include "../INodeEditor.h"
|
||||
|
||||
class CScaleNodeCommand : public QUndoCommand
|
||||
{
|
||||
struct SNodeScale
|
||||
{
|
||||
CSceneNode *pNode;
|
||||
CVector3f initialPos;
|
||||
CVector3f initialScale;
|
||||
CVector3f newPos;
|
||||
CVector3f newScale;
|
||||
};
|
||||
QList<SNodeScale> mNodeList;
|
||||
INodeEditor *mpEditor;
|
||||
bool mCommandEnded;
|
||||
|
||||
public:
|
||||
CScaleNodeCommand();
|
||||
CScaleNodeCommand(INodeEditor *pEditor, const QList<CSceneNode*>& nodes, const CVector3f& pivot, const CVector3f& delta);
|
||||
~CScaleNodeCommand();
|
||||
int id() const;
|
||||
bool mergeWith(const QUndoCommand *other);
|
||||
void undo();
|
||||
void redo();
|
||||
static CScaleNodeCommand* End();
|
||||
};
|
||||
|
||||
#endif // CScaleNODECOMMAND_H
|
|
@ -0,0 +1,42 @@
|
|||
#include "CSelectNodeCommand.h"
|
||||
#include "../CWorldEditor.h"
|
||||
|
||||
CSelectNodeCommand::CSelectNodeCommand(INodeEditor *pEditor, CSceneNode *pNode, QList<CSceneNode*>& selection)
|
||||
: QUndoCommand("Select"),
|
||||
mpEditor(pEditor),
|
||||
mpNode(pNode),
|
||||
mpSelection(&selection)
|
||||
{
|
||||
}
|
||||
|
||||
void CSelectNodeCommand::undo()
|
||||
{
|
||||
if (mpNode->IsSelected())
|
||||
{
|
||||
mpNode->SetSelected(false);
|
||||
|
||||
for (auto it = mpSelection->begin(); it != mpSelection->end(); it++)
|
||||
{
|
||||
if (*it == mpNode)
|
||||
{
|
||||
mpSelection->erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mpEditor->RecalculateSelectionBounds();
|
||||
mpEditor->UpdateSelectionUI();
|
||||
}
|
||||
|
||||
void CSelectNodeCommand::redo()
|
||||
{
|
||||
if (!mpNode->IsSelected())
|
||||
{
|
||||
mpNode->SetSelected(true);
|
||||
mpSelection->push_back(mpNode);
|
||||
}
|
||||
|
||||
mpEditor->ExpandSelectionBounds(mpNode);
|
||||
mpEditor->UpdateSelectionUI();
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef CSELECTNODECOMMAND_H
|
||||
#define CSELECTNODECOMMAND_H
|
||||
|
||||
#include <QUndoCommand>
|
||||
#include "../INodeEditor.h"
|
||||
#include <Scene/CSceneNode.h>
|
||||
|
||||
class CSelectNodeCommand : public QUndoCommand
|
||||
{
|
||||
INodeEditor *mpEditor;
|
||||
CSceneNode *mpNode;
|
||||
QList<CSceneNode*> *mpSelection;
|
||||
public:
|
||||
CSelectNodeCommand(INodeEditor *pEditor, CSceneNode *pNode, QList<CSceneNode*>& selection);
|
||||
void undo();
|
||||
void redo();
|
||||
};
|
||||
|
||||
#endif // CSELECTNODECOMMAND_H
|
|
@ -0,0 +1,92 @@
|
|||
#include "CTranslateNodeCommand.h"
|
||||
#include "EUndoCommand.h"
|
||||
#include "../CWorldEditor.h"
|
||||
|
||||
CTranslateNodeCommand::CTranslateNodeCommand()
|
||||
: QUndoCommand("Translate"),
|
||||
mpEditor(nullptr),
|
||||
mCommandEnded(false)
|
||||
{
|
||||
}
|
||||
|
||||
CTranslateNodeCommand::CTranslateNodeCommand(INodeEditor *pEditor, const QList<CSceneNode*>& nodes, const CVector3f& delta, ETransformSpace transformSpace)
|
||||
: QUndoCommand("Translate"),
|
||||
mpEditor(pEditor),
|
||||
mCommandEnded(false)
|
||||
{
|
||||
mNodeList.reserve(nodes.size());
|
||||
|
||||
foreach (CSceneNode *pNode, nodes)
|
||||
{
|
||||
SNodeTranslate translate;
|
||||
translate.pNode = pNode;
|
||||
translate.initialPos = pNode->LocalPosition();
|
||||
pNode->Translate(delta, transformSpace);
|
||||
translate.newPos = pNode->LocalPosition();
|
||||
mNodeList.push_back(translate);
|
||||
}
|
||||
}
|
||||
|
||||
CTranslateNodeCommand::~CTranslateNodeCommand()
|
||||
{
|
||||
}
|
||||
|
||||
int CTranslateNodeCommand::id() const
|
||||
{
|
||||
return eTranslateNodeCmd;
|
||||
}
|
||||
|
||||
bool CTranslateNodeCommand::mergeWith(const QUndoCommand *other)
|
||||
{
|
||||
if (mCommandEnded) return false;
|
||||
|
||||
if (other->id() == eTranslateNodeCmd)
|
||||
{
|
||||
const CTranslateNodeCommand *pCmd = static_cast<const CTranslateNodeCommand*>(other);
|
||||
|
||||
if (pCmd->mCommandEnded)
|
||||
{
|
||||
mCommandEnded = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if ((mpEditor == pCmd->mpEditor) && (mNodeList.size() == pCmd->mNodeList.size()))
|
||||
{
|
||||
for (u32 iNode = 0; iNode < mNodeList.size(); iNode++)
|
||||
mNodeList[iNode].newPos = pCmd->mNodeList[iNode].newPos;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void CTranslateNodeCommand::undo()
|
||||
{
|
||||
if (!mpEditor) return;
|
||||
|
||||
foreach (SNodeTranslate translate, mNodeList)
|
||||
translate.pNode->SetPosition(translate.initialPos);
|
||||
|
||||
mpEditor->RecalculateSelectionBounds();
|
||||
mpEditor->UpdateGizmoUI();
|
||||
}
|
||||
|
||||
void CTranslateNodeCommand::redo()
|
||||
{
|
||||
if (!mpEditor) return;
|
||||
|
||||
foreach (SNodeTranslate translate, mNodeList)
|
||||
translate.pNode->SetPosition(translate.newPos);
|
||||
|
||||
mpEditor->RecalculateSelectionBounds();
|
||||
mpEditor->UpdateGizmoUI();
|
||||
}
|
||||
|
||||
CTranslateNodeCommand* CTranslateNodeCommand::End()
|
||||
{
|
||||
CTranslateNodeCommand *pCmd = new CTranslateNodeCommand();
|
||||
pCmd->mCommandEnded = true;
|
||||
return pCmd;
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
#ifndef CTRANSLATENODECOMMAND_H
|
||||
#define CTRANSLATENODECOMMAND_H
|
||||
|
||||
#include <QUndoCommand>
|
||||
#include <QList>
|
||||
#include <Scene/CSceneNode.h>
|
||||
#include "../INodeEditor.h"
|
||||
|
||||
class CTranslateNodeCommand : public QUndoCommand
|
||||
{
|
||||
struct SNodeTranslate
|
||||
{
|
||||
CSceneNode *pNode;
|
||||
CVector3f initialPos;
|
||||
CVector3f newPos;
|
||||
};
|
||||
QList<SNodeTranslate> mNodeList;
|
||||
INodeEditor *mpEditor;
|
||||
bool mCommandEnded;
|
||||
|
||||
public:
|
||||
CTranslateNodeCommand();
|
||||
CTranslateNodeCommand(INodeEditor *pEditor, const QList<CSceneNode*>& nodes, const CVector3f& delta, ETransformSpace transformSpace);
|
||||
~CTranslateNodeCommand();
|
||||
int id() const;
|
||||
bool mergeWith(const QUndoCommand *other);
|
||||
void undo();
|
||||
void redo();
|
||||
static CTranslateNodeCommand* End();
|
||||
};
|
||||
|
||||
#endif // CTRANSLATENODECOMMAND_H
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef EUNDOCOMMAND
|
||||
#define EUNDOCOMMAND
|
||||
|
||||
enum EUndoCommand
|
||||
{
|
||||
eTranslateNodeCmd,
|
||||
eRotateNodeCmd,
|
||||
eScaleNodeCmd
|
||||
};
|
||||
|
||||
#endif // EUNDOCOMMAND
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
#ifndef UNDOCOMMANDS
|
||||
#define UNDOCOMMANDS
|
||||
|
||||
#include "CTranslateNodeCommand.h"
|
||||
#include "CRotateNodeCommand.h"
|
||||
#include "CScaleNodeCommand.h"
|
||||
#include "CSelectNodeCommand.h"
|
||||
#include "CDeselectNodeCommand.h"
|
||||
#include "CClearSelectionCommand.h"
|
||||
#include "EUndoCommand.h"
|
||||
|
||||
#endif // UNDOCOMMANDS
|
||||
|
Loading…
Reference in New Issue