1 // Copyright 2001-2018 Crytek GmbH / Crytek Group. All rights reserved.
4 #include "ObjectMode.h"
6 #include <Preferences/ViewportPreferences.h>
7 #include "ViewManager.h"
8 #include "Terrain/Heightmap.h"
9 #include "GameEngine.h"
10 #include "Objects/EntityObject.h"
11 #include "Objects/CameraObject.h"
12 #include "Controls/DynamicPopupMenu.h"
13 #include "Objects/BrushObject.h"
14 #include "DeepSelection.h"
15 #include "SubObjectSelectionReferenceFrameCalculator.h"
16 #include "Gizmos/IGizmoManager.h"
17 #include "Objects/ParticleEffectObject.h"
18 #include "Objects/PrefabObject.h"
20 #include "IUndoManager.h"
21 #include "Objects/ISelectionGroup.h"
23 /////////////////////////////
24 // CObjectManipulatorOwner
25 /////////////////////////////
26 CObjectManipulatorOwner::CObjectManipulatorOwner(CObjectMode
* objectModeTool
)
28 , m_visibilityDirty(true)
30 m_manipulator
= GetIEditor()->GetGizmoManager()->AddManipulator(this);
31 m_manipulator
->signalBeginDrag
.Connect(objectModeTool
, &CObjectMode::OnManipulatorBeginDrag
);
32 m_manipulator
->signalDragging
.Connect(objectModeTool
, &CObjectMode::OnManipulatorDrag
);
33 m_manipulator
->signalEndDrag
.Connect(objectModeTool
, &CObjectMode::OnManipulatorEndDrag
);
35 GetIEditor()->GetObjectManager()->signalObjectsChanged
.Connect(this, &CObjectManipulatorOwner::OnObjectsChanged
);
36 GetIEditor()->GetObjectManager()->signalSelectionChanged
.Connect(this, &CObjectManipulatorOwner::OnSelectionChanged
);
38 const ISelectionGroup
* pSelection
= GetIEditor()->GetISelectionGroup();
39 int totCount
= pSelection
->GetCount();
41 // register to all selected objects on initialization
42 for (int i
= 0; i
< totCount
; ++i
)
44 CBaseObject
* pObj
= pSelection
->GetObject(i
);
45 pObj
->signalChanged
.Connect(this, &CObjectManipulatorOwner::OnObjectChanged
);
49 CObjectManipulatorOwner::~CObjectManipulatorOwner()
51 GetIEditor()->GetObjectManager()->signalObjectsChanged
.DisconnectObject(this);
52 GetIEditor()->GetObjectManager()->signalSelectionChanged
.DisconnectObject(this);
54 m_manipulator
->signalBeginDrag
.DisconnectAll();
55 m_manipulator
->signalDragging
.DisconnectAll();
56 m_manipulator
->signalEndDrag
.DisconnectAll();
57 GetIEditor()->GetGizmoManager()->RemoveManipulator(m_manipulator
);
59 m_manipulator
= nullptr;
61 const ISelectionGroup
* pSelection
= GetIEditor()->GetISelectionGroup();
62 int totCount
= pSelection
->GetCount();
64 // unregister from all selected objects
65 for (int i
= 0; i
< totCount
; ++i
)
67 CBaseObject
* pObj
= pSelection
->GetObject(i
);
68 pObj
->signalChanged
.DisconnectObject(this);
72 bool CObjectManipulatorOwner::GetManipulatorMatrix(Matrix34
& tm
)
74 const ISelectionGroup
* pSelection
= GetIEditor()->GetISelectionGroup();
75 return pSelection
->GetManipulatorMatrix(tm
);
78 void CObjectManipulatorOwner::GetManipulatorPosition(Vec3
& position
)
80 const ISelectionGroup
* pSelection
= GetIEditor()->GetISelectionGroup();
82 position
.Set(0.0f
, 0.0f
, 0.0f
);
84 int totCount
= pSelection
->GetCount();
85 for (int i
= 0; i
< totCount
; ++i
)
87 CBaseObject
* pObj
= pSelection
->GetObject(i
);
88 if (pObj
->IsVisible() && !pObj
->IsFrozen())
90 position
+= pObj
->GetWorldPos();
94 position
*= (1.0f
/ totCount
);
97 void CObjectManipulatorOwner::OnObjectChanged(const CBaseObject
* pObject
, const CObjectEvent
& event
)
99 if (event
.m_type
== OBJECT_ON_TRANSFORM
)
101 // tag for update next cycle
102 m_manipulator
->Invalidate();
104 else if (event
.m_type
== OBJECT_ON_VISIBILITY
)
106 m_manipulator
->Invalidate();
107 m_visibilityDirty
= true;
111 void CObjectManipulatorOwner::OnObjectsChanged(const std::vector
<CBaseObject
*>& objects
, const CObjectEvent
& event
)
113 if (event
.m_type
== OBJECT_ON_TRANSFORM
)
115 // tag for update next cycle
116 m_manipulator
->Invalidate();
120 void CObjectManipulatorOwner::OnSelectionChanged(const std::vector
<CBaseObject
*>& selected
, const std::vector
<CBaseObject
*>& deselected
)
122 CRY_PROFILE_FUNCTION(PROFILE_EDITOR
);
123 // unregister from all manipulated objects
124 for (auto& pObject
: deselected
)
126 pObject
->signalChanged
.DisconnectObject(this);
129 for (auto& pObject
: selected
)
131 pObject
->signalChanged
.Connect(this, &CObjectManipulatorOwner::OnObjectChanged
);
134 m_manipulator
->Invalidate();
135 m_visibilityDirty
= true;
138 bool CObjectManipulatorOwner::IsManipulatorVisible()
140 if (m_visibilityDirty
)
142 UpdateVisibilityState();
143 m_manipulator
->Invalidate();
144 m_visibilityDirty
= false;
149 void CObjectManipulatorOwner::UpdateVisibilityState()
151 const ISelectionGroup
* pSelection
= GetIEditor()->GetISelectionGroup();
152 m_bIsVisible
= false;
153 int totCount
= pSelection
->GetCount();
154 for (int i
= 0; i
< totCount
; ++i
)
156 CBaseObject
* pObj
= pSelection
->GetObject(i
);
158 if (pObj
->IsVisible() && !pObj
->IsFrozen())
166 //////////////////////////////////////////////////////////////////////////
167 IMPLEMENT_DYNCREATE(CObjectMode
, CEditTool
)
169 SDeepSelectionPreferences gDeepSelectionPreferences
;
170 REGISTER_PREFERENCES_PAGE_PTR(SDeepSelectionPreferences
, &gDeepSelectionPreferences
)
172 //////////////////////////////////////////////////////////////////////////
173 CObjectMode::CObjectMode()
174 : m_objectManipulatorOwner(this)
175 , m_bDragThresholdExceeded(false)
177 m_openContext
= false;
178 m_commandMode
= NothingMode
;
179 m_MouseOverObject
= CryGUID::Null();
181 m_pDeepSelection
= new CDeepSelection();
182 m_bMoveByFaceNormManipShown
= false;
185 m_bTransformChanged
= false;
187 m_suspendHighlightChange
= false;
188 m_normalMoveGizmo
= nullptr;
190 m_bGizmoDrag
= false;
193 //////////////////////////////////////////////////////////////////////////
194 CObjectMode::~CObjectMode()
196 GetIEditor()->UnRegisterAllObjectModeSubTools();
197 CAutoRegisterObjectModeSubToolHelper::UnregisterAll();
199 CBaseObject
* pMouseOverObject
= nullptr;
200 if (m_MouseOverObject
!= CryGUID::Null())
202 pMouseOverObject
= GetIEditor()->GetObjectManager()->FindObject(m_MouseOverObject
);
205 if (pMouseOverObject
)
207 pMouseOverObject
->SetHighlight(false);
210 if (m_normalMoveGizmo
)
212 m_normalMoveGizmo
->signalBeginDrag
.DisconnectAll();
213 m_normalMoveGizmo
->signalDragging
.DisconnectAll();
214 m_normalMoveGizmo
->signalEndDrag
.DisconnectAll();
215 GetIEditor()->GetGizmoManager()->RemoveManipulator(m_normalMoveGizmo
);
216 m_normalMoveGizmo
= nullptr;
220 void CObjectMode::Activate()
222 CAutoRegisterObjectModeSubToolHelper::RegisterAll();
223 GetIEditor()->RegisterAllObjectModeSubTools();
226 void CObjectMode::RegisterSubTool(ISubTool
* pSubTool
)
228 m_subTools
.insert(pSubTool
);
231 void CObjectMode::UnRegisterSubTool(ISubTool
* pSubTool
)
233 m_subTools
.erase(pSubTool
);
236 void CObjectMode::DisplaySelectionPreview(SDisplayContext
& dc
)
238 IDisplayViewport
* pDisplayViewport
= dc
.view
;
239 if (!pDisplayViewport
)
242 CViewport
* pViewport
= static_cast<CViewport
*>(pDisplayViewport
);
246 IObjectManager
* objMan
= GetIEditor()->GetObjectManager();
248 CRect rc
= pViewport
->GetSelectionRectangle();
250 if (GetCommandMode() == SelectMode
)
252 if (rc
.Width() > 1 && rc
.Height() > 1)
254 GetIEditor()->GetObjectManager()->FindObjectsInRect(pViewport
, rc
, m_PreviewGUIDs
);
256 // Do not include child objects in the count of object candidates
258 for (int objNo
= 0; objNo
< m_PreviewGUIDs
.size(); ++objNo
)
260 auto foundObj
= objMan
->FindObject(m_PreviewGUIDs
[objNo
]);
261 if (foundObj
&& foundObj
->GetParent())
265 // Draw Preview for objects
266 for (size_t i
= 0; i
< m_PreviewGUIDs
.size(); ++i
)
268 CBaseObject
* pObject
= GetIEditor()->GetObjectManager()->FindObject(m_PreviewGUIDs
[i
]);
273 if (pObject
->GetType() & ~gViewportSelectionPreferences
.objectSelectMask
)
276 pObject
->DrawSelectionPreviewHighlight(dc
);
282 //////////////////////////////////////////////////////////////////////////
283 void CObjectMode::Display(SDisplayContext
& dc
)
285 // Selection Candidates Preview
286 DisplaySelectionPreview(dc
);
289 //////////////////////////////////////////////////////////////////////////
290 bool CObjectMode::MouseCallback(CViewport
* view
, EMouseEvent event
, CPoint
& point
, int flags
)
292 // Sub tools get to handle the event first, if it goes unhandled, object mode will then try to handle it
293 for (ISubTool
* pSubTool
: m_subTools
)
295 if (pSubTool
->HandleMouseEvent(view
, event
, point
, flags
))
304 return OnLButtonDown(view
, flags
, point
);
307 return OnLButtonUp(view
, flags
, point
);
309 case eMouseLDblClick
:
310 return OnLButtonDblClk(view
, flags
, point
);
313 return OnRButtonDown(view
, flags
, point
);
316 return OnRButtonUp(view
, flags
, point
);
320 return OnMouseMove(view
, flags
, point
);
323 return OnMButtonDown(view
, flags
, point
);
325 case eMouseFocusLeave
:
327 SetObjectCursor(view
, 0, IObjectManager::ESelectOp::eNone
);
334 //////////////////////////////////////////////////////////////////////////
335 bool CObjectMode::OnKeyDown(CViewport
* view
, uint32 nChar
, uint32 nRepCnt
, uint32 nFlags
)
337 if (nChar
== Qt::Key_Escape
)
339 GetIEditor()->ClearSelection();
340 CLevelEditorSharedState
* pLevelEditor
= GetIEditor()->GetLevelEditorSharedState();
342 if (pLevelEditor
->GetEditMode() == CLevelEditorSharedState::EditMode::SelectArea
)
343 pLevelEditor
->SetEditMode(CLevelEditorSharedState::EditMode::Select
);
348 //////////////////////////////////////////////////////////////////////////
349 bool CObjectMode::OnKeyUp(CViewport
* view
, uint32 nChar
, uint32 nRepCnt
, uint32 nFlags
)
354 //////////////////////////////////////////////////////////////////////////
355 bool CObjectMode::OnLButtonDown(CViewport
* view
, int nFlags
, CPoint point
)
357 if (m_bMoveByFaceNormManipShown
)
359 HideMoveByFaceNormGizmo();
366 if (GetIEditor()->IsInGameMode())
368 // Ignore clicks while in game.
372 // Save the mouse down position
373 m_cMouseDownPos
= point
;
375 m_bDragThresholdExceeded
= false;
377 view
->ResetSelectionRegion();
379 Vec3 pos
= view
->SnapToGrid(view
->ViewToWorld(point
));
380 CLevelEditorSharedState::EditMode editMode
= GetIEditor()->GetLevelEditorSharedState()->GetEditMode();
382 // Show marker position in the status bar
383 //cry_sprintf(szNewStatusText, "X:%g Y:%g Z:%g",pos.x,pos.y,pos.z );
387 CHeightmap
* pHeightmap
= GetIEditor()->GetHeightmap();
389 unitSize
= pHeightmap
->GetUnitSize();
390 float hx
= pos
.y
/ unitSize
;
391 float hy
= pos
.x
/ unitSize
;
392 float hz
= GetIEditor()->GetTerrainElevation(pos
.x
, pos
.y
);
394 // Get control key status.
395 const bool bAltClick
= (nFlags
& MK_ALT
);
396 const bool bCtrlClick
= (nFlags
& MK_CONTROL
);
397 const bool bShiftClick
= (nFlags
& MK_SHIFT
);
399 const bool bAddSelect
= bShiftClick
;
400 const bool bToggle
= bCtrlClick
;
401 // Alt click might be beginning of marque deselection - so we must not remove selection
402 const bool bNoRemoveSelection
= bAddSelect
|| bToggle
|| bAltClick
;
404 // Check deep selection mode activated
405 // The Deep selection has two mode.
406 // The normal mode pops the context menu, another is the cyclic selection on clinking.
407 bool bTabPressed
= CheckVirtualKey(VK_TAB
);
408 bool bZKeyPressed
= CheckVirtualKey('Z');
410 CDeepSelection::EDeepSelectionMode dsMode
=
411 (bTabPressed
? (bZKeyPressed
? CDeepSelection::DSM_POP
: CDeepSelection::DSM_CYCLE
) : CDeepSelection::DSM_NONE
);
413 bool bLockSelection
= GetIEditor()->IsSelectionLocked();
415 int numUnselected
= 0;
423 if (dsMode
== CDeepSelection::DSM_POP
)
425 m_pDeepSelection
->Reset(true);
426 m_pDeepSelection
->SetMode(dsMode
);
427 hitInfo
.pDeepSelection
= m_pDeepSelection
;
429 else if (dsMode
== CDeepSelection::DSM_CYCLE
)
431 if (!m_pDeepSelection
->OnCycling(point
))
433 // Start of the deep selection cycling mode.
434 m_pDeepSelection
->Reset(false);
435 m_pDeepSelection
->SetMode(dsMode
);
436 hitInfo
.pDeepSelection
= m_pDeepSelection
;
441 if (m_pDeepSelection
->GetPreviousMode() == CDeepSelection::DSM_NONE
)
442 m_pDeepSelection
->Reset(true);
444 m_pDeepSelection
->SetMode(CDeepSelection::DSM_NONE
);
445 hitInfo
.pDeepSelection
= 0;
449 if (view
->HitTest(point
, hitInfo
))
451 if (hitInfo
.axis
!= CLevelEditorSharedState::Axis::None
)
453 GetIEditor()->GetLevelEditorSharedState()->SetAxisConstraint(hitInfo
.axis
);
454 // if edit mode is set to selection, then we treat gizmo as a selection component and we should not lock the selection
455 if (editMode
!= CLevelEditorSharedState::EditMode::Select
)
457 bLockSelection
= true;
461 //////////////////////////////////////////////////////////////////////////
463 CheckDeepSelection(hitInfo
, view
);
466 CBaseObject
* hitObj
= hitInfo
.object
;
468 CLevelEditorSharedState::CoordSystem coordSys
= GetIEditor()->GetLevelEditorSharedState()->GetCoordSystem();
469 Vec3 gridPosition
= (hitObj
) ? hitObj
->GetWorldPos() : pos
;
471 if (coordSys
== CLevelEditorSharedState::CoordSystem::UserDefined
)
473 Matrix34 userTM
= Matrix34::CreateIdentity();
474 GetIEditor()->GetISelectionGroup()->GetManipulatorMatrix(userTM
);
475 userTM
.SetTranslation(Vec3(0, 0, 0));
476 userTM
.SetTranslation(gridPosition
);
477 view
->SetConstructionMatrix(userTM
);
479 else if (coordSys
== CLevelEditorSharedState::CoordSystem::World
|| !hitObj
)
481 Matrix34 tm
= Matrix34::CreateIdentity();
482 tm
.SetTranslation(gridPosition
);
483 view
->SetConstructionMatrix(tm
);
485 else if (coordSys
== CLevelEditorSharedState::CoordSystem::Parent
)
487 if (hitInfo
.object
->GetParent())
489 Matrix34 parentTM
= hitInfo
.object
->GetParent()->GetWorldTM();
490 parentTM
.OrthonormalizeFast();
491 parentTM
.SetTranslation(gridPosition
);
492 view
->SetConstructionMatrix(parentTM
);
496 view
->SetConstructionMatrix(hitInfo
.object
->GetWorldTM());
499 else if (coordSys
== CLevelEditorSharedState::CoordSystem::Local
)
501 view
->SetConstructionMatrix(hitInfo
.object
->GetWorldTM());
504 if (gSnappingPreferences
.IsSnapToTerrainEnabled() && GetIEditor()->GetLevelEditorSharedState()->GetAxisConstraint() != CLevelEditorSharedState::Axis::Z
)
506 m_mouseDownWorldPos
= view
->ViewToWorld(point
);
510 m_mouseDownWorldPos
= view
->MapViewToCP(point
);
513 if (editMode
!= CLevelEditorSharedState::EditMode::Tool
)
515 // Check for Move to position.
516 if (bCtrlClick
&& bShiftClick
)
518 // Ctrl-Click on terrain will move selected objects to specified location.
519 MoveSelectionToPos(view
, pos
, bAltClick
, point
);
520 bLockSelection
= true;
524 if (editMode
== CLevelEditorSharedState::EditMode::Move
)
526 if (!bNoRemoveSelection
)
527 SetCommandMode(MoveMode
);
529 if (hitObj
&& hitObj
->IsSelected() && !bNoRemoveSelection
)
530 bLockSelection
= true;
532 else if (editMode
== CLevelEditorSharedState::EditMode::Rotate
)
534 if (!bNoRemoveSelection
)
535 SetCommandMode(RotateMode
);
536 if (hitObj
&& hitObj
->IsSelected() && !bNoRemoveSelection
)
537 bLockSelection
= true;
539 else if (editMode
== CLevelEditorSharedState::EditMode::Scale
)
541 if (!bNoRemoveSelection
)
543 SetCommandMode(ScaleMode
);
546 if (hitObj
&& hitObj
->IsSelected() && !bNoRemoveSelection
)
547 bLockSelection
= true;
549 else if (hitObj
!= 0 && GetIEditor()->GetSelectedObject() == hitObj
&& !bAddSelect
&& !bToggle
)
551 bLockSelection
= true;
556 // If not selection locked.
559 IObjectManager
* pObjectManager
= GetIEditor()->GetObjectManager();
561 if (!bNoRemoveSelection
)
563 // Current selection should be cleared
564 numSelected
= GetIEditor()->GetISelectionGroup()->GetCount();
565 pObjectManager
->ClearSelection();
574 pObjectManager
->SelectObject(hitObj
);
578 if (hitObj
->IsSelected())
580 pObjectManager
->UnselectObject(hitObj
);
584 pObjectManager
->SelectObject(hitObj
);
588 if (view
->IsUndoRecording())
590 view
->AcceptUndo("Select Object(s)");
593 if (numSelected
== 0 || editMode
== CLevelEditorSharedState::EditMode::Select
|| editMode
== CLevelEditorSharedState::EditMode::SelectArea
)
595 // If object is not selected.
596 // Capture mouse input for this window.
597 SetCommandMode(SelectMode
);
601 if (GetCommandMode() == MoveMode
||
602 GetCommandMode() == RotateMode
||
603 GetCommandMode() == ScaleMode
)
605 m_suspendHighlightChange
= true;
609 //////////////////////////////////////////////////////////////////////////
610 // Change cursor, must be before Capture mouse.
611 //////////////////////////////////////////////////////////////////////////
612 SetObjectCursor(view
, hitObj
, bAddSelect
? IObjectManager::ESelectOp::eSelect
: IObjectManager::ESelectOp::eNone
);
614 m_bTransformChanged
= false;
616 if (m_pDeepSelection
->GetMode() == CDeepSelection::DSM_POP
)
617 return OnLButtonUp(view
, nFlags
, point
);
622 //////////////////////////////////////////////////////////////////////////
623 bool CObjectMode::OnLButtonUp(CViewport
* view
, int nFlags
, CPoint point
)
625 if (GetIEditor()->IsInGameMode())
627 // Ignore clicks while in game.
631 if (m_bTransformChanged
)
633 const ISelectionGroup
* pSelection
= GetIEditor()->GetISelectionGroup();
635 pSelection
->FinishChanges();
636 m_bTransformChanged
= false;
639 // Undo may have been accepted already for MoveMode (if mouse has moved from original position), so view->IsUndoRecording()
640 // will be false here, but we still need to cleanup. AcceptUndo is safe in any case because it checks if we are using undo.
641 if (view
->IsUndoRecording())
643 if (GetCommandMode() == MoveMode
)
645 view
->AcceptUndo("Move Selection");
647 else if (GetCommandMode() == RotateMode
)
649 view
->AcceptUndo("Rotate Selection");
651 else if (GetCommandMode() == ScaleMode
)
653 view
->AcceptUndo("Scale Selection");
661 if (GetCommandMode() == MoveMode
)
663 m_bDragThresholdExceeded
= false;
666 //////////////////////////////////////////////////////////////////////////
668 if (GetCommandMode() == SelectMode
&& (!GetIEditor()->IsSelectionLocked()))
670 const bool bUnselect
= (nFlags
& MK_ALT
);
671 const bool bToggle
= (nFlags
& MK_CONTROL
);
673 const IObjectManager::ESelectOp selectOp
= bUnselect
? IObjectManager::ESelectOp::eUnselect
:
674 (bToggle
? IObjectManager::ESelectOp::eToggle
: IObjectManager::ESelectOp::eSelect
);
676 CRect selectRect
= view
->GetSelectionRectangle();
677 if (!selectRect
.IsRectEmpty())
679 // Ignore too small rectangles.
680 if (selectRect
.Width() > 5 && selectRect
.Height() > 5)
682 GetIEditor()->GetObjectManager()->SelectObjectsInRect(view
, selectRect
, selectOp
);
686 if (GetIEditor()->GetLevelEditorSharedState()->GetEditMode() == CLevelEditorSharedState::EditMode::SelectArea
)
688 GetIEditor()->ClearSelection();
692 // If command mode is still "NothingMode" this object was just created and placed and needs this update too.
693 if (GetCommandMode() == ScaleMode
|| GetCommandMode() == MoveMode
|| GetCommandMode() == RotateMode
|| GetCommandMode() == NothingMode
)
695 m_suspendHighlightChange
= false;
696 GetIEditor()->GetISelectionGroup()->ObjectModified();
699 if (GetIEditor()->GetLevelEditorSharedState()->GetEditMode() != CLevelEditorSharedState::EditMode::SelectArea
)
701 view
->ResetSelectionRegion();
703 // Reset selected rectangle.
704 view
->SetSelectionRectangle(CPoint(0, 0), CPoint(0, 0));
706 SetCommandMode(NothingMode
);
711 //////////////////////////////////////////////////////////////////////////
712 bool CObjectMode::OnLButtonDblClk(CViewport
* view
, int nFlags
, CPoint point
)
714 // If shift clicked, Move the camera to this place.
715 if (nFlags
& MK_SHIFT
)
717 // Get the heightmap coordinates for the click position
718 Vec3 v
= view
->ViewToWorld(point
);
719 if (!(v
.x
== 0 && v
.y
== 0 && v
.z
== 0))
721 Matrix34 tm
= view
->GetViewTM();
722 Vec3 p
= tm
.GetTranslation();
723 float height
= p
.z
- GetIEditor()->GetTerrainElevation(p
.x
, p
.y
);
724 if (height
< 1) height
= 1;
727 p
.z
= GetIEditor()->GetTerrainElevation(p
.x
, p
.y
) + height
;
728 tm
.SetTranslation(p
);
734 // Check if double clicked on object.
736 view
->HitTest(point
, hitInfo
);
738 CBaseObject
* hitObj
= hitInfo
.object
;
741 // Fire double click event on hit object.
742 hitObj
->OnEvent(EVENT_DBLCLICK
);
748 //////////////////////////////////////////////////////////////////////////
749 bool CObjectMode::OnRButtonDown(CViewport
* view
, int nFlags
, CPoint point
)
751 if (gViewportPreferences
.enableContextMenu
)
753 // Check if right clicked on object.
755 if (view
->HitTest(point
, hitInfo
) && hitInfo
.object
)
757 m_openContext
= true;
758 m_rMouseDownPos
= point
;
765 //////////////////////////////////////////////////////////////////////////
766 bool CObjectMode::OnRButtonUp(CViewport
* view
, int nFlags
, CPoint point
)
770 m_openContext
= false;
772 // check if we are close to the original mouse position
773 int halfLength
= gViewportPreferences
.dragSquareSize
/ 2;
774 CRect
rcDrag(m_rMouseDownPos
.x
, m_rMouseDownPos
.y
, m_rMouseDownPos
.x
, m_rMouseDownPos
.y
);
775 InflateRect(rcDrag
, halfLength
, halfLength
);
777 if (!PtInRect(rcDrag
, point
))
780 // Check if right clicked on object.
782 if (!view
->HitTest(point
, hitInfo
))
787 CDynamicPopupMenu menu
;
788 hitInfo
.object
->OnContextMenu(&menu
.GetRoot());
790 if (!menu
.GetRoot().Empty())
792 // suspend highlight change for the duration of the popup...
793 m_suspendHighlightChange
= true;
795 // and resume on close
796 menu
.SetOnHideFunctor([ = ]
798 if (GetIEditor()->GetLevelEditorSharedState()->GetEditTool() == this)
800 AllowHighlightChange();
803 menu
.SpawnAtCursor();
810 //////////////////////////////////////////////////////////////////////////
811 bool CObjectMode::OnMButtonDown(CViewport
* view
, int nFlags
, CPoint point
)
813 if (GetIEditor()->GetGameEngine()->GetSimulationMode())
815 // Get control key status.
816 const bool bAltClick
= (nFlags
& MK_ALT
);
817 const bool bCtrlClick
= (nFlags
& MK_CONTROL
);
818 const bool bShiftClick
= (nFlags
& MK_SHIFT
);
822 // In simulation mode awake objects under the cursor when Ctrl+MButton pressed.
823 AwakeObjectAtPoint(view
, point
);
830 //////////////////////////////////////////////////////////////////////////
831 void CObjectMode::AwakeObjectAtPoint(CViewport
* view
, CPoint point
)
833 // In simulation mode awake objects under the cursor.
834 // Check if double clicked on object.
836 view
->HitTest(point
, hitInfo
);
837 CBaseObject
* hitObj
= hitInfo
.object
;
840 IPhysicalEntity
* pent
= hitObj
->GetCollisionEntity();
850 //////////////////////////////////////////////////////////////////////////
851 bool CObjectMode::CheckVirtualKey(int virtualKey
)
853 GetAsyncKeyState(virtualKey
);
854 if (GetAsyncKeyState(virtualKey
))
859 //////////////////////////////////////////////////////////////////////////
860 void CObjectMode::MoveSelectionToPos(CViewport
* view
, Vec3
& pos
, bool align
, const CPoint
& point
)
863 // Find center of selection.
864 const ISelectionGroup
* pSelection
= GetIEditor()->GetISelectionGroup();
865 Vec3 center
= pSelection
->GetCenter();
866 pSelection
->Move(pos
- center
, ISelectionGroup::eMS_None
, point
, true);
869 GetIEditor()->GetISelectionGroup()->Align();
871 view
->AcceptUndo("Move Selection");
874 //////////////////////////////////////////////////////////////////////////
875 bool CObjectMode::OnMouseMove(CViewport
* view
, int nFlags
, CPoint point
)
877 if (GetIEditor()->IsInGameMode())
879 // Ignore while in game.
882 const bool bAltClick
= (nFlags
& MK_ALT
);
883 const bool bCtrlClick
= (nFlags
& MK_CONTROL
);
884 const bool bShiftClick
= (nFlags
& MK_SHIFT
);
886 bool bSomethingDone
= false;
888 bool bAdding
= false;
889 bool bRemoving
= false;
891 m_openContext
= false;
893 // get current axis constrains.
894 if (GetCommandMode() == MoveMode
)
896 if (!m_bDragThresholdExceeded
)
898 int halfLength
= gViewportPreferences
.dragSquareSize
/ 2;
899 CRect
rcDrag(m_cMouseDownPos
.x
, m_cMouseDownPos
.y
, m_cMouseDownPos
.x
, m_cMouseDownPos
.y
);
900 InflateRect(rcDrag
, halfLength
, halfLength
);
902 if (!PtInRect(rcDrag
, point
))
904 // Save the current positions, move tool relies on them - change from relying on undo system.
905 GetIEditor()->GetISelectionGroup()->FilterParents();
906 GetIEditor()->GetISelectionGroup()->SaveFilteredTransform();
915 Vec3 p1
= m_mouseDownWorldPos
;
916 if (gSnappingPreferences
.IsSnapToTerrainEnabled() && GetIEditor()->GetLevelEditorSharedState()->GetAxisConstraint() != CLevelEditorSharedState::Axis::Z
)
918 Vec3 p2
= view
->SnapToGrid(view
->ViewToWorld(point
));
919 v
= view
->GetCPVector(p1
, p2
);
924 Vec3 p2
= view
->MapViewToCP(point
);
925 if (p1
.IsZero() || p2
.IsZero())
928 v
= view
->GetCPVector(p1
, p2
);
931 int selectionFlags
= ISelectionGroup::eMS_None
;
932 if (gSnappingPreferences
.IsSnapToTerrainEnabled() && GetIEditor()->GetLevelEditorSharedState()->GetAxisConstraint() != CLevelEditorSharedState::Axis::Z
)
933 selectionFlags
= ISelectionGroup::eMS_FollowTerrain
;
935 if (gSnappingPreferences
.IsSnapToGeometryEnabled())
936 selectionFlags
|= ISelectionGroup::eMS_FollowGeometry
;
938 if (gSnappingPreferences
.IsSnapToNormalEnabled())
939 selectionFlags
|= ISelectionGroup::eMS_SnapToNormal
;
941 if ((nFlags
& MK_CONTROL
) && !(nFlags
& MK_SHIFT
))
942 selectionFlags
= ISelectionGroup::eMS_FollowGeometry
| ISelectionGroup::eMS_SnapToNormal
;
944 if (!v
.IsEquivalent(Vec3(0, 0, 0)))
945 m_bTransformChanged
= true;
947 #pragma message("TODO")
948 //CTrackViewSequenceNoNotificationContext context(pSequence);
950 if (m_bDragThresholdExceeded
)
952 // All moved objects should have pushed an undo after moving, so suspend here
953 // if we don't we'll end up with a huge undo step with duplicate entries for the objects.
954 // TODO: improve undo system to only push when really necessary.
955 GetIEditor()->GetIUndoManager()->Suspend();
958 GetIEditor()->GetISelectionGroup()->Move(v
, selectionFlags
, point
, true);
960 if (m_bDragThresholdExceeded
)
962 GetIEditor()->GetIUndoManager()->Resume();
965 m_bDragThresholdExceeded
= true;
966 bSomethingDone
= true;
968 else if (GetCommandMode() == RotateMode
)
970 GetIEditor()->GetIUndoManager()->Restore();
973 float ax
= point
.x
- m_cMouseDownPos
.x
;
974 float ay
= point
.y
- m_cMouseDownPos
.y
;
975 switch (GetIEditor()->GetLevelEditorSharedState()->GetAxisConstraint())
977 case CLevelEditorSharedState::Axis::X
:
980 case CLevelEditorSharedState::Axis::Y
:
983 case CLevelEditorSharedState::Axis::Z
:
986 case CLevelEditorSharedState::Axis::XY
:
989 case CLevelEditorSharedState::Axis::XZ
:
992 case CLevelEditorSharedState::Axis::YZ
:
998 ang
= gSnappingPreferences
.SnapAngle(ang
);
1000 if (!ang
.IsEquivalent(Ang3(0, 0, 0)))
1001 m_bTransformChanged
= true;
1003 //m_cMouseDownPos = point;
1004 GetIEditor()->GetISelectionGroup()->Rotate(ang
);
1005 bSomethingDone
= true;
1007 else if (GetCommandMode() == ScaleMode
)
1011 GetScale(view
, point
, scale
);
1013 if (!m_bTransformChanged
)
1015 if (!scale
.IsEquivalent(Vec3(0, 0, 0)))
1017 // Save the current positions, scale tool relies on them - change from relying on undo system.
1018 GetIEditor()->GetISelectionGroup()->FilterParents();
1019 GetIEditor()->GetISelectionGroup()->SaveFilteredTransform();
1027 if (m_bTransformChanged
)
1029 GetIEditor()->GetIUndoManager()->Suspend();
1031 GetIEditor()->GetISelectionGroup()->Scale(scale
);
1032 if (m_bTransformChanged
)
1034 GetIEditor()->GetIUndoManager()->Resume();
1036 m_bTransformChanged
= true;
1037 bSomethingDone
= true;
1039 else if (GetCommandMode() == SelectMode
)
1041 // Ignore select when selection locked.
1042 if (GetIEditor()->IsSelectionLocked())
1054 CRect
rc(m_cMouseDownPos
, point
);
1055 if (GetIEditor()->GetLevelEditorSharedState()->GetEditMode() == CLevelEditorSharedState::EditMode::SelectArea
)
1057 view
->OnDragSelectRectangle(CPoint(rc
.left
, rc
.top
), CPoint(rc
.right
, rc
.bottom
), false);
1061 view
->SetSelectionRectangle(rc
.TopLeft(), rc
.BottomRight());
1064 //OnDragSelectRectangle( CPoint(rc.left,rc.top),CPoint(rc.right,rc.bottom),true );
1066 bSomethingDone
= true;
1069 if (!(nFlags
& MK_RBUTTON
|| nFlags
& MK_MBUTTON
))
1071 const IObjectManager::ESelectOp selectOp
= bAdding
? IObjectManager::ESelectOp::eSelect
:
1072 (bRemoving
? IObjectManager::ESelectOp::eUnselect
: IObjectManager::ESelectOp::eNone
);
1074 // Track mouse movements.
1075 CGizmo
* highlightedGizmo
= GetIEditor()->GetGizmoManager()->GetHighlightedGizmo();
1078 if (!highlightedGizmo
&& view
->HitTest(point
, hitInfo
))
1080 SetObjectCursor(view
, hitInfo
.object
, selectOp
);
1084 SetObjectCursor(view
, nullptr, selectOp
);
1087 HandleMoveByFaceNormal(hitInfo
);
1092 SetObjectCursor(view
, nullptr, IObjectManager::ESelectOp::eNone
);
1095 if ((nFlags
& MK_MBUTTON
) && GetIEditor()->GetGameEngine()->GetSimulationMode())
1097 // Get control key status.
1100 // In simulation mode awake objects under the cursor when Ctrl+MButton pressed.
1101 AwakeObjectAtPoint(view
, point
);
1105 return bSomethingDone
;
1108 //////////////////////////////////////////////////////////////////////////
1109 void CObjectMode::SetObjectCursor(CViewport
* view
, CBaseObject
* hitObj
, IObjectManager::ESelectOp selectMode
)
1111 EStdCursor cursor
= STD_CURSOR_DEFAULT
;
1114 CBaseObject
* pMouseOverObject
= NULL
;
1115 if (m_MouseOverObject
!= CryGUID::Null() && !m_suspendHighlightChange
)
1117 pMouseOverObject
= GetIEditor()->GetObjectManager()->FindObject(m_MouseOverObject
);
1120 //HCURSOR hPrevCursor = m_hCurrCursor;
1121 if (pMouseOverObject
)
1123 pMouseOverObject
->SetHighlight(false);
1126 if (!m_suspendHighlightChange
)
1129 m_MouseOverObject
= hitObj
->GetId();
1131 m_MouseOverObject
= CryGUID::Null();
1132 pMouseOverObject
= hitObj
;
1135 bool bHitSelectedObject
= false;
1136 if (pMouseOverObject
)
1138 if (GetCommandMode() != SelectMode
&& !GetIEditor()->IsSelectionLocked())
1140 if (pMouseOverObject
->CanBeHightlighted() && GetIEditor()->IsHelpersDisplayed())
1141 pMouseOverObject
->SetHighlight(true);
1143 m_cursorStr
= pMouseOverObject
->GetName();
1145 string
comment(pMouseOverObject
->GetComment());
1146 if (!comment
.IsEmpty())
1148 m_cursorStr
+= "\n";
1149 m_cursorStr
+= comment
;
1152 if (gViewportDebugPreferences
.showMeshStatsOnMouseOver
)
1154 const string triangleCountText
= pMouseOverObject
->GetMouseOverStatisticsText();
1156 if (!triangleCountText
.IsEmpty())
1158 m_cursorStr
+= triangleCountText
;
1162 string
warnings(pMouseOverObject
->GetWarningsText());
1163 if (!warnings
.IsEmpty())
1165 m_cursorStr
+= warnings
;
1168 cursor
= STD_CURSOR_HIT
;
1169 if (pMouseOverObject
->IsSelected())
1170 bHitSelectedObject
= true;
1176 cursor
= STD_CURSOR_DEFAULT
;
1179 const bool bAddSelect
= (selectMode
== IObjectManager::ESelectOp::eSelect
);
1180 const bool bUnselect
= (selectMode
== IObjectManager::ESelectOp::eUnselect
);
1181 const bool bNoRemoveSelection
= bAddSelect
|| bUnselect
;
1183 bool bLockSelection
= GetIEditor()->IsSelectionLocked();
1185 if (GetCommandMode() == SelectMode
|| GetCommandMode() == NothingMode
)
1188 cursor
= STD_CURSOR_SEL_PLUS
;
1190 cursor
= STD_CURSOR_SEL_MINUS
;
1192 if ((bHitSelectedObject
&& !bNoRemoveSelection
) || bLockSelection
)
1194 CLevelEditorSharedState::EditMode editMode
= GetIEditor()->GetLevelEditorSharedState()->GetEditMode();
1195 if (editMode
== CLevelEditorSharedState::EditMode::Move
)
1197 cursor
= STD_CURSOR_MOVE
;
1199 else if (editMode
== CLevelEditorSharedState::EditMode::Rotate
)
1201 cursor
= STD_CURSOR_ROTATE
;
1203 else if (editMode
== CLevelEditorSharedState::EditMode::Scale
)
1205 cursor
= STD_CURSOR_SCALE
;
1209 else if (GetCommandMode() == MoveMode
)
1211 cursor
= STD_CURSOR_MOVE
;
1213 else if (GetCommandMode() == RotateMode
)
1215 cursor
= STD_CURSOR_ROTATE
;
1217 else if (GetCommandMode() == ScaleMode
)
1219 cursor
= STD_CURSOR_SCALE
;
1222 view
->SetCurrentCursor(cursor
, m_cursorStr
);
1225 //////////////////////////////////////////////////////////////////////////
1226 // Class description.
1227 //////////////////////////////////////////////////////////////////////////
1228 class CObjectMode_ClassDesc
: public IClassDesc
1230 //! This method returns an Editor defined GUID describing the class this plugin class is associated with.
1231 virtual ESystemClassID
SystemClassID() { return ESYSTEM_CLASS_EDITTOOL
; }
1233 //! This method returns the human readable name of the class.
1234 virtual const char* ClassName() { return "EditTool.ObjectMode"; };
1236 //! This method returns Category of this class, Category is specifing where this plugin class fits best in
1238 virtual const char* Category() { return "Select"; };
1239 virtual CRuntimeClass
* GetRuntimeClass() { return RUNTIME_CLASS(CObjectMode
); }
1240 //////////////////////////////////////////////////////////////////////////
1243 REGISTER_CLASS_DESC(CObjectMode_ClassDesc
);
1245 //////////////////////////////////////////////////////////////////////////
1246 void CObjectMode::CheckDeepSelection(HitContext
& hitContext
, CViewport
* pWnd
)
1248 if (hitContext
.pDeepSelection
)
1250 m_pDeepSelection
->CollectCandidate(hitContext
.dist
, gDeepSelectionPreferences
.deepSelectionRange
);
1253 if (m_pDeepSelection
->GetCandidateObjectCount() > 1)
1255 // Deep Selection Pop Mode
1256 if (m_pDeepSelection
->GetMode() == CDeepSelection::DSM_POP
)
1258 CMenu popUpDeepSelect
;
1259 popUpDeepSelect
.CreatePopupMenu();
1261 for (int i
= 0; i
< m_pDeepSelection
->GetCandidateObjectCount(); ++i
)
1263 popUpDeepSelect
.AppendMenu(MF_STRING
, i
+ 1, m_pDeepSelection
->GetCandidateObject(i
)->GetName());
1268 int nSelect
= popUpDeepSelect
.TrackPopupMenu(TPM_NONOTIFY
| TPM_RETURNCMD
| TPM_CENTERALIGN
, p
.x
, p
.y
, CWnd::FromHandle((HWND
)pWnd
->GetSafeHwnd()), NULL
);
1272 // Update HitContext hitInfo.
1273 hitContext
.object
= m_pDeepSelection
->GetCandidateObject(nSelect
- 1);
1274 m_pDeepSelection
->ExcludeHitTest(nSelect
- 1);
1277 else if (m_pDeepSelection
->GetMode() == CDeepSelection::DSM_CYCLE
)
1279 int selPos
= m_pDeepSelection
->GetCurrentSelectPos();
1280 hitContext
.object
= m_pDeepSelection
->GetCandidateObject(selPos
+ 1);
1281 m_pDeepSelection
->ExcludeHitTest(selPos
+ 1);
1286 Vec3
& CObjectMode::GetScale(const CViewport
* view
, const CPoint
& point
, Vec3
& OutScale
)
1288 float ay
= 1.0f
- 0.01f
* (point
.y
- m_cMouseDownPos
.y
);
1290 if (ay
< 0.01f
) ay
= 0.01f
;
1292 Vec3
scl(ay
, ay
, ay
);
1294 CLevelEditorSharedState::Axis axisConstraint
= GetIEditor()->GetLevelEditorSharedState()->GetAxisConstraint();
1296 switch (axisConstraint
)
1298 case CLevelEditorSharedState::Axis::X
:
1301 case CLevelEditorSharedState::Axis::Y
:
1304 case CLevelEditorSharedState::Axis::Z
:
1307 case CLevelEditorSharedState::Axis::XY
:
1310 case CLevelEditorSharedState::Axis::XZ
:
1313 case CLevelEditorSharedState::Axis::YZ
:
1316 case CLevelEditorSharedState::Axis::XYZ
:
1322 if (gSnappingPreferences
.IsSnapToTerrainEnabled())
1330 void CObjectMode::OnManipulatorBeginDrag(IDisplayViewport
* view
, ITransformManipulator
* pManipulator
, const Vec2i
& point
, int flags
)
1332 m_cMouseDownPos
= CPoint(point
.x
, point
.y
);
1333 m_bGizmoDrag
= true;
1334 CLevelEditorSharedState::EditMode editMode
= GetIEditor()->GetLevelEditorSharedState()->GetEditMode();
1336 if (editMode
== CLevelEditorSharedState::EditMode::Scale
|| editMode
== CLevelEditorSharedState::EditMode::Move
)
1338 const ISelectionGroup
* pSelection
= GetIEditor()->GetISelectionGroup();
1339 pSelection
->FilterParents();
1340 pSelection
->SaveFilteredTransform();
1342 // Hack: Only for move mode, set the command mode to move, so that grid shows up in the viewport
1343 if (editMode
== CLevelEditorSharedState::EditMode::Move
)
1345 m_bDragThresholdExceeded
= false;
1349 if (editMode
== CLevelEditorSharedState::EditMode::Move
)
1351 m_commandMode
= MoveMode
;
1353 else if (editMode
== CLevelEditorSharedState::EditMode::Scale
)
1355 m_commandMode
= ScaleMode
;
1357 else if (editMode
== CLevelEditorSharedState::EditMode::Rotate
)
1359 m_commandMode
= RotateMode
;
1362 ((CViewport
*)view
)->DegradateQuality(true);
1365 void CObjectMode::OnManipulatorEndDrag(IDisplayViewport
* view
, ITransformManipulator
* pManipulator
)
1367 if (m_commandMode
== ScaleMode
|| m_commandMode
== MoveMode
)
1369 if (m_bDragThresholdExceeded
)
1371 const ISelectionGroup
* pSelection
= GetIEditor()->GetISelectionGroup();
1372 pSelection
->FinishChanges();
1373 m_bDragThresholdExceeded
= false;
1376 m_commandMode
= NothingMode
;
1377 m_bGizmoDrag
= false;
1379 ((CViewport
*)view
)->DegradateQuality(false);
1380 GetIEditor()->UpdateViews(eUpdateObjects
);
1383 //////////////////////////////////////////////////////////////////////////
1384 // This callback is currently called only to handle the case of the 'move by the face normal'.
1385 // Other movements of the object are handled in the 'CObjectMode::OnMouseMove()' method.
1386 void CObjectMode::OnManipulatorDrag(IDisplayViewport
* view
, ITransformManipulator
* pManipulator
, const Vec2i
& point
, const Vec3
& value
, int flags
)
1388 CPoint
p(point
.x
, point
.y
);
1390 if (m_commandMode
== MoveMode
)
1392 int halfLength
= gViewportPreferences
.dragSquareSize
/ 2;
1393 CRect
rcDrag(m_cMouseDownPos
.x
, m_cMouseDownPos
.y
, m_cMouseDownPos
.x
, m_cMouseDownPos
.y
);
1394 InflateRect(rcDrag
, halfLength
, halfLength
);
1396 if (PtInRect(rcDrag
, p
))
1401 const ISelectionGroup
* pSelection
= GetIEditor()->GetISelectionGroup();
1403 if (m_bDragThresholdExceeded
)
1405 // All moved objects should have pushed an undo after moving, so suspend here
1406 // if we don't we'll end up with a huge undo step with duplicate entries for the objects.
1407 // TODO: improve undo system to only push when really necessary.
1408 GetIEditor()->GetIUndoManager()->Suspend();
1411 int selectionFlags
= ISelectionGroup::eMS_None
;
1412 if (gSnappingPreferences
.IsSnapToTerrainEnabled())
1413 selectionFlags
= ISelectionGroup::eMS_FollowTerrain
;
1415 if (gSnappingPreferences
.IsSnapToNormalEnabled())
1416 selectionFlags
|= ISelectionGroup::eMS_SnapToNormal
;
1418 pSelection
->Move(value
, selectionFlags
, p
, true);
1421 UpdateMoveByFaceNormGizmo(m_pHitObject
);
1423 if (m_bDragThresholdExceeded
)
1425 GetIEditor()->GetIUndoManager()->Resume();
1427 m_bDragThresholdExceeded
= true;
1429 else if (m_commandMode
== RotateMode
)
1431 GetIEditor()->GetIUndoManager()->Restore();
1432 const ISelectionGroup
* pSelection
= GetIEditor()->GetISelectionGroup();
1434 // unfortunately more conversion to fit selectiongroup format
1435 Ang3 angles
= RAD2DEG(-value
);
1436 pSelection
->Rotate(angles
);
1438 else if (m_commandMode
== ScaleMode
)
1440 const ISelectionGroup
* pSelection
= GetIEditor()->GetISelectionGroup();
1441 pSelection
->Scale(value
);
1442 m_bDragThresholdExceeded
= true;
1446 void CObjectMode::HandleMoveByFaceNormal(HitContext
& hitInfo
)
1448 CBaseObject
* pHitObject
= hitInfo
.object
;
1449 bool bFaceNormalMovePossible
= pHitObject
&& GetIEditor()->GetLevelEditorSharedState()->GetEditMode() == CLevelEditorSharedState::EditMode::Move
1450 && (pHitObject
->GetType() == OBJTYPE_SOLID
|| pHitObject
->GetType() == OBJTYPE_BRUSH
)
1451 && pHitObject
->IsSelected();
1452 bool bNKeyPressed
= CheckVirtualKey('N');
1453 if (bFaceNormalMovePossible
&& bNKeyPressed
)
1455 // Test a hit for its faces.
1456 hitInfo
.nSubObjFlags
= SO_HIT_POINT
| SO_HIT_SELECT
| SO_HIT_NO_EDIT
| SO_HIT_ELEM_FACE
;
1457 pHitObject
->SetFlags(OBJFLAG_SUBOBJ_EDITING
);
1458 pHitObject
->HitTest(hitInfo
);
1459 pHitObject
->ClearFlags(OBJFLAG_SUBOBJ_EDITING
);
1461 UpdateMoveByFaceNormGizmo(pHitObject
);
1463 else if (m_bMoveByFaceNormManipShown
&& !bNKeyPressed
)
1465 HideMoveByFaceNormGizmo();
1469 void CObjectMode::UpdateMoveByFaceNormGizmo(CBaseObject
* pHitObject
)
1472 refFrame
.SetIdentity();
1473 SubObjectSelectionReferenceFrameCalculator
calculator(SO_ELEM_FACE
);
1474 pHitObject
->CalculateSubObjectSelectionReferenceFrame(&calculator
);
1475 if (calculator
.GetFrame(refFrame
) == false)
1477 HideMoveByFaceNormGizmo();
1481 if (!m_normalMoveGizmo
)
1483 m_normalMoveGizmo
= GetIEditor()->GetGizmoManager()->AddManipulator(&m_normalGizmoOwner
);
1485 m_bMoveByFaceNormManipShown
= true;
1486 m_pHitObject
= pHitObject
;
1487 m_normalMoveGizmo
->SetCustomTransform(true, refFrame
);
1491 void CObjectMode::HideMoveByFaceNormGizmo()
1493 if (m_normalMoveGizmo
)
1495 m_normalMoveGizmo
->signalBeginDrag
.DisconnectAll();
1496 m_normalMoveGizmo
->signalDragging
.DisconnectAll();
1497 m_normalMoveGizmo
->signalEndDrag
.DisconnectAll();
1498 GetIEditor()->GetGizmoManager()->RemoveManipulator(m_normalMoveGizmo
);
1499 m_normalMoveGizmo
= nullptr;
1501 m_bMoveByFaceNormManipShown
= false;
1502 m_pHitObject
= NULL
;
1505 // only display the grid when we actually transform something
1506 bool CObjectMode::IsDisplayGrid()
1509 (!m_bGizmoDrag
&& m_commandMode
!= NothingMode
)
1510 || (m_commandMode
== MoveMode
);