You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
o3de/Code/Editor/Objects/AxisGizmo.cpp

366 lines
9.7 KiB
C++

/*
* Copyright (c) Contributors to the Open 3D Engine Project.
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*
*/
#include "EditorDefs.h"
#include "AxisGizmo.h"
// Editor
#include "Viewport.h"
#include "GizmoManager.h"
#include "ViewManager.h"
#include "Settings.h"
#include "RenderHelpers/AxisHelper.h"
#include "IObjectManager.h"
//////////////////////////////////////////////////////////////////////////
// CAxisGizmo implementation.
//////////////////////////////////////////////////////////////////////////
int CAxisGizmo::m_axisGizmoCount = 0;
//////////////////////////////////////////////////////////////////////////
CAxisGizmo::CAxisGizmo(CBaseObject* object)
{
assert(object != 0);
m_object = object;
m_pAxisHelper.reset(new CAxisHelper);
// Set selectable flag.
SetFlags(EGIZMO_SELECTABLE | EGIZMO_TRANSFORM_MANIPULATOR);
m_axisGizmoCount++;
m_object->AddEventListener(this);
m_localTM.SetIdentity();
m_parentTM.SetIdentity();
m_matrix.SetIdentity();
m_bDragging = false;
m_bAlwaysUseLocal = false;
m_coordSysBackUp = COORDS_VIEW;
}
//////////////////////////////////////////////////////////////////////////
CAxisGizmo::CAxisGizmo()
{
// Set selectable flag.
SetFlags(EGIZMO_SELECTABLE);
m_axisGizmoCount++;
m_pAxisHelper.reset(new CAxisHelper);
m_bDragging = false;
m_bAlwaysUseLocal = false;
m_coordSysBackUp = COORDS_VIEW;
}
//////////////////////////////////////////////////////////////////////////
CAxisGizmo::~CAxisGizmo()
{
if (m_object)
{
m_object->RemoveEventListener(this);
}
m_axisGizmoCount--;
}
//////////////////////////////////////////////////////////////////////////
void CAxisGizmo::OnObjectEvent([[maybe_unused]] CBaseObject* object, int event)
{
if (event == CBaseObject::ON_DELETE || event == CBaseObject::ON_UNSELECT)
{
// This gizmo must be deleted as well.
GetIEditor()->GetObjectManager()->GetGizmoManager()->RemoveGizmo(this);
return;
}
}
//////////////////////////////////////////////////////////////////////////
void CAxisGizmo::Display(DisplayContext& dc)
{
if (m_object)
{
const bool visible =
!m_object->IsHidden()
&& !m_object->IsFrozen()
&& m_object->IsSelected();
if (!visible)
{
// This gizmo must be deleted.
DeleteThis();
return;
}
if (m_object->IsSkipSelectionHelper())
{
return;
}
}
DrawAxis(dc);
}
//////////////////////////////////////////////////////////////////////////
void CAxisGizmo::SetWorldBounds(const AABB& bbox)
{
m_bbox = bbox;
}
//////////////////////////////////////////////////////////////////////////
void CAxisGizmo::GetWorldBounds(AABB& bbox)
{
if (m_object)
{
m_object->GetBoundBox(bbox);
}
else
{
bbox.min = Vec3(-1000000, -1000000, -1000000);
bbox.max = Vec3(1000000, 1000000, 1000000);
}
}
//////////////////////////////////////////////////////////////////////////
void CAxisGizmo::DrawAxis(DisplayContext& dc)
{
m_pAxisHelper->SetHighlightAxis(m_highlightAxis);
Matrix34 tm = GetTransformation(m_bAlwaysUseLocal ? COORDS_LOCAL : GetIEditor()->GetReferenceCoordSys(), dc.view);
m_pAxisHelper->DrawAxis(tm, GetIEditor()->GetGlobalGizmoParameters(), dc);
if (m_object && m_object->CheckFlags(OBJFLAG_IS_PARTICLE))
{
AABB objectBox;
m_object->GetBoundBox(objectBox);
m_pAxisHelper->DrawDome(tm, GetIEditor()->GetGlobalGizmoParameters(), dc, objectBox);
}
}
//////////////////////////////////////////////////////////////////////////
const Matrix34& CAxisGizmo::GetMatrix() const
{
if (m_object)
{
m_matrix.SetTranslation(m_object->GetWorldTM().GetTranslation());
}
return m_matrix;
}
//////////////////////////////////////////////////////////////////////////
bool CAxisGizmo::HitTest(HitContext& hc)
{
Matrix34 tm = GetTransformation(m_bAlwaysUseLocal ? COORDS_LOCAL : GetIEditor()->GetReferenceCoordSys(), hc.view);
CAxisHelper axis;
bool bRes = m_pAxisHelper->HitTest(tm, GetIEditor()->GetGlobalGizmoParameters(), hc);
if (bRes)
{
hc.object = m_object;
}
m_highlightAxis = m_pAxisHelper->GetHighlightAxis();
return bRes;
}
//////////////////////////////////////////////////////////////////////////
bool CAxisGizmo::HitTestManipulator(HitContext& hc)
{
return HitTest(hc);
}
//////////////////////////////////////////////////////////////////////////
void CAxisGizmo::SetTransformation(RefCoordSys coordSys, const Matrix34& tm)
{
switch (coordSys)
{
case COORDS_WORLD:
SetMatrix(tm);
break;
case COORDS_LOCAL:
m_localTM = tm;
{
Matrix34 wtm;
wtm.SetIdentity();
wtm.SetTranslation(m_localTM.GetTranslation());
SetMatrix(wtm);
m_userTM = tm;
}
m_parentTM = m_localTM;
break;
case COORDS_PARENT:
m_parentTM = tm;
break;
case COORDS_USERDEFINED:
m_userTM = tm;
break;
}
}
//////////////////////////////////////////////////////////////////////////
Matrix34 CAxisGizmo::GetTransformation(RefCoordSys coordSys, IDisplayViewport* view /*=nullptr*/) const
{
if (m_object)
{
switch (coordSys)
{
case COORDS_VIEW:
if (view)
{
Matrix34 tm = view->GetViewTM();
tm.SetTranslation(m_object->GetWorldTM().GetTranslation());
return tm;
}
return GetMatrix();
break;
case COORDS_LOCAL:
return m_object->GetWorldTM();
break;
case COORDS_PARENT:
//return m_parentTM;
if (m_object->GetParent())
{
Matrix34 parentTM = m_object->GetParent()->GetWorldTM();
parentTM.SetTranslation(m_object->GetWorldTM().GetTranslation());
return parentTM;
}
else
{
return GetMatrix();
}
break;
case COORDS_WORLD:
return GetMatrix();
break;
case COORDS_USERDEFINED:
{
Matrix34 userTM;
userTM.SetIdentity();
userTM.SetTranslation(m_object->GetWorldTM().GetTranslation());
return userTM;
}
break;
}
}
else
{
switch (coordSys)
{
case COORDS_VIEW:
return GetMatrix();
break;
case COORDS_LOCAL:
return m_localTM;
break;
case COORDS_PARENT:
return m_parentTM;
break;
case COORDS_WORLD:
return GetMatrix();
break;
case COORDS_USERDEFINED:
return m_userTM;
break;
}
}
return GetMatrix();
}
//////////////////////////////////////////////////////////////////////////
bool CAxisGizmo::MouseCallback(CViewport* view, EMouseEvent event, QPoint& point, [[maybe_unused]] int nFlags)
{
AZ_PROFILE_FUNCTION(Editor);
if (event == eMouseLDown)
{
HitContext hc;
hc.view = view;
hc.b2DViewport = view->GetType() != ET_ViewportCamera;
hc.point2d = point;
view->ViewToWorldRay(point, hc.raySrc, hc.rayDir);
if (HitTest(hc))
{
if (event != eMouseLDown)
{
return false;
}
// On Left mouse down.
// Hit axis gizmo.
GetIEditor()->SetAxisConstraints((AxisConstrains)hc.axis);
view->SetAxisConstrain(hc.axis);
if (m_bAlwaysUseLocal)
{
m_coordSysBackUp = GetIEditor()->GetReferenceCoordSys();
GetIEditor()->SetReferenceCoordSys(COORDS_LOCAL);
}
view->SetConstructionMatrix(COORDS_LOCAL, GetTransformation(COORDS_LOCAL));
view->SetConstructionMatrix(COORDS_PARENT, GetTransformation(COORDS_PARENT));
view->SetConstructionMatrix(COORDS_USERDEFINED, GetTransformation(COORDS_USERDEFINED));
view->BeginUndo();
view->CaptureMouse();
m_bDragging = true;
m_cMouseDownPos = point;
m_initPos = GetTransformation(COORDS_WORLD).GetTranslation();
return true;
}
}
else if (event == eMouseMove)
{
if (m_bDragging)
{
return true;
}
else
{
// Hit test current transform manipulator, to highlight when mouse over.
HitContext hc;
hc.view = view;
hc.b2DViewport = view->GetType() != ET_ViewportCamera;
hc.point2d = point;
view->ViewToWorldRay(point, hc.raySrc, hc.rayDir);
if (HitTest(hc))
{
switch (hc.manipulatorMode)
{
case 1:
view->SetCurrentCursor(STD_CURSOR_MOVE);
break;
case 2:
view->SetCurrentCursor(STD_CURSOR_ROTATE);
break;
case 3:
view->SetCurrentCursor(STD_CURSOR_SCALE);
break;
}
}
}
}
else if (event == eMouseLUp)
{
if (m_bDragging)
{
view->AcceptUndo("Manipulator Drag");
view->ReleaseMouse();
m_bDragging = false;
if (m_bAlwaysUseLocal)
{
GetIEditor()->SetReferenceCoordSys(m_coordSysBackUp);
}
}
}
return false;
}