Updates and fixes to viewport placement (#5712)

* updates to use more modern viewport intersection logic

Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com>

* updates to editor viewport ray intersection for object placement

Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com>

* make ed_defaultEntityPlacementDistance visible to Viewport.cpp

Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com>

* fix link error for AZ_CVAR variable

Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com>

* updates following review feedback

Signed-off-by: Tom Hulton-Harrop <82228511+hultonha@users.noreply.github.com>
This commit is contained in:
Tom Hulton-Harrop
2021-11-18 10:58:18 +00:00
committed by GitHub
parent cf540b6f44
commit bf4f52e146
10 changed files with 98 additions and 266 deletions
+26 -210
View File
@@ -14,14 +14,19 @@
// Qt
#include <QPainter>
// AzCore
#include <AzCore/Console/IConsole.h>
// AzQtComponents
#include <AzQtComponents/DragAndDrop/ViewportDragAndDrop.h>
#include <AzToolsFramework/API/ComponentEntitySelectionBus.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
#include <AzToolsFramework/Viewport/ViewportMessages.h>
#include <AzToolsFramework/ViewportSelection/EditorSelectionUtil.h>
// Editor
#include "Editor/Plugins/ComponentEntityEditorPlugin/SandboxIntegration.h"
#include "ViewManager.h"
#include "Include/ITransformManipulator.h"
#include "Include/HitContext.h"
@@ -32,22 +37,35 @@
#include "GameEngine.h"
#include "Settings.h"
#ifdef LoadCursor
#undef LoadCursor
#endif
AZ_CVAR(
float,
ed_defaultEntityPlacementDistance,
10.0f,
nullptr,
AZ::ConsoleFunctorFlags::Null,
"The default distance to place an entity from the camera if no intersection is found");
float GetDefaultEntityPlacementDistance()
{
return ed_defaultEntityPlacementDistance;
}
//////////////////////////////////////////////////////////////////////
// Viewport drag and drop support
//////////////////////////////////////////////////////////////////////
void QtViewport::BuildDragDropContext(AzQtComponents::ViewportDragContext& context, const QPoint& pt)
void QtViewport::BuildDragDropContext(
AzQtComponents::ViewportDragContext& context, const AzFramework::ViewportId viewportId, const QPoint& point)
{
context.m_hitLocation = AZ::Vector3::CreateZero();
context.m_hitLocation = GetHitLocation(pt);
context.m_hitLocation = AzToolsFramework::FindClosestPickIntersection(
viewportId, AzToolsFramework::ViewportInteraction::ScreenPointFromQPoint(point), AzToolsFramework::EditorPickRayLength,
GetDefaultEntityPlacementDistance());
}
void QtViewport::dragEnterEvent(QDragEnterEvent* event)
{
if (!GetIEditor()->GetGameEngine()->IsLevelLoaded())
@@ -66,7 +84,7 @@ void QtViewport::dragEnterEvent(QDragEnterEvent* event)
// new bus-based way of doing it (install a listener!)
using namespace AzQtComponents;
ViewportDragContext context;
BuildDragDropContext(context, event->pos());
BuildDragDropContext(context, GetViewportId(), event->pos());
DragAndDropEventsBus::Event(DragAndDropContexts::EditorViewport, &DragAndDropEvents::DragEnter, event, context);
}
}
@@ -89,7 +107,7 @@ void QtViewport::dragMoveEvent(QDragMoveEvent* event)
// new bus-based way of doing it (install a listener!)
using namespace AzQtComponents;
ViewportDragContext context;
BuildDragDropContext(context, event->pos());
BuildDragDropContext(context, GetViewportId(), event->pos());
DragAndDropEventsBus::Event(DragAndDropContexts::EditorViewport, &DragAndDropEvents::DragMove, event, context);
}
}
@@ -112,7 +130,7 @@ void QtViewport::dropEvent(QDropEvent* event)
{
// new bus-based way of doing it (install a listener!)
ViewportDragContext context;
BuildDragDropContext(context, event->pos());
BuildDragDropContext(context, GetViewportId(), event->pos());
DragAndDropEventsBus::Event(DragAndDropContexts::EditorViewport, &DragAndDropEvents::Drop, event, context);
}
}
@@ -340,13 +358,6 @@ void QtViewport::resizeEvent(QResizeEvent* event)
Update();
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::leaveEvent(QEvent* event)
{
QWidget::leaveEvent(event);
MouseCallback(eMouseLeave, QPoint(), Qt::KeyboardModifiers(), Qt::MouseButtons());
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::paintEvent([[maybe_unused]] QPaintEvent* event)
{
@@ -581,63 +592,7 @@ void QtViewport::keyReleaseEvent(QKeyEvent* event)
OnKeyUp(nativeKey, 1, event->nativeModifiers());
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnLButtonDown(Qt::KeyboardModifiers modifiers, const QPoint& point)
{
// Save the mouse down position
m_cMouseDownPos = point;
if (MouseCallback(eMouseLDown, point, modifiers))
{
return;
}
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnLButtonUp(Qt::KeyboardModifiers modifiers, const QPoint& point)
{
// Check Edit Tool.
MouseCallback(eMouseLUp, point, modifiers);
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnRButtonDown(Qt::KeyboardModifiers modifiers, const QPoint& point)
{
MouseCallback(eMouseRDown, point, modifiers);
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnRButtonUp(Qt::KeyboardModifiers modifiers, const QPoint& point)
{
MouseCallback(eMouseRUp, point, modifiers);
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnMButtonDown(Qt::KeyboardModifiers modifiers, const QPoint& point)
{
// Check Edit Tool.
MouseCallback(eMouseMDown, point, modifiers);
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnMButtonUp(Qt::KeyboardModifiers modifiers, const QPoint& point)
{
// Move the viewer to the mouse location.
// Check Edit Tool.
MouseCallback(eMouseMUp, point, modifiers);
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnMButtonDblClk(Qt::KeyboardModifiers modifiers, const QPoint& point)
{
MouseCallback(eMouseMDblClick, point, modifiers);
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnMouseMove(Qt::KeyboardModifiers modifiers, Qt::MouseButtons buttons, const QPoint& point)
{
MouseCallback(eMouseMove, point, modifiers, buttons);
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnSetCursor()
@@ -696,44 +651,6 @@ void QtViewport::OnDragSelectRectangle(const QRect& rect, bool bNormalizeRect)
GetIEditor()->SetStatusText(szNewStatusText);
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnLButtonDblClk(Qt::KeyboardModifiers modifiers, const QPoint& point)
{
if (GetIEditor()->IsInGameMode())
{
// Ignore double clicks while in game.
return;
}
MouseCallback(eMouseLDblClick, point, modifiers);
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnRButtonDblClk(Qt::KeyboardModifiers modifiers, const QPoint& point)
{
MouseCallback(eMouseRDblClick, point, modifiers);
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnKeyDown([[maybe_unused]] UINT nChar, [[maybe_unused]] UINT nRepCnt, [[maybe_unused]] UINT nFlags)
{
if (GetIEditor()->IsInGameMode())
{
// Ignore key downs while in game.
return;
}
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::OnKeyUp([[maybe_unused]] UINT nChar, [[maybe_unused]] UINT nRepCnt, [[maybe_unused]] UINT nFlags)
{
if (GetIEditor()->IsInGameMode())
{
// Ignore key downs while in game.
return;
}
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::SetCurrentCursor(const QCursor& hCursor, const QString& cursorString)
{
@@ -1119,29 +1036,6 @@ bool QtViewport::HitTest(const QPoint& point, HitContext& hitInfo)
return false;
}
AZ::Vector3 QtViewport::GetHitLocation(const QPoint& point)
{
Vec3 pos = Vec3(ZERO);
HitContext hit;
if (HitTest(point, hit))
{
pos = hit.raySrc + hit.rayDir * hit.dist;
pos = SnapToGrid(pos);
}
else
{
bool hitTerrain;
pos = ViewToWorld(point, &hitTerrain);
if (hitTerrain)
{
pos.z = GetIEditor()->GetTerrainElevation(pos.x, pos.y);
}
pos = SnapToGrid(pos);
}
return AZ::Vector3(pos.x, pos.y, pos.z);
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::SetZoomFactor(float fZoomFactor)
{
@@ -1315,84 +1209,6 @@ bool QtViewport::GetAdvancedSelectModeFlag()
return m_bAdvancedSelectMode;
}
//////////////////////////////////////////////////////////////////////////
bool QtViewport::MouseCallback(EMouseEvent event, const QPoint& point, Qt::KeyboardModifiers modifiers, Qt::MouseButtons buttons)
{
AZ_PROFILE_FUNCTION(Editor);
// Ignore any mouse events in game mode.
if (GetIEditor()->IsInGameMode())
{
return true;
}
// We must ignore mouse events when we are in the middle of an assert.
// Reason: If we have an assert called from an engine module under the editor, if we call this function,
// it may call the engine again and cause a deadlock.
// Concrete example: CryPhysics called from Trackview causing an assert, and moving the cursor over the viewport
// would cause the editor to freeze as it calls CryPhysics again for a raycast while it didn't release the lock.
if (gEnv->pSystem->IsAssertDialogVisible())
{
return true;
}
//////////////////////////////////////////////////////////////////////////
// Hit test gizmo objects.
//////////////////////////////////////////////////////////////////////////
bool bAltClick = (modifiers & Qt::AltModifier);
bool bCtrlClick = (modifiers & Qt::ControlModifier);
bool bShiftClick = (modifiers & Qt::ShiftModifier);
int flags = (bCtrlClick ? MK_CONTROL : 0) |
(bShiftClick ? MK_SHIFT : 0) |
((buttons& Qt::LeftButton) ? MK_LBUTTON : 0) |
((buttons& Qt::MiddleButton) ? MK_MBUTTON : 0) |
((buttons& Qt::RightButton) ? MK_RBUTTON : 0);
switch (event)
{
case eMouseMove:
if (m_nLastUpdateFrame == m_nLastMouseMoveFrame)
{
// If mouse move event generated in the same frame, ignore it.
return false;
}
m_nLastMouseMoveFrame = m_nLastUpdateFrame;
// Skip the marker position update if anything is selected, since it is only used
// by the info bar which doesn't show the marker when there is an active selection.
// This helps a performance issue when calling ViewToWorld (which calls RayWorldIntersection)
// on every mouse movement becomes very expensive in scenes with large amounts of entities.
CSelectionGroup* selection = GetIEditor()->GetSelection();
if (!(buttons & Qt::RightButton) /* && m_nLastUpdateFrame != m_nLastMouseMoveFrame*/ && (selection && selection->IsEmpty()))
{
//m_nLastMouseMoveFrame = m_nLastUpdateFrame;
Vec3 pos = ViewToWorld(point);
GetIEditor()->SetMarkerPosition(pos);
}
break;
}
QPoint tempPoint(point.x(), point.y());
//////////////////////////////////////////////////////////////////////////
// Handle viewport manipulators.
//////////////////////////////////////////////////////////////////////////
if (!bAltClick)
{
ITransformManipulator* pManipulator = GetIEditor()->GetTransformManipulator();
if (pManipulator)
{
if (pManipulator->MouseCallback(this, event, tempPoint, flags))
{
return true;
}
}
}
return false;
}
//////////////////////////////////////////////////////////////////////////
void QtViewport::ProcessRenderLisneters(DisplayContext& rstDisplayContext)
{