123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038 |
- /*
- * 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 "ComponentEntityObject.h"
- #include "Settings.h"
- #include "IIconManager.h"
- #include "Include/IObjectManager.h"
- #include "Objects/SelectionGroup.h"
- #include <AzCore/Component/Entity.h>
- #include <AzCore/Component/ComponentApplicationBus.h>
- #include <AzCore/Component/TransformBus.h>
- #include <AzCore/Serialization/Utils.h>
- #include <AzCore/std/string/string.h>
- #include <AzCore/Math/Transform.h>
- #include <AzFramework/Viewport/DisplayContextRequestBus.h>
- #include <AzToolsFramework/API/ComponentEntitySelectionBus.h>
- #include <AzToolsFramework/Commands/PreemptiveUndoCache.h>
- #include <AzToolsFramework/Entity/EditorEntityContextBus.h>
- #include <AzToolsFramework/Entity/EditorEntityInfoBus.h>
- #include <AzToolsFramework/Entity/EditorEntityHelpers.h>
- #include <AzToolsFramework/ToolsComponents/EditorLayerComponentBus.h>
- #include <AzToolsFramework/ToolsComponents/EditorLockComponent.h>
- #include <AzToolsFramework/ToolsComponents/EditorVisibilityComponent.h>
- #include <AzToolsFramework/ToolsComponents/SelectionComponent.h>
- #include <AzToolsFramework/ToolsComponents/TransformComponent.h>
- #include <AzToolsFramework/ToolsComponents/GenericComponentWrapper.h>
- #include <AzToolsFramework/ToolsComponents/EditorSelectionAccentSystemComponent.h>
- #include <AzToolsFramework/ToolsComponents/EditorEntityIconComponentBus.h>
- #include <AzToolsFramework/Undo/UndoCacheInterface.h>
- #include <LmbrCentral/Rendering/RenderNodeBus.h>
- #include <IDisplayViewport.h>
- #include <CryCommon/Cry_GeoIntersect.h>
- #include <MathConversion.h>
- #include <TrackView/TrackViewAnimNode.h>
- #include <ViewManager.h>
- #include <Viewport.h>
- /**
- * Scalars for icon drawing behavior.
- */
- static const int s_kIconSize = 36; /// Icon display size (in pixels)
- CComponentEntityObject::CComponentEntityObject()
- : m_hasIcon(false)
- , m_entityIconVisible(false)
- , m_iconOnlyHitTest(false)
- , m_drawAccents(true)
- , m_accentType(AzToolsFramework::EntityAccentType::None)
- , m_isIsolated(false)
- , m_iconTexture(nullptr)
- {
- }
- CComponentEntityObject::~CComponentEntityObject()
- {
- DeleteEntity();
- }
- bool CComponentEntityObject::Init(IEditor* ie, CBaseObject* copyFrom, const QString& file)
- {
- SetColor(RGB(0, 255, 0));
- SetTextureIcon(GetClassDesc()->GetTextureIconId());
- // Sandbox does not serialize this object with others in the layer.
- SetFlags(OBJFLAG_DONT_SAVE);
- const bool result = CEntityObject::Init(ie, copyFrom, file);
- return result;
- }
- void CComponentEntityObject::UpdatePreemptiveUndoCache()
- {
- using namespace AzToolsFramework;
- auto undoCacheInterface = AZ::Interface<UndoSystem::UndoCacheInterface>::Get();
- if (undoCacheInterface)
- {
- undoCacheInterface->UpdateCache(m_entityId);
- }
- }
- void CComponentEntityObject::AssignEntity(AZ::Entity* entity, bool destroyOld)
- {
- const AZ::EntityId newEntityId = entity ? entity->GetId() : AZ::EntityId();
- if (m_entityId.IsValid())
- {
- AZ::TransformNotificationBus::Handler::BusDisconnect();
- LmbrCentral::RenderBoundsNotificationBus::Handler::BusDisconnect();
- AzToolsFramework::ComponentEntityEditorRequestBus::Handler::BusDisconnect();
- AZ::EntityBus::Handler::BusDisconnect();
- AzToolsFramework::ComponentEntityObjectRequestBus::Handler::BusDisconnect();
- AzToolsFramework::EditorLockComponentNotificationBus::Handler::BusDisconnect();
- AzToolsFramework::EditorVisibilityNotificationBus::Handler::BusDisconnect();
- AzToolsFramework::EditorEntityIconComponentNotificationBus::Handler::BusDisconnect();
- if (destroyOld && m_entityId != newEntityId)
- {
- EBUS_EVENT(AzToolsFramework::EditorEntityContextRequestBus, DestroyEditorEntity, m_entityId);
- }
- m_entityId.SetInvalid();
- }
- if (entity)
- {
- m_entityId = entity->GetId();
- // note: GetObjectManager() will always be valid during normal operation but
- // will not exist when running unit tests
- if (IObjectManager* objectManager = GetObjectManager())
- {
- // Use the entity id to generate a GUID for this CEO because we need it to stay consistent for systems
- // that register by GUID such as undo/redo since our own undo/redo system constantly recreates CEOs
- GUID entityBasedGUID;
- entityBasedGUID.Data1 = 0;
- entityBasedGUID.Data2 = 0;
- entityBasedGUID.Data3 = 0;
- static_assert(sizeof(m_entityId) >= sizeof(entityBasedGUID.Data4), "The data contained in entity Id should fit inside Data4, if not switch to some other method of conversion to GUID");
- memcpy(&entityBasedGUID.Data4, &m_entityId, sizeof(entityBasedGUID.Data4));
- objectManager->ChangeObjectId(GetId(), entityBasedGUID);
- // Synchronize sandbox name to new entity's name.
- {
- EditorActionScope nameChange(m_nameReentryGuard);
- SetName(QString(entity->GetName().c_str()));
- }
- }
- EBUS_EVENT(AzToolsFramework::EditorEntityContextRequestBus, AddRequiredComponents, *entity);
- AZ::TransformNotificationBus::Handler::BusConnect(m_entityId);
- LmbrCentral::RenderBoundsNotificationBus::Handler::BusConnect(m_entityId);
- AzToolsFramework::ComponentEntityEditorRequestBus::Handler::BusConnect(m_entityId);
- AZ::EntityBus::Handler::BusConnect(m_entityId);
- AzToolsFramework::ComponentEntityObjectRequestBus::Handler::BusConnect(this);
- AzToolsFramework::EditorLockComponentNotificationBus::Handler::BusConnect(m_entityId);
- AzToolsFramework::EditorVisibilityNotificationBus::Handler::BusConnect(m_entityId);
- AzToolsFramework::EditorEntityIconComponentNotificationBus::Handler::BusConnect(m_entityId);
- // Synchronize transform to Sandbox.
- AzToolsFramework::Components::TransformComponent* transformComponent =
- entity->FindComponent<AzToolsFramework::Components::TransformComponent>();
- if (transformComponent)
- {
- OnTransformChanged(transformComponent->GetLocalTM(), transformComponent->GetWorldTM());
- }
- }
- RefreshVisibilityAndLock();
- }
- void CComponentEntityObject::RefreshVisibilityAndLock()
- {
- using AzToolsFramework::EditorEntityInfoRequestBus;
- using AzToolsFramework::EditorEntityLockComponentNotificationBus;
- using AzToolsFramework::EditorEntityVisibilityNotificationBus;
- // Lock state is tracked in 3 places:
- // EditorLockComponent, EditorEntityModel, and ComponentEntityObject.
- // Entities in layers have additional behavior in relation to lock state, if the layer is locked it supersedes the entity's lock state.
- // The viewport controls for manipulating entities are disabled during lock state here in ComponentEntityObject using the OBJFLAG_FROZEN.
- // In this case, the lock behavior should include the layer hierarchy as well, if the layer is locked this entity can't move.
- // EditorEntityModel can report this information.
- bool locked = false;
- EditorEntityInfoRequestBus::EventResult(
- locked, m_entityId, &EditorEntityInfoRequestBus::Events::IsLocked);
- EditorEntityLockComponentNotificationBus::Event(
- m_entityId, &EditorEntityLockComponentNotificationBus::Events::OnEntityLockChanged, locked);
- // OBJFLAG_HIDDEN should match EditorVisibilityComponent's VisibilityFlag.
- // Visibility state is similar to lock state in the number of areas it can be set / tracked. See the comment about the lock state above.
- bool visibility = true;
- EditorEntityInfoRequestBus::EventResult(
- visibility, m_entityId, &EditorEntityInfoRequestBus::Events::IsVisible);
- EditorEntityVisibilityNotificationBus::Event(
- m_entityId, &EditorEntityVisibilityNotificationBus::Events::OnEntityVisibilityChanged, visibility);
- }
- void CComponentEntityObject::SetName(const QString& name)
- {
- if (m_nameReentryGuard)
- {
- EditorActionScope nameChange(m_nameReentryGuard);
- AZ::Entity* entity = nullptr;
- EBUS_EVENT_RESULT(entity, AZ::ComponentApplicationBus, FindEntity, m_entityId);
- if (entity)
- {
- entity->SetName(name.toUtf8().data());
- }
- }
- CEntityObject::SetName(name);
- }
- void CComponentEntityObject::DeleteEntity()
- {
- AssignEntity(nullptr);
- CEntityObject::DeleteEntity();
- }
- float CComponentEntityObject::GetRadius()
- {
- static const float s_defaultRadius = 0.5f;
- return s_defaultRadius;
- }
- void CComponentEntityObject::SetSelected(bool bSelect)
- {
- CEntityObject::SetSelected(bSelect);
- if (m_selectionReentryGuard)
- {
- // Ignore event when received from the tools app, since the action is originating in Sandbox.
- EditorActionScope selectionChange(m_selectionReentryGuard);
- // Pass the action to the tools application.
- if (bSelect)
- {
- AzToolsFramework::ToolsApplicationRequestBus::Broadcast(&AzToolsFramework::ToolsApplicationRequests::MarkEntitySelected, m_entityId);
- }
- else
- {
- AzToolsFramework::ToolsApplicationRequestBus::Broadcast(&AzToolsFramework::ToolsApplicationRequests::MarkEntityDeselected, m_entityId);
- }
- }
- bool anySelected = false;
-
- AzToolsFramework::ToolsApplicationRequestBus::BroadcastResult(anySelected, &AzToolsFramework::ToolsApplicationRequests::AreAnyEntitiesSelected);
- if (!anySelected)
- {
- GetIEditor()->Notify(eNotify_OnEntitiesDeselected);
- }
- else
- {
- GetIEditor()->Notify(eNotify_OnEntitiesSelected);
- }
- }
- void CComponentEntityObject::SetHighlight(bool bHighlight)
- {
- CEntityObject::SetHighlight(bHighlight);
- if (m_entityId.IsValid())
- {
- EBUS_EVENT(AzToolsFramework::ToolsApplicationRequests::Bus, SetEntityHighlighted, m_entityId, bHighlight);
- }
- }
- IRenderNode* CComponentEntityObject::GetEngineNode() const
- {
- // It's possible for AZ::Entities to have multiple IRenderNodes.
- // However, the editor currently expects a single IRenderNode per "editor object".
- // Therefore, return the highest priority handler.
- if (auto* renderNodeHandler = LmbrCentral::RenderNodeRequestBus::FindFirstHandler(m_entityId))
- {
- return renderNodeHandler->GetRenderNode();
- }
- return nullptr;
- }
- void CComponentEntityObject::OnEntityNameChanged(const AZStd::string& name)
- {
- if (m_nameReentryGuard)
- {
- EditorActionScope selectionChange(m_nameReentryGuard);
- SetName(QString(name.c_str()));
- }
- }
- void CComponentEntityObject::AttachChild(CBaseObject* child, bool /*bKeepPos*/)
- {
- if (child->GetType() == OBJTYPE_AZENTITY)
- {
- CComponentEntityObject* childComponentEntity = static_cast<CComponentEntityObject*>(child);
- AZ::EntityId childEntityId = childComponentEntity->GetAssociatedEntityId();
- if (childEntityId.IsValid())
- {
- // The action is originating from Sandbox, so ignore the return event.
- EditorActionScope parentChange(childComponentEntity->m_parentingReentryGuard);
- {
- AzToolsFramework::ScopedUndoBatch undoBatch("Editor Parent");
- EBUS_EVENT_ID(childEntityId, AZ::TransformBus, SetParent, m_entityId);
- undoBatch.MarkEntityDirty(childEntityId);
- }
- EBUS_EVENT(AzToolsFramework::ToolsApplicationEvents::Bus, InvalidatePropertyDisplay, AzToolsFramework::Refresh_Values);
- }
- }
- }
- void CComponentEntityObject::DetachAll(bool /*bKeepPos*/)
- {
- }
- void CComponentEntityObject::DetachThis(bool /*bKeepPos*/)
- {
- if (m_parentingReentryGuard)
- {
- EditorActionScope parentChange(m_parentingReentryGuard);
- if (m_entityId.IsValid())
- {
- AzToolsFramework::ScopedUndoBatch undoBatch("Editor Unparent");
- EBUS_EVENT_ID(m_entityId, AZ::TransformBus, SetParent, AZ::EntityId());
- undoBatch.MarkEntityDirty(m_entityId);
- }
- EBUS_EVENT(AzToolsFramework::ToolsApplicationEvents::Bus, InvalidatePropertyDisplay, AzToolsFramework::Refresh_Values);
- }
- }
- CBaseObject* CComponentEntityObject::GetLinkParent() const
- {
- AZ::EntityId parentId;
- EBUS_EVENT_ID_RESULT(parentId, m_entityId, AZ::TransformBus, GetParentId);
- return CComponentEntityObject::FindObjectForEntity(parentId);
- }
- bool CComponentEntityObject::IsFrozen() const
- {
- return CheckFlags(OBJFLAG_FROZEN);
- }
- void CComponentEntityObject::SetFrozen(bool frozen)
- {
- if (m_lockedReentryGuard)
- {
- EditorActionScope flagChange(m_lockedReentryGuard);
- AzToolsFramework::SetEntityLockState(m_entityId, frozen);
- }
- }
- void CComponentEntityObject::OnEntityLockChanged(bool locked)
- {
- CEntityObject::SetFrozen(locked);
- }
- void CComponentEntityObject::SetHidden(
- bool bHidden, [[maybe_unused]] uint64 hiddenId /*=CBaseObject::s_invalidHiddenID*/, [[maybe_unused]] bool bAnimated /*=false*/)
- {
- if (m_visibilityFlagReentryGuard)
- {
- EditorActionScope flagChange(m_visibilityFlagReentryGuard);
- AzToolsFramework::SetEntityVisibility(m_entityId, !bHidden);
- }
- }
- void CComponentEntityObject::OnEntityVisibilityChanged(bool visible)
- {
- CEntityObject::SetHidden(!visible);
- }
- void CComponentEntityObject::OnEntityIconChanged(const AZ::Data::AssetId& entityIconAssetId)
- {
- (void)entityIconAssetId;
- SetupEntityIcon();
- }
- void CComponentEntityObject::OnParentChanged([[maybe_unused]] AZ::EntityId oldParent, [[maybe_unused]] AZ::EntityId newParent)
- {
- }
- void CComponentEntityObject::OnRenderBoundsReset()
- {
- CEntityObject::InvalidateTM(0);
- }
- void CComponentEntityObject::SetSandboxObjectAccent(AzToolsFramework::EntityAccentType accent)
- {
- m_accentType = accent;
- AzToolsFramework::EditorComponentSelectionNotificationsBus::Event(m_entityId,
- &AzToolsFramework::EditorComponentSelectionNotificationsBus::Events::OnAccentTypeChanged, m_accentType);
- }
- void CComponentEntityObject::SetSandBoxObjectIsolated(bool isIsolated)
- {
- m_isIsolated = isIsolated;
- GetIEditor()->GetObjectManager()->InvalidateVisibleList();
- }
- bool CComponentEntityObject::IsSandBoxObjectIsolated()
- {
- return m_isIsolated;
- }
- bool CComponentEntityObject::SetPos(const Vec3& pos, int flags)
- {
- bool isAzEditorTransformLocked = false;
- AzToolsFramework::Components::TransformComponentMessages::Bus::EventResult(isAzEditorTransformLocked, m_entityId,
- &AzToolsFramework::Components::TransformComponentMessages::IsTransformLocked);
- bool lockTransformOnUserInput = isAzEditorTransformLocked && (flags & eObjectUpdateFlags_UserInput);
- if (IsLayer() || lockTransformOnUserInput)
- {
- return false;
- }
- if ((flags & eObjectUpdateFlags_MoveTool) || (flags & eObjectUpdateFlags_UserInput))
- {
- // If we have a parent also in the selection set, don't allow the move tool to manipulate our position.
- if (IsNonLayerAncestorSelected())
- {
- return false;
- }
- }
- return CEntityObject::SetPos(pos, flags);
- }
- bool CComponentEntityObject::SetRotation(const Quat& rotate, int flags)
- {
- bool isAzEditorTransformLocked = false;
- AzToolsFramework::Components::TransformComponentMessages::Bus::EventResult(isAzEditorTransformLocked, m_entityId,
- &AzToolsFramework::Components::TransformComponentMessages::IsTransformLocked);
- bool lockTransformOnUserInput = isAzEditorTransformLocked && (flags & eObjectUpdateFlags_UserInput);
- if (IsLayer() || lockTransformOnUserInput)
- {
- return false;
- }
- if (flags & eObjectUpdateFlags_UserInput)
- {
- // If we have a parent also in the selection set, don't allow the rotate tool to manipulate our position.
- if (IsNonLayerAncestorSelected())
- {
- return false;
- }
- }
- return CEntityObject::SetRotation(rotate, flags);
- }
- bool CComponentEntityObject::SetScale(const Vec3& scale, int flags)
- {
- bool isAzEditorTransformLocked = false;
- AzToolsFramework::Components::TransformComponentMessages::Bus::EventResult(isAzEditorTransformLocked, m_entityId,
- &AzToolsFramework::Components::TransformComponentMessages::IsTransformLocked);
- bool lockTransformOnUserInput = isAzEditorTransformLocked && (flags & eObjectUpdateFlags_UserInput);
- if (IsLayer() || lockTransformOnUserInput)
- {
- return false;
- }
- if ((flags & eObjectUpdateFlags_ScaleTool) || (flags & eObjectUpdateFlags_UserInput))
- {
- // If we have a parent also in the selection set, don't allow the scale tool to manipulate our position.
- if (IsNonLayerAncestorSelected())
- {
- return false;
- }
- }
- return CEntityObject::SetScale(scale, flags);
- }
- bool CComponentEntityObject::IsNonLayerAncestorSelected() const
- {
- AZ::EntityId parentId;
- AZ::TransformBus::EventResult(parentId, m_entityId, &AZ::TransformBus::Events::GetParentId);
- while (parentId.IsValid())
- {
- CComponentEntityObject* parentObject = CComponentEntityObject::FindObjectForEntity(parentId);
- if (parentObject && parentObject->IsSelected())
- {
- bool isLayerEntity = false;
- AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(
- isLayerEntity,
- parentObject->GetAssociatedEntityId(),
- &AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer);
- if (!isLayerEntity)
- {
- return true;
- }
- }
- AZ::EntityId currentParentId = parentId;
- parentId.SetInvalid();
- AZ::TransformBus::EventResult(parentId, currentParentId, &AZ::TransformBus::Events::GetParentId);
- }
- return false;
- }
- bool CComponentEntityObject::IsLayer() const
- {
- bool isLayerEntity = false;
- AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(
- isLayerEntity,
- m_entityId,
- &AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer);
- return isLayerEntity;
- }
- bool CComponentEntityObject::IsAncestorIconDrawingAtSameLocation() const
- {
- if (m_entityId.IsValid())
- {
- AZ::EntityId parentId;
- AZ::TransformBus::EventResult(parentId, m_entityId, &AZ::TransformBus::Events::GetParentId);
- if (!parentId.IsValid())
- {
- return false;
- }
- AZ::Vector3 worldTranslation;
- AZ::TransformBus::EventResult(worldTranslation, m_entityId, &AZ::TransformBus::Events::GetWorldTranslation);
- while (parentId.IsValid())
- {
- AZ::Vector3 parentTranslation;
- AZ::TransformBus::EventResult(parentTranslation, parentId, &AZ::TransformBus::Events::GetWorldTranslation);
- if (parentTranslation.GetDistanceSq(worldTranslation) < 0.01f)
- {
- CComponentEntityObject* parentObject = CComponentEntityObject::FindObjectForEntity(parentId);
- if (parentObject && !parentObject->IsSelected() && parentObject->IsEntityIconVisible())
- {
- // An ancestor in the same location that's not selected and has icon visible has been found
- return true;
- }
- }
- AZ::EntityId currentParentId = parentId;
- parentId.SetInvalid();
- AZ::TransformBus::EventResult(parentId, currentParentId, &AZ::TransformBus::Events::GetParentId);
- }
- }
- return false;
- }
- bool CComponentEntityObject::IsDescendantSelectedAtSameLocation() const
- {
- if (m_entityId.IsValid())
- {
- if (GetObjectManager()->GetSelection() && GetObjectManager()->GetSelection()->GetCount() == 0)
- {
- return false;
- }
- AZ::Vector3 worldTranslation;
- AZ::TransformBus::EventResult(worldTranslation, m_entityId, &AZ::TransformBus::Events::GetWorldTranslation);
- // For each descendant, check if it's selected and if so if it's located at the same location as we are
- AzToolsFramework::EntityIdList descendantIds;
- AZ::TransformBus::EventResult(descendantIds, m_entityId, &AZ::TransformBus::Events::GetAllDescendants);
- for (AZ::EntityId entityId : descendantIds)
- {
- CComponentEntityObject* descendantObject = CComponentEntityObject::FindObjectForEntity(entityId);
- if (descendantObject && descendantObject->IsSelected())
- {
- // Check if this entity is at the exact location of us
- AZ::Vector3 entityTranslation;
- AZ::TransformBus::EventResult(entityTranslation, entityId, &AZ::TransformBus::Events::GetWorldTranslation);
- if (entityTranslation.GetDistanceSq(worldTranslation) < 0.01f)
- {
- return true;
- }
- }
- }
- }
- return false;
- }
- void CComponentEntityObject::InvalidateTM(int nWhyFlags)
- {
- CEntityObject::InvalidateTM(nWhyFlags);
- if (m_transformReentryGuard)
- {
- EditorActionScope transformChange(m_transformReentryGuard);
- if (m_entityId.IsValid())
- {
- Matrix34 worldTransform = GetWorldTM();
- EBUS_EVENT_ID(m_entityId, AZ::TransformBus, SetWorldTM, LYTransformToAZTransform(worldTransform));
- }
- }
- }
- void CComponentEntityObject::OnTransformChanged([[maybe_unused]] const AZ::Transform& local, const AZ::Transform& world)
- {
- if (m_transformReentryGuard) // Ignore if action originated from Sandbox.
- {
- EditorActionScope transformChange(m_transformReentryGuard);
- Matrix34 worlTM = AZTransformToLYTransform(world);
- SetLocalTM(worlTM, eObjectUpdateFlags_Animated);
- }
- }
- int CComponentEntityObject::MouseCreateCallback(CViewport* view, EMouseEvent event, QPoint& point, int flags)
- {
- if (event == eMouseMove || event == eMouseLDown)
- {
- Vec3 pos;
- if (GetIEditor()->GetAxisConstrains() != AXIS_TERRAIN)
- {
- pos = view->MapViewToCP(point);
- }
- else
- {
- // Snap to terrain.
- bool hitTerrain;
- pos = view->ViewToWorld(point, &hitTerrain);
- if (hitTerrain)
- {
- pos.z = GetIEditor()->GetTerrainElevation(pos.x, pos.y);
- }
- pos = view->SnapToGrid(pos);
- }
- pos = view->SnapToGrid(pos);
- SetPos(pos);
- if (event == eMouseLDown)
- {
- return MOUSECREATE_OK;
- }
- return MOUSECREATE_CONTINUE;
- }
- return CBaseObject::MouseCreateCallback(view, event, point, flags);
- }
- bool CComponentEntityObject::HitHelperTest(HitContext& hc)
- {
- bool hit = CEntityObject::HitHelperTest(hc);
- if (!hit && m_entityId.IsValid())
- {
- // Pick against icon in screen space.
- if (IsEntityIconVisible())
- {
- const QPoint entityScreenPos = hc.view->WorldToView(GetWorldPos());
- const float screenPosX = static_cast<float>(entityScreenPos.x());
- const float screenPosY = static_cast<float>(entityScreenPos.y());
- const float iconRange = static_cast<float>(s_kIconSize / 2);
- if ((hc.point2d.x() >= screenPosX - iconRange && hc.point2d.x() <= screenPosX + iconRange)
- && (hc.point2d.y() >= screenPosY - iconRange && hc.point2d.y() <= screenPosY + iconRange))
- {
- hc.dist = hc.raySrc.GetDistance(GetWorldPos());
- hc.iconHit = true;
- return true;
- }
- }
- }
- return hit;
- }
- bool CComponentEntityObject::HitTest(HitContext& hc)
- {
- AZ_PROFILE_FUNCTION(Entity);
- if (m_iconOnlyHitTest)
- {
- return false;
- }
- if (m_entityId.IsValid())
- {
- // Pick against bounding box/geometry
- AABB bounds(AABB::RESET);
- GetBoundBox(bounds);
- if (!bounds.IsReset())
- {
- Vec3 hitPos;
- if (Intersect::Ray_AABB(Ray(hc.raySrc, hc.rayDir), bounds, hitPos))
- {
- bool rayIntersection = false;
- bool preciseSelectionRequired = false;
- float closestDistance = std::numeric_limits<float>::max();
- const int viewportId = GetIEditor()->GetViewManager()->GetGameViewport()->GetViewportId();
- AzToolsFramework::EditorComponentSelectionRequestsBus::EnumerateHandlersId(m_entityId,
- [&hc, &closestDistance, &rayIntersection, &preciseSelectionRequired, viewportId](
- AzToolsFramework::EditorComponentSelectionRequests* handler) -> bool
- {
- AZ_PROFILE_FUNCTION(Entity);
- if (handler->SupportsEditorRayIntersect())
- {
- float distance = std::numeric_limits<float>::max();
- preciseSelectionRequired = true;
- const bool intersection = handler->EditorSelectionIntersectRayViewport(
- { viewportId }, LYVec3ToAZVec3(hc.raySrc), LYVec3ToAZVec3(hc.rayDir), distance);
- rayIntersection = rayIntersection || intersection;
- if (intersection && distance < closestDistance)
- {
- closestDistance = distance;
- }
- }
- return true; // iterate over all handlers
- });
- hc.object = this;
- if (preciseSelectionRequired)
- {
- hc.dist = closestDistance;
- return rayIntersection;
- }
- hc.dist = (hitPos - hc.raySrc).GetLength();
- return true;
- }
- return false;
- }
- }
- const Vec3 origin = GetWorldPos();
- const float radius = GetRadius();
- Vec3 w = origin - hc.raySrc;
- Vec3 wcross = hc.rayDir.Cross(w);
- const float d = wcross.GetLengthSquared();
- if (d < square(radius) + hc.distanceTolerance &&
- w.GetLengthSquared() > square(radius))
- {
- Vec3 i0;
- hc.object = this;
- if (Intersect::Ray_SphereFirst(Ray(hc.raySrc, hc.rayDir), ::Sphere(origin, radius), i0))
- {
- hc.dist = hc.raySrc.GetDistance(i0);
- return true;
- }
- hc.dist = hc.raySrc.GetDistance(origin);
- return true;
- }
- return false;
- }
- void CComponentEntityObject::GetBoundBox(AABB& box)
- {
- AZ_PROFILE_FUNCTION(Entity);
- box.Reset();
- const AZ::EntityId entityId = m_entityId;
- if (entityId.IsValid())
- {
- CViewport* gameViewport = GetIEditor()->GetViewManager()->GetGameViewport();
- const int viewportId = gameViewport ? gameViewport->GetViewportId() : -1;
- if (const AZ::Aabb bound =
- AzToolsFramework::CalculateEditorEntitySelectionBounds(entityId, AzFramework::ViewportInfo{viewportId});
- bound.IsValid())
- {
- box.Add(AZVec3ToLYVec3(bound.GetMin()));
- box.Add(AZVec3ToLYVec3(bound.GetMax()));
- return;
- }
- }
- CBaseObject::GetBoundBox(box);
- }
- void CComponentEntityObject::GetLocalBounds(AABB& box)
- {
- box.Reset();
- float r = GetRadius();
- box.min = -Vec3(r, r, r);
- box.max = Vec3(r, r, r);
- }
- XmlNodeRef CComponentEntityObject::Export([[maybe_unused]] const QString& levelPath, [[maybe_unused]] XmlNodeRef& xmlNode)
- {
- // All component entities are serialized out in a separate pass, so they can be
- // loaded en-masse rather than individually. As such, we don't export them
- // alongside Cry Entities.
- return XmlNodeRef();
- }
- CComponentEntityObject* CComponentEntityObject::FindObjectForEntity(AZ::EntityId id)
- {
- CEntityObject* object = nullptr;
- EBUS_EVENT_ID_RESULT(object, id, AzToolsFramework::ComponentEntityEditorRequestBus, GetSandboxObject);
- if (object && (object->GetType() == OBJTYPE_AZENTITY))
- {
- return static_cast<CComponentEntityObject*>(object);
- }
- return nullptr;
- }
- void CComponentEntityObject::Display(DisplayContext& dc)
- {
- if (!(dc.flags & DISPLAY_2D))
- {
- m_entityIconVisible = false;
- }
- bool displaySelectionHelper = false;
- if (!CanBeDrawn(dc, displaySelectionHelper))
- {
- return;
- }
- DrawDefault(dc);
- bool showIcons = m_hasIcon;
- if (showIcons)
- {
- SEditorSettings* editorSettings = GetIEditor()->GetEditorSettings();
- if (!editorSettings->viewports.bShowIcons && !editorSettings->viewports.bShowSizeBasedIcons)
- {
- showIcons = false;
- }
- }
- if (m_entityId.IsValid())
- {
- // Draw link to parent if this or the parent object are selected.
- {
- AZ::EntityId parentId;
- EBUS_EVENT_ID_RESULT(parentId, m_entityId, AZ::TransformBus, GetParentId);
- if (parentId.IsValid())
- {
- bool isParentVisible = false;
- AzToolsFramework::EditorEntityInfoRequestBus::EventResult(isParentVisible, parentId, &AzToolsFramework::EditorEntityInfoRequestBus::Events::IsVisible);
- CComponentEntityObject* parentObject = CComponentEntityObject::FindObjectForEntity(parentId);
- if (isParentVisible && (IsSelected() || (parentObject && parentObject->IsSelected())))
- {
- const QColor kLinkColorParent(0, 255, 255);
- const QColor kLinkColorChild(0, 0, 255);
- AZ::Vector3 parentTranslation;
- EBUS_EVENT_ID_RESULT(parentTranslation, parentId, AZ::TransformBus, GetWorldTranslation);
- dc.DrawLine(AZVec3ToLYVec3(parentTranslation), GetWorldTM().GetTranslation(), kLinkColorParent, kLinkColorChild);
- }
- }
- }
- // Don't draw icons if we have an ancestor in the same location that has an icon - makes sure
- // ancestor icons draw on top and are able to be selected over children. Also check if a descendant
- // is selected at the same location. In cases of entity hierarchies where numerous ancestors have
- // no position offset, we need this so the ancestors don't draw over us when we're selected
- if (showIcons)
- {
- if ((dc.flags & DISPLAY_2D) ||
- IsSelected() ||
- IsAncestorIconDrawingAtSameLocation() ||
- IsDescendantSelectedAtSameLocation())
- {
- showIcons = false;
- }
- }
- // Allow components to override in-editor visualization.
- {
- const AzFramework::DisplayContextRequestGuard displayContextGuard(dc);
- AzFramework::DebugDisplayRequestBus::BusPtr debugDisplayBus;
- AzFramework::DebugDisplayRequestBus::Bind(
- debugDisplayBus, AzFramework::g_defaultSceneEntityDebugDisplayId);
- AZ_Assert(debugDisplayBus, "Invalid DebugDisplayRequestBus.");
- AzFramework::DebugDisplayRequests* debugDisplay =
- AzFramework::DebugDisplayRequestBus::FindFirstHandler(debugDisplayBus);
- AzFramework::EntityDebugDisplayEventBus::Event(
- m_entityId, &AzFramework::EntityDebugDisplayEvents::DisplayEntityViewport,
- AzFramework::ViewportInfo{ dc.GetView()->asCViewport()->GetViewportId() },
- *debugDisplay);
- }
- }
- }
- void CComponentEntityObject::DrawDefault(DisplayContext& dc, const QColor& labelColor)
- {
- CEntityObject::DrawDefault(dc, labelColor);
- DrawAccent(dc);
- }
- IStatObj* CComponentEntityObject::GetIStatObj()
- {
- return nullptr;
- }
- bool CComponentEntityObject::IsIsolated() const
- {
- return m_isIsolated;
- }
- bool CComponentEntityObject::IsSelected() const
- {
- return AzToolsFramework::IsSelected(m_entityId);
- }
- bool CComponentEntityObject::IsSelectable() const
- {
- return AzToolsFramework::IsSelectableInViewport(m_entityId);
- }
- void CComponentEntityObject::SetWorldPos(const Vec3& pos, int flags)
- {
- // Layers, by design, are not supposed to be moveable. Layers are intended to just be a grouping
- // mechanism to allow teams to cleanly split their level into working zones, and a moveable position
- // complicates that behavior more than it helps.
- // Unfortunately component entity objects have a position under the hood, so prevent layers from moving here.
- bool isLayerEntity = false;
- AzToolsFramework::Layers::EditorLayerComponentRequestBus::EventResult(
- isLayerEntity,
- m_entityId,
- &AzToolsFramework::Layers::EditorLayerComponentRequestBus::Events::HasLayer);
- bool isAzEditorTransformLocked = false;
- AzToolsFramework::Components::TransformComponentMessages::Bus::EventResult(isAzEditorTransformLocked, m_entityId,
- &AzToolsFramework::Components::TransformComponentMessages::IsTransformLocked);
- bool lockTransformOnUserInput = isAzEditorTransformLocked && (flags & eObjectUpdateFlags_UserInput);
- if (isLayerEntity || lockTransformOnUserInput)
- {
- return;
- }
- CEntityObject::SetWorldPos(pos, flags);
- }
- void CComponentEntityObject::OnContextMenu(QMenu* /*pMenu*/)
- {
- // Deliberately bypass the base class implementation (CEntityObject::OnContextMenu()).
- }
- void CComponentEntityObject::SetupEntityIcon()
- {
- bool hideIconInViewport = false;
- m_hasIcon = false;
- AzToolsFramework::EditorEntityIconComponentRequestBus::EventResult(hideIconInViewport, m_entityId, &AzToolsFramework::EditorEntityIconComponentRequestBus::Events::IsEntityIconHiddenInViewport);
- if (!hideIconInViewport)
- {
- AzToolsFramework::EditorEntityIconComponentRequestBus::EventResult(m_icon, m_entityId, &AzToolsFramework::EditorEntityIconComponentRequestBus::Events::GetEntityIconPath);
- if (!m_icon.empty())
- {
- m_hasIcon = true;
- // ToDo: Get from Atom?
- // int textureId = GetIEditor()->GetIconManager()->GetIconTexture(m_icon.c_str());
- m_iconTexture = nullptr;
- }
- }
- }
- void CComponentEntityObject::DrawAccent(DisplayContext& dc)
- {
- if (!m_drawAccents)
- {
- return;
- }
- switch (m_accentType)
- {
- case AzToolsFramework::EntityAccentType::None:
- {
- if (dc.flags & DISPLAY_2D)
- {
- dc.SetColor(0.941f, 0.764f, 0.176f); // Yellow
- }
- else
- {
- return;
- }
- break;
- }
- case AzToolsFramework::EntityAccentType::Hover:
- {
- dc.SetColor(0, 1, 0); // Green
- break;
- }
- case AzToolsFramework::EntityAccentType::Selected:
- {
- dc.SetColor(1, 0, 0); // Red
- break;
- }
- case AzToolsFramework::EntityAccentType::ParentSelected:
- {
- dc.SetColor(1, 0.549f, 0); // Orange
- break;
- }
- case AzToolsFramework::EntityAccentType::SliceSelected:
- {
- dc.SetColor(0.117f, 0.565f, 1); // Blue
- break;
- }
- default:
- {
- dc.SetColor(1, 0.0784f, 0.576f); // Pink
- break;
- }
- }
- // if there are no explicit handlers, default to show the aabb when the mouse is over or the entity is selected.
- // this will be the case with newly added entities without explicit handlers attached (no components).
- if (!AzToolsFramework::EditorComponentSelectionRequestsBus::HasHandlers(m_entityId))
- {
- AABB box;
- GetBoundBox(box);
- dc.DrawWireBox(box.min, box.max);
- }
- }
|