Feature additions and improvements for pick mode and the POI -> World editor

This commit is contained in:
parax0 2016-01-16 12:57:20 -07:00
parent 5c3a37ca4a
commit 440c3ad484
19 changed files with 331 additions and 100 deletions

View File

@ -5,14 +5,15 @@
enum EKeyInput
{
eCtrlKey = 0x1,
eAltKey = 0x2,
eQKey = 0x4,
eWKey = 0x8,
eEKey = 0x10,
eAKey = 0x20,
eSKey = 0x40,
eDKey = 0x80
eCtrlKey = 0x1,
eShiftKey = 0x2,
eAltKey = 0x2,
eQKey = 0x4,
eWKey = 0x8,
eEKey = 0x10,
eAKey = 0x20,
eSKey = 0x40,
eDKey = 0x80
};
DECLARE_FLAGS(EKeyInput, FKeyInputs)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
if (!mViewInfo.GameMode)
CheckGizmoInput(Ray);
if (!mpEditor->Gizmo()->IsTransforming())
SceneRayCast(ray);
if (!mpEditor->Gizmo()->IsTransforming())
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);
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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