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.
180 lines
7.9 KiB
C++
180 lines
7.9 KiB
C++
/*
|
|
* All or portions of this file Copyright (c) Amazon.com, Inc. or its affiliates or
|
|
* its licensors.
|
|
*
|
|
* For complete copyright and license terms please see the LICENSE at the root of this
|
|
* distribution (the "License"). All use of this software is governed by the License,
|
|
* or, if provided, by the license below or the license accompanying this file. Do not
|
|
* remove or modify any license notices. This file is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
*
|
|
*/
|
|
|
|
#include "EntityVisibilityBoundsUnionSystem.h"
|
|
|
|
#include <AzFramework/Visibility/BoundsBus.h>
|
|
#include <cstring>
|
|
|
|
namespace AzFramework
|
|
{
|
|
EntityVisibilityBoundsUnionSystem::EntityVisibilityBoundsUnionSystem()
|
|
: m_entityActivatedEventHandler([this](AZ::Entity* entity) { OnEntityActivated(entity); })
|
|
, m_entityDeactivatedEventHandler([this](AZ::Entity* entity) { OnEntityDeactivated(entity); })
|
|
{
|
|
;
|
|
}
|
|
|
|
void EntityVisibilityBoundsUnionSystem::Connect()
|
|
{
|
|
AZ::Interface<IEntityBoundsUnion>::Register(this);
|
|
IEntityBoundsUnionRequestBus::Handler::BusConnect();
|
|
AZ::TransformNotificationBus::Router::BusRouterConnect();
|
|
AZ::TickBus::Handler::BusConnect();
|
|
|
|
AZ::Interface<AZ::ComponentApplicationRequests>::Get()->RegisterEntityActivatedEventHandler(m_entityActivatedEventHandler);
|
|
AZ::Interface<AZ::ComponentApplicationRequests>::Get()->RegisterEntityDeactivatedEventHandler(m_entityDeactivatedEventHandler);
|
|
}
|
|
|
|
void EntityVisibilityBoundsUnionSystem::Disconnect()
|
|
{
|
|
AZ::TickBus::Handler::BusDisconnect();
|
|
IEntityBoundsUnionRequestBus::Handler::BusDisconnect();
|
|
AZ::TransformNotificationBus::Router::BusRouterDisconnect();
|
|
AZ::Interface<IEntityBoundsUnion>::Unregister(this);
|
|
}
|
|
|
|
void EntityVisibilityBoundsUnionSystem::OnEntityActivated(AZ::Entity* entity)
|
|
{
|
|
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework);
|
|
|
|
// ignore any entity that might activate which does not have a TransformComponent
|
|
if (entity->GetTransform() == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity);
|
|
instance_it == m_entityVisibilityBoundsUnionInstanceMapping.end())
|
|
{
|
|
AZ::TransformInterface* transformInterface = entity->GetTransform();
|
|
const AZ::Vector3 entityPosition = transformInterface->GetWorldTranslation();
|
|
|
|
EntityVisibilityBoundsUnionInstance instance;
|
|
instance.m_localEntityBoundsUnion = CalculateEntityLocalBoundsUnion(entity);
|
|
instance.m_visibilityEntry.m_typeFlags = VisibilityEntry::TYPE_Entity;
|
|
instance.m_visibilityEntry.m_userData = static_cast<void*>(entity);
|
|
|
|
auto next_it = m_entityVisibilityBoundsUnionInstanceMapping.insert({ entity, instance });
|
|
UpdateVisibilitySystem(entity, next_it.first->second);
|
|
}
|
|
}
|
|
|
|
void EntityVisibilityBoundsUnionSystem::OnEntityDeactivated(AZ::Entity* entity)
|
|
{
|
|
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework);
|
|
|
|
// ignore any entity that might activate which does not have a TransformComponent
|
|
if (entity->GetTransform() == nullptr)
|
|
{
|
|
return;
|
|
}
|
|
|
|
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity);
|
|
instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end())
|
|
{
|
|
if (IVisibilitySystem* visibilitySystem = AZ::Interface<IVisibilitySystem>::Get())
|
|
{
|
|
visibilitySystem->GetDefaultVisibilityScene()->RemoveEntry(instance_it->second.m_visibilityEntry);
|
|
m_entityVisibilityBoundsUnionInstanceMapping.erase(instance_it);
|
|
}
|
|
}
|
|
}
|
|
|
|
void EntityVisibilityBoundsUnionSystem::UpdateVisibilitySystem(AZ::Entity* entity, EntityVisibilityBoundsUnionInstance& instance)
|
|
{
|
|
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework);
|
|
|
|
if (const auto& localEntityBoundsUnions = instance.m_localEntityBoundsUnion; localEntityBoundsUnions.IsValid())
|
|
{
|
|
// note: worldEntityBounds will not be a 'tight-fit' Aabb but that of a transformed local aabb
|
|
// there will be some wasted space but it should be sufficient for the visibility system
|
|
AZ::TransformInterface* transformInterface = entity->GetTransform();
|
|
const AZ::Aabb worldEntityBoundsUnion = localEntityBoundsUnions.GetTransformedAabb(transformInterface->GetWorldTM());
|
|
IVisibilitySystem* visibilitySystem = AZ::Interface<IVisibilitySystem>::Get();
|
|
if (visibilitySystem && !worldEntityBoundsUnion.IsClose(instance.m_visibilityEntry.m_boundingVolume))
|
|
{
|
|
instance.m_visibilityEntry.m_boundingVolume = worldEntityBoundsUnion;
|
|
visibilitySystem->GetDefaultVisibilityScene()->InsertOrUpdateEntry(instance.m_visibilityEntry);
|
|
}
|
|
}
|
|
}
|
|
|
|
void EntityVisibilityBoundsUnionSystem::RefreshEntityLocalBoundsUnion(const AZ::EntityId entityId)
|
|
{
|
|
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(entityId);
|
|
if (entity != nullptr)
|
|
{
|
|
// track entities that need their bounds union to be recalculated
|
|
m_entityBoundsDirty.insert(entity);
|
|
}
|
|
}
|
|
|
|
AZ::Aabb EntityVisibilityBoundsUnionSystem::GetEntityLocalBoundsUnion(const AZ::EntityId entityId) const
|
|
{
|
|
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(entityId);
|
|
if (entity != nullptr)
|
|
{
|
|
// if the entity is not found in the mapping then return a null Aabb, this is to mimic
|
|
// as closely as possible the behavior of an individual GetLocalBounds call to an Entity that
|
|
// had been deleted (there would be no response, leaving the default value assigned)
|
|
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity);
|
|
instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end())
|
|
{
|
|
return instance_it->second.m_localEntityBoundsUnion;
|
|
}
|
|
}
|
|
|
|
return AZ::Aabb::CreateNull();
|
|
}
|
|
|
|
void EntityVisibilityBoundsUnionSystem::ProcessEntityBoundsUnionRequests()
|
|
{
|
|
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework);
|
|
|
|
// iterate over all entities whose bounds changed and recalculate them
|
|
for (const auto& entity : m_entityBoundsDirty)
|
|
{
|
|
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity);
|
|
instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end())
|
|
{
|
|
instance_it->second.m_localEntityBoundsUnion = CalculateEntityLocalBoundsUnion(entity);
|
|
UpdateVisibilitySystem(entity, instance_it->second);
|
|
}
|
|
}
|
|
|
|
// clear dirty entities once the visibility system has been updated
|
|
m_entityBoundsDirty.clear();
|
|
}
|
|
|
|
void EntityVisibilityBoundsUnionSystem::OnTransformChanged(const AZ::Transform&, const AZ::Transform&)
|
|
{
|
|
AZ_PROFILE_FUNCTION(AZ::Debug::ProfileCategory::AzFramework);
|
|
|
|
const AZ::EntityId entityId = *AZ::TransformNotificationBus::GetCurrentBusId();
|
|
AZ::Entity* entity = AZ::Interface<AZ::ComponentApplicationRequests>::Get()->FindEntity(entityId);
|
|
|
|
// update the world transform of the visibility bounds union
|
|
if (auto instance_it = m_entityVisibilityBoundsUnionInstanceMapping.find(entity);
|
|
instance_it != m_entityVisibilityBoundsUnionInstanceMapping.end())
|
|
{
|
|
UpdateVisibilitySystem(entity, instance_it->second);
|
|
}
|
|
}
|
|
|
|
void EntityVisibilityBoundsUnionSystem::OnTick(
|
|
[[maybe_unused]] float deltaTime, [[maybe_unused]] AZ::ScriptTimePoint time)
|
|
{
|
|
ProcessEntityBoundsUnionRequests();
|
|
}
|
|
} // namespace AzFramework
|