Feature additions and improvements for pick mode and the POI -> World editor
This commit is contained in:
parent
5c3a37ca4a
commit
440c3ad484
|
@ -6,6 +6,7 @@
|
|||
enum EKeyInput
|
||||
{
|
||||
eCtrlKey = 0x1,
|
||||
eShiftKey = 0x2,
|
||||
eAltKey = 0x2,
|
||||
eQKey = 0x4,
|
||||
eWKey = 0x8,
|
||||
|
|
|
@ -68,10 +68,6 @@ void CPoiToWorld::RemovePoiMeshMap(u32 PoiID, u32 ModelID)
|
|||
if (*ListIt == ModelID)
|
||||
{
|
||||
pMap->ModelIDs.erase(ListIt);
|
||||
|
||||
if (pMap->ModelIDs.empty())
|
||||
RemovePoi(PoiID);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
#define SRAYINTERSECTION
|
||||
|
||||
#include <Common/types.h>
|
||||
#include <Math/CVector3f.h>
|
||||
|
||||
class CSceneNode;
|
||||
|
||||
|
@ -9,12 +10,15 @@ struct SRayIntersection
|
|||
{
|
||||
bool Hit;
|
||||
float Distance;
|
||||
CVector3f HitPoint;
|
||||
CSceneNode *pNode;
|
||||
u32 ComponentIndex;
|
||||
|
||||
SRayIntersection() {}
|
||||
SRayIntersection(bool _Hit, float _Distance, CSceneNode *_pNode, u32 _ComponentIndex)
|
||||
: Hit(_Hit), Distance(_Distance), pNode(_pNode), ComponentIndex(_ComponentIndex) {}
|
||||
SRayIntersection()
|
||||
: Hit(false), Distance(0.f), HitPoint(CVector3f::skZero), pNode(nullptr), ComponentIndex(-1) {}
|
||||
|
||||
SRayIntersection(bool _Hit, float _Distance, CVector3f _HitPoint, CSceneNode *_pNode, u32 _ComponentIndex)
|
||||
: Hit(_Hit), Distance(_Distance), HitPoint(_HitPoint), pNode(_pNode), ComponentIndex(_ComponentIndex) {}
|
||||
};
|
||||
|
||||
#endif // SRAYINTERSECTION
|
||||
|
|
|
@ -18,7 +18,7 @@ public:
|
|||
inline void RayAABoxIntersectTest(CRayCollisionTester&, const SViewInfo&) {}
|
||||
|
||||
inline SRayIntersection RayNodeIntersectTest(const CRay &, u32, const SViewInfo&) {
|
||||
return SRayIntersection(false, 0.f, nullptr, 0);
|
||||
return SRayIntersection();
|
||||
}
|
||||
|
||||
inline void DrawSelection() {}
|
||||
|
|
|
@ -250,13 +250,15 @@ void CDamageableTriggerExtra::RayAABoxIntersectTest(CRayCollisionTester& Tester,
|
|||
std::pair<bool,float> Result = AABox().IntersectsRay(Ray);
|
||||
|
||||
if (Result.first)
|
||||
{
|
||||
Tester.AddNode(this, -1, Result.second);
|
||||
mCachedRayDistance = Result.second;
|
||||
}
|
||||
}
|
||||
|
||||
SRayIntersection CDamageableTriggerExtra::RayNodeIntersectTest(const CRay& Ray, u32 /*ComponentIndex*/, const SViewInfo& /*ViewInfo*/)
|
||||
{
|
||||
// The bounding box and all other tests already passed in RayAABoxIntersectTest, so we
|
||||
// already know that we have a positive. We just need the distance again.
|
||||
std::pair<bool,float> Result = AABox().IntersectsRay(Ray);
|
||||
return SRayIntersection(true, Result.second, mpParent, -1);
|
||||
// already know that we have a positive.
|
||||
return SRayIntersection(true, mCachedRayDistance, Ray.PointOnRay(mCachedRayDistance), mpParent, -1);
|
||||
}
|
||||
|
|
|
@ -28,6 +28,8 @@ class CDamageableTriggerExtra : public CScriptExtra
|
|||
CMaterial *mpMat;
|
||||
CVector2f mCoordScale;
|
||||
|
||||
float mCachedRayDistance;
|
||||
|
||||
public:
|
||||
explicit CDamageableTriggerExtra(CScriptObject *pInstance, CScene *pScene, CSceneNode *pParent = 0);
|
||||
~CDamageableTriggerExtra();
|
||||
|
|
|
@ -144,6 +144,8 @@ void CBasicViewport::keyPressEvent(QKeyEvent *pEvent)
|
|||
case Qt::Key_S: mKeysPressed |= eSKey; break;
|
||||
case Qt::Key_D: mKeysPressed |= eDKey; break;
|
||||
case Qt::Key_Control: mKeysPressed |= eCtrlKey; break;
|
||||
case Qt::Key_Shift: mKeysPressed |= eShiftKey; break;
|
||||
case Qt::Key_Alt: mKeysPressed |= eAltKey; break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -158,6 +160,8 @@ void CBasicViewport::keyReleaseEvent(QKeyEvent *pEvent)
|
|||
case Qt::Key_S: mKeysPressed &= ~eSKey; break;
|
||||
case Qt::Key_D: mKeysPressed &= ~eDKey; break;
|
||||
case Qt::Key_Control: mKeysPressed &= ~eCtrlKey; break;
|
||||
case Qt::Key_Shift: mKeysPressed &= ~eShiftKey; break;
|
||||
case Qt::Key_Alt: mKeysPressed &= ~eAltKey; break;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -204,13 +208,13 @@ bool CBasicViewport::IsCursorVisible()
|
|||
|
||||
bool CBasicViewport::IsMouseInputActive()
|
||||
{
|
||||
static const int skMoveButtons = eMiddleButton | eRightButton;
|
||||
static const FMouseInputs skMoveButtons = eMiddleButton | eRightButton;
|
||||
return ((mButtonsPressed & skMoveButtons) != 0);
|
||||
}
|
||||
|
||||
bool CBasicViewport::IsKeyboardInputActive()
|
||||
{
|
||||
static const int skMoveKeys = eQKey | eWKey | eEKey | eAKey | eSKey | eDKey;
|
||||
static const FKeyInputs skMoveKeys = eQKey | eWKey | eEKey | eAKey | eSKey | eDKey;
|
||||
return ((mKeysPressed & skMoveKeys) != 0);
|
||||
}
|
||||
|
||||
|
|
|
@ -34,8 +34,8 @@ protected:
|
|||
QPoint mLastMousePos;
|
||||
bool mMouseMoved;
|
||||
CTimer mMoveTimer;
|
||||
int mButtonsPressed; // int container for EMouseInputs flags
|
||||
int mKeysPressed; // int container for EKeyInputs flags
|
||||
FMouseInputs mButtonsPressed;
|
||||
FKeyInputs mKeysPressed;
|
||||
|
||||
public:
|
||||
explicit CBasicViewport(QWidget *pParent = 0);
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
#include <Core/Render/SViewInfo.h>
|
||||
#include <Core/Resource/Script/CScriptLayer.h>
|
||||
#include <Core/Scene/CSceneIterator.h>
|
||||
#include <QApplication>
|
||||
#include <QMenu>
|
||||
|
||||
CSceneViewport::CSceneViewport(QWidget *pParent)
|
||||
|
@ -109,7 +110,7 @@ void CSceneViewport::CheckGizmoInput(const CRay& ray)
|
|||
else mGizmoHovering = false;
|
||||
}
|
||||
|
||||
void CSceneViewport::SceneRayCast(const CRay& ray)
|
||||
void CSceneViewport::SceneRayCast(const CRay& rkRay)
|
||||
{
|
||||
if (mpEditor->Gizmo()->IsTransforming())
|
||||
{
|
||||
|
@ -117,16 +118,16 @@ void CSceneViewport::SceneRayCast(const CRay& ray)
|
|||
return;
|
||||
}
|
||||
|
||||
SRayIntersection result = mpScene->SceneRayCast(ray, mViewInfo);
|
||||
mRayIntersection = mpScene->SceneRayCast(rkRay, mViewInfo);
|
||||
|
||||
if (result.Hit)
|
||||
if (mRayIntersection.Hit)
|
||||
{
|
||||
if (mpHoverNode)
|
||||
mpHoverNode->SetMouseHovering(false);
|
||||
|
||||
mpHoverNode = result.pNode;
|
||||
mpHoverNode = mRayIntersection.pNode;
|
||||
mpHoverNode->SetMouseHovering(true);
|
||||
mHoverPoint = ray.PointOnRay(result.Distance);
|
||||
mHoverPoint = rkRay.PointOnRay(mRayIntersection.Distance);
|
||||
}
|
||||
|
||||
else
|
||||
|
@ -210,6 +211,11 @@ void CSceneViewport::CreateContextMenu()
|
|||
mpContextMenu->addActions(Actions);
|
||||
}
|
||||
|
||||
QMouseEvent CSceneViewport::CreateMouseEvent()
|
||||
{
|
||||
return QMouseEvent(QEvent::MouseMove, mapFromGlobal(QCursor::pos()), Qt::NoButton, qApp->mouseButtons(), qApp->keyboardModifiers());
|
||||
}
|
||||
|
||||
// ************ PROTECTED SLOTS ************
|
||||
void CSceneViewport::CheckUserInput()
|
||||
{
|
||||
|
@ -219,18 +225,24 @@ void CSceneViewport::CheckUserInput()
|
|||
{
|
||||
ResetHover();
|
||||
mGizmoHovering = false;
|
||||
|
||||
if (!MouseActive)
|
||||
return;
|
||||
}
|
||||
|
||||
CRay ray = CastRay();
|
||||
if (MouseActive)
|
||||
{
|
||||
CRay Ray = CastRay();
|
||||
|
||||
if (!mViewInfo.GameMode)
|
||||
CheckGizmoInput(ray);
|
||||
CheckGizmoInput(Ray);
|
||||
|
||||
if (!mpEditor->Gizmo()->IsTransforming())
|
||||
SceneRayCast(ray);
|
||||
SceneRayCast(Ray);
|
||||
}
|
||||
|
||||
else
|
||||
mRayIntersection = SRayIntersection();
|
||||
|
||||
QMouseEvent Event = CreateMouseEvent();
|
||||
emit InputProcessed(mRayIntersection, &Event);
|
||||
}
|
||||
|
||||
void CSceneViewport::Paint()
|
||||
|
@ -346,7 +358,7 @@ void CSceneViewport::OnMouseRelease(QMouseEvent *pEvent)
|
|||
|
||||
// Object selection/deselection
|
||||
else
|
||||
emit ViewportClick(mpHoverNode, pEvent);
|
||||
emit ViewportClick(mRayIntersection, pEvent);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -16,6 +16,7 @@ class CSceneViewport : public CBasicViewport
|
|||
// Scene interaction
|
||||
bool mGizmoHovering;
|
||||
bool mGizmoTransforming;
|
||||
SRayIntersection mRayIntersection;
|
||||
CSceneNode *mpHoverNode;
|
||||
CVector3f mHoverPoint;
|
||||
|
||||
|
@ -54,9 +55,11 @@ public:
|
|||
|
||||
protected:
|
||||
void CreateContextMenu();
|
||||
QMouseEvent CreateMouseEvent();
|
||||
|
||||
signals:
|
||||
void ViewportClick(CSceneNode *pNode, QMouseEvent *pEvent);
|
||||
void InputProcessed(const SRayIntersection& rkIntersect, QMouseEvent *pEvent);
|
||||
void ViewportClick(const SRayIntersection& rkIntersect, QMouseEvent *pEvent);
|
||||
void GizmoMoved();
|
||||
void CameraOrbit();
|
||||
|
||||
|
|
|
@ -209,7 +209,7 @@ const QList<CSceneNode*>& INodeEditor::GetSelection() const
|
|||
return mSelection;
|
||||
}
|
||||
|
||||
void INodeEditor::EnterPickMode(FNodeFlags AllowedNodes, bool ExitOnInvalidPick, bool EmitOnInvalidPick, QCursor Cursor /*= Qt::CrossCursor*/)
|
||||
void INodeEditor::EnterPickMode(FNodeFlags AllowedNodes, bool ExitOnInvalidPick, bool EmitOnInvalidPick, bool EmitHoverOnButtonPress, QCursor Cursor /*= Qt::CrossCursor*/)
|
||||
{
|
||||
// If we're already in pick mode, exit first so the previous caller has a chance to disconnect
|
||||
if (mPickMode)
|
||||
|
@ -219,6 +219,7 @@ void INodeEditor::EnterPickMode(FNodeFlags AllowedNodes, bool ExitOnInvalidPick,
|
|||
mAllowedPickNodes = AllowedNodes;
|
||||
mExitOnInvalidPick = ExitOnInvalidPick;
|
||||
mEmitOnInvalidPick = EmitOnInvalidPick;
|
||||
mEmitOnButtonPress = EmitHoverOnButtonPress;
|
||||
emit PickModeEntered(Cursor);
|
||||
}
|
||||
|
||||
|
@ -263,12 +264,14 @@ void INodeEditor::OnGizmoMoved()
|
|||
}
|
||||
|
||||
// ************ PROTECTED SLOTS ************
|
||||
void INodeEditor::OnViewportClick(CSceneNode *pHoverNode, QMouseEvent *pEvent)
|
||||
void INodeEditor::OnViewportClick(const SRayIntersection& rkRayIntersect, QMouseEvent *pEvent)
|
||||
{
|
||||
CSceneNode *pNode = rkRayIntersect.pNode;
|
||||
|
||||
// Not in pick mode: process node selection/deselection
|
||||
if (!mPickMode)
|
||||
{
|
||||
bool ValidNode = (pHoverNode && (pHoverNode->NodeType() & mSelectionNodeFlags));
|
||||
bool ValidNode = (pNode && (pNode->NodeType() & mSelectionNodeFlags));
|
||||
bool AltPressed = ((pEvent->modifiers() & Qt::AltModifier) != 0);
|
||||
bool CtrlPressed = ((pEvent->modifiers() & Qt::ControlModifier) != 0);
|
||||
|
||||
|
@ -278,14 +281,14 @@ void INodeEditor::OnViewportClick(CSceneNode *pHoverNode, QMouseEvent *pEvent)
|
|||
if (!ValidNode)
|
||||
return;
|
||||
|
||||
DeselectNode(pHoverNode);
|
||||
DeselectNode(pNode);
|
||||
}
|
||||
|
||||
// Ctrl: Add to selection
|
||||
else if (CtrlPressed)
|
||||
{
|
||||
if (ValidNode)
|
||||
SelectNode(pHoverNode);
|
||||
SelectNode(pNode);
|
||||
}
|
||||
|
||||
// Neither: clear selection + select
|
||||
|
@ -294,7 +297,7 @@ void INodeEditor::OnViewportClick(CSceneNode *pHoverNode, QMouseEvent *pEvent)
|
|||
if (!mGizmoHovering)
|
||||
{
|
||||
if (ValidNode)
|
||||
ClearAndSelectNode(pHoverNode);
|
||||
ClearAndSelectNode(pNode);
|
||||
else
|
||||
ClearSelection();
|
||||
}
|
||||
|
@ -306,16 +309,43 @@ void INodeEditor::OnViewportClick(CSceneNode *pHoverNode, QMouseEvent *pEvent)
|
|||
// In pick mode: process node pick
|
||||
else
|
||||
{
|
||||
bool ValidNode = (pHoverNode && (pHoverNode->NodeType() & mAllowedPickNodes));
|
||||
bool ValidNode = (pNode && (pNode->NodeType() & mAllowedPickNodes));
|
||||
|
||||
if (ValidNode || mEmitOnInvalidPick)
|
||||
emit PickModeClick(pHoverNode, pEvent);
|
||||
emit PickModeClick(rkRayIntersect, pEvent);
|
||||
|
||||
if (!ValidNode && mExitOnInvalidPick)
|
||||
ExitPickMode();
|
||||
}
|
||||
}
|
||||
|
||||
void INodeEditor::OnViewportInputProcessed(const SRayIntersection& rkRayIntersect, QMouseEvent *pEvent)
|
||||
{
|
||||
// In pick mode: process node hover
|
||||
if (mPickMode)
|
||||
{
|
||||
CSceneNode *pNode = rkRayIntersect.pNode;
|
||||
bool NewNode = pNode != mpPickHoverNode;
|
||||
|
||||
bool ButtonsChanged = mPickButtons != pEvent->buttons();
|
||||
bool ModifiersChanged = mPickModifiers != pEvent->modifiers();
|
||||
|
||||
if (NewNode || ((ModifiersChanged || ButtonsChanged) && mEmitOnButtonPress))
|
||||
{
|
||||
bool ValidNode = (pNode && (pNode->NodeType() & mAllowedPickNodes));
|
||||
|
||||
if (ValidNode || mEmitOnInvalidPick)
|
||||
emit PickModeHoverChanged(rkRayIntersect, pEvent);
|
||||
else
|
||||
emit PickModeHoverChanged(SRayIntersection(), pEvent);
|
||||
}
|
||||
|
||||
mpPickHoverNode = rkRayIntersect.pNode;
|
||||
mPickButtons = pEvent->buttons();
|
||||
mPickModifiers = pEvent->modifiers();
|
||||
}
|
||||
}
|
||||
|
||||
// ************ PRIVATE ************
|
||||
void INodeEditor::UpdateTransformActionsEnabled()
|
||||
{
|
||||
|
|
|
@ -45,7 +45,11 @@ protected:
|
|||
bool mPickMode;
|
||||
bool mExitOnInvalidPick;
|
||||
bool mEmitOnInvalidPick;
|
||||
bool mEmitOnButtonPress;
|
||||
FNodeFlags mAllowedPickNodes;
|
||||
CSceneNode *mpPickHoverNode;
|
||||
Qt::MouseButtons mPickButtons;
|
||||
Qt::KeyboardModifiers mPickModifiers;
|
||||
|
||||
public:
|
||||
explicit INodeEditor(QWidget *pParent = 0);
|
||||
|
@ -70,7 +74,7 @@ public:
|
|||
bool HasSelection() const;
|
||||
const QList<CSceneNode*>& GetSelection() const;
|
||||
|
||||
void EnterPickMode(FNodeFlags AllowedNodes, bool ExitOnInvalidPick, bool EmitOnInvalidPick, QCursor Cursor = Qt::CrossCursor);
|
||||
void EnterPickMode(FNodeFlags AllowedNodes, bool ExitOnInvalidPick, bool EmitOnInvalidPick, bool EmitHoverOnButtonPress, QCursor Cursor = Qt::CrossCursor);
|
||||
void ExitPickMode();
|
||||
|
||||
signals:
|
||||
|
@ -79,7 +83,8 @@ signals:
|
|||
|
||||
void PickModeEntered(QCursor Cursor);
|
||||
void PickModeExited();
|
||||
void PickModeClick(CSceneNode *pNode, QMouseEvent *pEvent);
|
||||
void PickModeClick(const SRayIntersection& rkRayIntersect, QMouseEvent *pEvent);
|
||||
void PickModeHoverChanged(const SRayIntersection& rkRayIntersect, QMouseEvent *pEvent);
|
||||
|
||||
public slots:
|
||||
void OnGizmoMoved();
|
||||
|
@ -90,7 +95,8 @@ protected:
|
|||
virtual void GizmoModeChanged(CGizmo::EGizmoMode /*mode*/) {}
|
||||
|
||||
protected slots:
|
||||
void OnViewportClick(CSceneNode *pHoverNode, QMouseEvent *pEvent);
|
||||
void OnViewportClick(const SRayIntersection& rkRayIntersect, QMouseEvent *pEvent);
|
||||
void OnViewportInputProcessed(const SRayIntersection& rkRayIntersect, QMouseEvent *pEvent);
|
||||
|
||||
private:
|
||||
void UpdateTransformActionsEnabled();
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
const CColor CPoiMapEditDialog::skNormalColor(0.137255f, 0.184314f, 0.776471f, 0.5f);
|
||||
const CColor CPoiMapEditDialog::skImportantColor(0.721569f, 0.066667f, 0.066667f, 0.5f);
|
||||
const CColor CPoiMapEditDialog::skHoverColor(0.047059f, 0.2f, 0.003922f, 0.5f);
|
||||
|
||||
CPoiMapEditDialog::CPoiMapEditDialog(CWorldEditor *pEditor, QWidget *parent)
|
||||
: QMainWindow(parent)
|
||||
|
@ -20,12 +21,16 @@ CPoiMapEditDialog::CPoiMapEditDialog(CWorldEditor *pEditor, QWidget *parent)
|
|||
, mSourceModel(pEditor, this)
|
||||
, mHighlightMode(eHighlightSelected)
|
||||
, mPickType(eNotPicking)
|
||||
, mPickTool(eNormalTool)
|
||||
, mHoverModelIsMapped(false)
|
||||
, mpHoverModel(nullptr)
|
||||
{
|
||||
mModel.setSourceModel(&mSourceModel);
|
||||
mModel.sort(0);
|
||||
|
||||
ui->setupUi(this);
|
||||
ui->ListView->setModel(&mModel);
|
||||
ui->ListView->selectionModel()->select(mModel.index(0,0), QItemSelectionModel::Select | QItemSelectionModel::Current);
|
||||
|
||||
QActionGroup *pGroup = new QActionGroup(this);
|
||||
pGroup->addAction(ui->ActionHighlightSelected);
|
||||
|
@ -41,8 +46,8 @@ CPoiMapEditDialog::CPoiMapEditDialog(CWorldEditor *pEditor, QWidget *parent)
|
|||
connect(ui->ListView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(OnItemDoubleClick(QModelIndex)));
|
||||
connect(ui->AddMeshButton, SIGNAL(clicked()), this, SLOT(PickButtonClicked()));
|
||||
connect(ui->RemoveMeshButton, SIGNAL(clicked()), this, SLOT(PickButtonClicked()));
|
||||
connect(ui->ButtonBox->button(QDialogButtonBox::Ok), SIGNAL(clicked()), this, SLOT(close()));
|
||||
connect(ui->ButtonBox->button(QDialogButtonBox::Cancel), SIGNAL(clicked()), this, SLOT(close()));
|
||||
connect(ui->ToolComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnToolComboBoxChanged(int)));
|
||||
connect(ui->ButtonBox->button(QDialogButtonBox::Close), SIGNAL(clicked()), this, SLOT(close()));
|
||||
connect(ui->ButtonBox->button(QDialogButtonBox::Save), SIGNAL(clicked()), this, SLOT(Save()));
|
||||
}
|
||||
|
||||
|
@ -103,6 +108,54 @@ void CPoiMapEditDialog::UnhighlightModel(CModelNode *pNode)
|
|||
pNode->SetScanOverlayEnabled(false);
|
||||
}
|
||||
|
||||
void CPoiMapEditDialog::RevertHoverModelOverlay()
|
||||
{
|
||||
if (mpHoverModel)
|
||||
{
|
||||
if (mHighlightMode == eHighlightAll)
|
||||
{
|
||||
for (int iRow = 0; iRow < mSourceModel.rowCount(QModelIndex()); iRow++)
|
||||
{
|
||||
QModelIndex Index = mSourceModel.index(iRow, 0);
|
||||
|
||||
if (mSourceModel.IsModelMapped(Index, mpHoverModel))
|
||||
{
|
||||
HighlightModel(Index, mpHoverModel);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
UnhighlightModel(mpHoverModel);
|
||||
}
|
||||
|
||||
else if (mHighlightMode == eHighlightSelected)
|
||||
{
|
||||
QModelIndex Index = GetSelectedRow();
|
||||
|
||||
if (mSourceModel.IsModelMapped(Index, mpHoverModel))
|
||||
{
|
||||
HighlightModel(Index, mpHoverModel);
|
||||
mHoverModelIsMapped = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
UnhighlightModel(mpHoverModel);
|
||||
mHoverModelIsMapped = false;
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
UnhighlightModel(mpHoverModel);
|
||||
}
|
||||
}
|
||||
|
||||
CPoiMapEditDialog::EPickType CPoiMapEditDialog::GetRealPickType(bool AltPressed) const
|
||||
{
|
||||
if (!AltPressed) return mPickType;
|
||||
if (mPickType == eAddMeshes) return eRemoveMeshes;
|
||||
return eAddMeshes;
|
||||
}
|
||||
|
||||
bool CPoiMapEditDialog::IsImportant(const QModelIndex& rkIndex)
|
||||
{
|
||||
CScriptNode *pPOI = mSourceModel.PoiNodePointer(rkIndex);
|
||||
|
@ -116,6 +169,12 @@ bool CPoiMapEditDialog::IsImportant(const QModelIndex& rkIndex)
|
|||
return Important;
|
||||
}
|
||||
|
||||
QModelIndex CPoiMapEditDialog::GetSelectedRow() const
|
||||
{
|
||||
QModelIndexList Indices = ui->ListView->selectionModel()->selectedRows();
|
||||
return ( Indices.isEmpty() ? QModelIndex() : mModel.mapToSource(Indices.front()) );
|
||||
}
|
||||
|
||||
void CPoiMapEditDialog::Save()
|
||||
{
|
||||
CPoiToWorld *pPoiToWorld = mpEditor->ActiveArea()->GetPoiToWorldMap();
|
||||
|
@ -135,17 +194,27 @@ void CPoiMapEditDialog::Save()
|
|||
void CPoiMapEditDialog::SetHighlightSelected()
|
||||
{
|
||||
const QItemSelection kSelection = ui->ListView->selectionModel()->selection();
|
||||
QList<QModelIndex> SelectedIndices;
|
||||
QList<QModelIndex> UnselectedIndices;
|
||||
|
||||
for (int iRow = 0; iRow < mModel.rowCount(QModelIndex()); iRow++)
|
||||
{
|
||||
QModelIndex Index = mModel.index(iRow, 0);
|
||||
|
||||
if (kSelection.contains(Index))
|
||||
HighlightPoiModels(Index);
|
||||
SelectedIndices << Index;
|
||||
else
|
||||
UnhighlightPoiModels(Index);
|
||||
UnselectedIndices << Index;
|
||||
}
|
||||
|
||||
for (int iIdx = 0; iIdx < UnselectedIndices.size(); iIdx++)
|
||||
UnhighlightPoiModels(UnselectedIndices[iIdx]);
|
||||
for (int iIdx = 0; iIdx < SelectedIndices.size(); iIdx++)
|
||||
HighlightPoiModels(SelectedIndices[iIdx]);
|
||||
|
||||
if (mpHoverModel && !mHoverModelIsMapped)
|
||||
HighlightModel(GetSelectedRow(), mpHoverModel);
|
||||
|
||||
mHighlightMode = eHighlightSelected;
|
||||
}
|
||||
|
||||
|
@ -154,6 +223,13 @@ void CPoiMapEditDialog::SetHighlightAll()
|
|||
for (int iRow = 0; iRow < mModel.rowCount(QModelIndex()); iRow++)
|
||||
HighlightPoiModels(mModel.index(iRow, 0));
|
||||
|
||||
// Call HighlightPoiModels again on the selected index to prioritize it over the non-selected POIs.
|
||||
if (ui->ListView->selectionModel()->hasSelection())
|
||||
HighlightPoiModels(ui->ListView->selectionModel()->selectedRows().front());
|
||||
|
||||
if (mpHoverModel)
|
||||
HighlightModel(GetSelectedRow(), mpHoverModel);
|
||||
|
||||
mHighlightMode = eHighlightAll;
|
||||
}
|
||||
|
||||
|
@ -162,6 +238,9 @@ void CPoiMapEditDialog::SetHighlightNone()
|
|||
for (int iRow = 0; iRow < mModel.rowCount(QModelIndex()); iRow++)
|
||||
UnhighlightPoiModels(mModel.index(iRow, 0));
|
||||
|
||||
if (mpHoverModel)
|
||||
UnhighlightModel(mpHoverModel);
|
||||
|
||||
mHighlightMode = eHighlightNone;
|
||||
}
|
||||
|
||||
|
@ -190,6 +269,14 @@ void CPoiMapEditDialog::OnItemDoubleClick(QModelIndex Index)
|
|||
mpEditor->ClearAndSelectNode(pPOI);
|
||||
}
|
||||
|
||||
void CPoiMapEditDialog::OnToolComboBoxChanged(int NewIndex)
|
||||
{
|
||||
if (NewIndex == 0)
|
||||
mPickTool = eNormalTool;
|
||||
else
|
||||
mPickTool = eSprayCanTool;
|
||||
}
|
||||
|
||||
void CPoiMapEditDialog::PickButtonClicked()
|
||||
{
|
||||
QPushButton *pButton = qobject_cast<QPushButton*>(sender());
|
||||
|
@ -199,9 +286,10 @@ void CPoiMapEditDialog::PickButtonClicked()
|
|||
|
||||
else
|
||||
{
|
||||
mpEditor->EnterPickMode(eModelNode, false, false);
|
||||
mpEditor->EnterPickMode(eModelNode, false, false, true);
|
||||
connect(mpEditor, SIGNAL(PickModeExited()), this, SLOT(StopPicking()));
|
||||
connect(mpEditor, SIGNAL(PickModeClick(CSceneNode*,QMouseEvent*)), this, SLOT(OnNodePicked(CSceneNode*,QMouseEvent*)));
|
||||
connect(mpEditor, SIGNAL(PickModeClick(SRayIntersection,QMouseEvent*)), this, SLOT(OnNodePicked(SRayIntersection,QMouseEvent*)));
|
||||
connect(mpEditor, SIGNAL(PickModeHoverChanged(SRayIntersection,QMouseEvent*)), this, SLOT(OnNodeHover(SRayIntersection,QMouseEvent*)));
|
||||
pButton->setChecked(true);
|
||||
|
||||
if (pButton == ui->AddMeshButton)
|
||||
|
@ -224,11 +312,16 @@ void CPoiMapEditDialog::StopPicking()
|
|||
ui->RemoveMeshButton->setChecked(false);
|
||||
mPickType = eNotPicking;
|
||||
|
||||
RevertHoverModelOverlay();
|
||||
mpHoverModel = nullptr;
|
||||
|
||||
disconnect(mpEditor, 0, this, 0);
|
||||
}
|
||||
|
||||
void CPoiMapEditDialog::OnNodePicked(CSceneNode *pNode, QMouseEvent* pEvent)
|
||||
void CPoiMapEditDialog::OnNodePicked(const SRayIntersection& rkRayIntersect, QMouseEvent* pEvent)
|
||||
{
|
||||
if (!rkRayIntersect.pNode) return;
|
||||
|
||||
// Check for valid selection
|
||||
QModelIndexList Indices = ui->ListView->selectionModel()->selectedRows();
|
||||
if (Indices.isEmpty()) return;
|
||||
|
@ -239,13 +332,10 @@ void CPoiMapEditDialog::OnNodePicked(CSceneNode *pNode, QMouseEvent* pEvent)
|
|||
SourceIndices << mModel.mapToSource(*it);
|
||||
|
||||
// If alt is pressed, invert the pick mode
|
||||
CModelNode *pModel = static_cast<CModelNode*>(pNode);
|
||||
bool AltPressed = (pEvent->modifiers() & Qt::AltModifier) != 0;
|
||||
CModelNode *pModel = static_cast<CModelNode*>(rkRayIntersect.pNode);
|
||||
|
||||
EPickType PickType;
|
||||
if (!AltPressed) PickType = mPickType;
|
||||
else if (mPickType == eAddMeshes) PickType = eRemoveMeshes;
|
||||
else PickType = eAddMeshes;
|
||||
bool AltPressed = (pEvent->modifiers() & Qt::AltModifier) != 0;
|
||||
EPickType PickType = GetRealPickType(AltPressed);
|
||||
|
||||
// Add meshes
|
||||
if (PickType == eAddMeshes)
|
||||
|
@ -255,6 +345,8 @@ void CPoiMapEditDialog::OnNodePicked(CSceneNode *pNode, QMouseEvent* pEvent)
|
|||
|
||||
if (mHighlightMode != eHighlightNone)
|
||||
HighlightModel(SourceIndices.front(), pModel);
|
||||
|
||||
mHoverModelIsMapped = true;
|
||||
}
|
||||
|
||||
// Remove meshes
|
||||
|
@ -264,6 +356,41 @@ void CPoiMapEditDialog::OnNodePicked(CSceneNode *pNode, QMouseEvent* pEvent)
|
|||
mSourceModel.RemoveMapping(*it, pModel);
|
||||
|
||||
if (mHighlightMode != eHighlightNone)
|
||||
RevertHoverModelOverlay();
|
||||
else
|
||||
UnhighlightModel(pModel);
|
||||
}
|
||||
}
|
||||
|
||||
void CPoiMapEditDialog::OnNodeHover(const SRayIntersection& rkIntersect, QMouseEvent *pEvent)
|
||||
{
|
||||
// Restore old hover model to correct overlay color, and set new hover model
|
||||
if (mpHoverModel)
|
||||
RevertHoverModelOverlay();
|
||||
|
||||
mpHoverModel = static_cast<CModelNode*>(rkIntersect.pNode);
|
||||
|
||||
// If we're using the spray can and the mouse is pressed, treat this as a click.
|
||||
if (mPickTool == eSprayCanTool && (pEvent->buttons() & Qt::LeftButton))
|
||||
OnNodePicked(rkIntersect, pEvent);
|
||||
|
||||
// Otherwise, process as a mouseover
|
||||
else
|
||||
{
|
||||
QModelIndex Index = GetSelectedRow();
|
||||
|
||||
// Process new hover model
|
||||
if (mpHoverModel)
|
||||
{
|
||||
bool AltPressed = (pEvent->modifiers() & Qt::AltModifier) != 0;
|
||||
EPickType PickType = GetRealPickType(AltPressed);
|
||||
|
||||
if ( ((PickType == eAddMeshes) && !mSourceModel.IsModelMapped(Index, mpHoverModel)) ||
|
||||
((PickType == eRemoveMeshes) && mSourceModel.IsModelMapped(Index, mpHoverModel)) )
|
||||
{
|
||||
mpHoverModel->SetScanOverlayEnabled(true);
|
||||
mpHoverModel->SetScanOverlayColor(skHoverColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -35,8 +35,18 @@ class CPoiMapEditDialog : public QMainWindow
|
|||
eAddPOIs
|
||||
} mPickType;
|
||||
|
||||
enum EPickTool
|
||||
{
|
||||
eNormalTool,
|
||||
eSprayCanTool
|
||||
} mPickTool;
|
||||
|
||||
bool mHoverModelIsMapped;
|
||||
CModelNode *mpHoverModel;
|
||||
|
||||
static const CColor skNormalColor;
|
||||
static const CColor skImportantColor;
|
||||
static const CColor skHoverColor;
|
||||
|
||||
public:
|
||||
explicit CPoiMapEditDialog(CWorldEditor *pEditor, QWidget *parent = 0);
|
||||
|
@ -46,8 +56,10 @@ public:
|
|||
void UnhighlightPoiModels(const QModelIndex& rkIndex);
|
||||
void HighlightModel(const QModelIndex& rkIndex, CModelNode *pNode);
|
||||
void UnhighlightModel(CModelNode *pNode);
|
||||
void RefreshHighlights();
|
||||
bool IsImportant(const QModelIndex& rkIndex);
|
||||
void RevertHoverModelOverlay();
|
||||
EPickType GetRealPickType(bool AltPressed) const;
|
||||
QModelIndex GetSelectedRow() const;
|
||||
|
||||
public slots:
|
||||
void Save();
|
||||
|
@ -56,10 +68,12 @@ public slots:
|
|||
void SetHighlightNone();
|
||||
void OnSelectionChanged(const QItemSelection& rkSelected, const QItemSelection& rkDeselected);
|
||||
void OnItemDoubleClick(QModelIndex Index);
|
||||
void OnToolComboBoxChanged(int NewIndex);
|
||||
|
||||
void PickButtonClicked();
|
||||
void StopPicking();
|
||||
void OnNodePicked(CSceneNode *pNode, QMouseEvent *pEvent);
|
||||
void OnNodePicked(const SRayIntersection& rkIntersect, QMouseEvent *pEvent);
|
||||
void OnNodeHover(const SRayIntersection& rkIntersect, QMouseEvent *pEvent);
|
||||
|
||||
signals:
|
||||
void Closed();
|
||||
|
|
|
@ -15,19 +15,6 @@
|
|||
</property>
|
||||
<widget class="QWidget" name="centralwidget">
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QListView" name="ListView">
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="verticalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
|
@ -58,6 +45,26 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="ToolComboBox">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>80</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Normal Tool</string>
|
||||
</property>
|
||||
</item>
|
||||
<item>
|
||||
<property name="text">
|
||||
<string>Spray Can</string>
|
||||
</property>
|
||||
</item>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
|
@ -73,10 +80,23 @@
|
|||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QListView" name="ListView">
|
||||
<property name="editTriggers">
|
||||
<set>QAbstractItemView::NoEditTriggers</set>
|
||||
</property>
|
||||
<property name="verticalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||
</property>
|
||||
<property name="horizontalScrollMode">
|
||||
<enum>QAbstractItemView::ScrollPerPixel</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="ButtonBox">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::Save</set>
|
||||
<set>QDialogButtonBox::Close|QDialogButtonBox::Save</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
|
@ -146,16 +146,26 @@ void CPoiMapModel::RemoveMapping(const QModelIndex& rkIndex, CModelNode *pNode)
|
|||
{
|
||||
QList<CModelNode*> *pList = mModelMap[pPOI];
|
||||
pList->removeOne(pNode);
|
||||
|
||||
if (pList->isEmpty())
|
||||
RemovePOI(rkIndex);
|
||||
else
|
||||
mpPoiToWorld->RemovePoiMeshMap(pPOI->Object()->InstanceID(), pNode->FindMeshID());
|
||||
}
|
||||
else
|
||||
mpPoiToWorld->RemovePoiMeshMap(pPOI->Object()->InstanceID(), pNode->FindMeshID());
|
||||
}
|
||||
|
||||
bool CPoiMapModel::IsModelMapped(const QModelIndex& rkIndex, CModelNode *pNode) const
|
||||
{
|
||||
if (!pNode) return false;
|
||||
|
||||
CScriptNode *pPOI = PoiNodePointer(rkIndex);
|
||||
|
||||
if (mModelMap.contains(pPOI))
|
||||
{
|
||||
QList<CModelNode*> *pList = mModelMap[pPOI];
|
||||
return (pList->contains(pNode));
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
|
||||
CScriptNode* CPoiMapModel::PoiNodePointer(const QModelIndex& rkIndex) const
|
||||
{
|
||||
if ((u32) rkIndex.row() < mpPoiToWorld->NumMappedPOIs())
|
||||
|
|
|
@ -31,6 +31,7 @@ public:
|
|||
void AddMapping(const QModelIndex& rkIndex, CModelNode *pNode);
|
||||
void RemovePOI(const QModelIndex& rkIndex);
|
||||
void RemoveMapping(const QModelIndex& rkIndex, CModelNode *pNode);
|
||||
bool IsModelMapped(const QModelIndex& rkIndex, CModelNode *pNode) const;
|
||||
|
||||
CScriptNode* PoiNodePointer(const QModelIndex& rkIndex) const;
|
||||
const QList<CModelNode*>& GetPoiMeshList(const QModelIndex& rkIndex) const;
|
||||
|
|
|
@ -68,7 +68,11 @@ CWorldEditor::CWorldEditor(QWidget *parent) :
|
|||
addAction(ui->ActionDecrementGizmo);
|
||||
|
||||
// Connect signals and slots
|
||||
connect(ui->MainViewport, SIGNAL(ViewportClick(CSceneNode*,QMouseEvent*)), this, SLOT(OnViewportClick(CSceneNode*,QMouseEvent*)));
|
||||
connect(ui->MainViewport, SIGNAL(ViewportClick(SRayIntersection,QMouseEvent*)), this, SLOT(OnViewportClick(SRayIntersection,QMouseEvent*)));
|
||||
connect(ui->MainViewport, SIGNAL(InputProcessed(SRayIntersection,QMouseEvent*)), this, SLOT(OnViewportInputProcessed(SRayIntersection,QMouseEvent*)));
|
||||
connect(ui->MainViewport, SIGNAL(InputProcessed(SRayIntersection,QMouseEvent*)), this, SLOT(UpdateGizmoUI()) );
|
||||
connect(ui->MainViewport, SIGNAL(InputProcessed(SRayIntersection,QMouseEvent*)), this, SLOT(UpdateStatusBar()) );
|
||||
connect(ui->MainViewport, SIGNAL(InputProcessed(SRayIntersection,QMouseEvent*)), this, SLOT(UpdateCursor()) );
|
||||
connect(ui->MainViewport, SIGNAL(GizmoMoved()), this, SLOT(OnGizmoMoved()));
|
||||
connect(ui->MainViewport, SIGNAL(CameraOrbit()), this, SLOT(UpdateCameraOrbit()));
|
||||
connect(this, SIGNAL(SelectionModified()), this, SLOT(UpdateCameraOrbit()));
|
||||
|
@ -166,7 +170,7 @@ CGameArea* CWorldEditor::ActiveArea()
|
|||
return mpArea;
|
||||
}
|
||||
|
||||
// ************ UPDATE UI ************
|
||||
// ************ PROTECTED SLOTS ************
|
||||
void CWorldEditor::UpdateStatusBar()
|
||||
{
|
||||
// Would be cool to do more frequent status bar updates with more info. Unfortunately, this causes lag.
|
||||
|
@ -262,13 +266,6 @@ void CWorldEditor::UpdateSelectionUI()
|
|||
UpdateGizmoUI();
|
||||
}
|
||||
|
||||
// ************ PROTECTED ************
|
||||
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) );
|
||||
}
|
||||
|
||||
void CWorldEditor::UpdateCursor()
|
||||
{
|
||||
if (ui->MainViewport->IsCursorVisible() && !mPickMode)
|
||||
|
@ -284,6 +281,13 @@ void CWorldEditor::UpdateCursor()
|
|||
}
|
||||
}
|
||||
|
||||
// ************ PROTECTED ************
|
||||
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) );
|
||||
}
|
||||
|
||||
// ************ PRIVATE SLOTS ************
|
||||
void CWorldEditor::OnPickModeEnter(QCursor Cursor)
|
||||
{
|
||||
|
@ -300,11 +304,8 @@ void CWorldEditor::RefreshViewport()
|
|||
if (!mGizmo.IsTransforming())
|
||||
mGizmo.ResetSelectedAxes();
|
||||
|
||||
// Process input + update UI
|
||||
// Process input
|
||||
ui->MainViewport->ProcessInput();
|
||||
UpdateCursor();
|
||||
UpdateStatusBar();
|
||||
UpdateGizmoUI();
|
||||
|
||||
// Render
|
||||
ui->MainViewport->Render();
|
||||
|
|
|
@ -45,16 +45,14 @@ public:
|
|||
void SetArea(CWorld *pWorld, CGameArea *pArea);
|
||||
CGameArea* ActiveArea();
|
||||
|
||||
// Update UI
|
||||
void UpdateStatusBar();
|
||||
|
||||
public slots:
|
||||
void UpdateStatusBar();
|
||||
void UpdateGizmoUI();
|
||||
void UpdateSelectionUI();
|
||||
void UpdateCursor();
|
||||
|
||||
protected:
|
||||
void GizmoModeChanged(CGizmo::EGizmoMode mode);
|
||||
void UpdateCursor();
|
||||
|
||||
private slots:
|
||||
void OnPickModeEnter(QCursor Cursor);
|
||||
|
|
Loading…
Reference in New Issue