Added terrain surface data notifications (#5067)

* Fix notifications for surface data changes.
Separated the notifications from the surface component and the height component to add a reason to a RefreshArea request.  This makes it possible to distinguish between surface changes and height changes and provide the appropriate OnTerrainDataChanged flags.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>

* Reworked to use a changeMask instead of separate calls.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>

* PR Feedback
Judicious use of "using" to reduce a bunch of bulky namespaces.

Signed-off-by: Mike Balfour <82224783+mbalfour-amzn@users.noreply.github.com>
This commit is contained in:
Mike Balfour
2021-10-28 16:17:38 -05:00
committed by GitHub
parent 00a49fa251
commit 86270339d8
9 changed files with 52 additions and 19 deletions
@@ -76,6 +76,7 @@ void TerrainSystem::Activate()
m_dirtyRegion = AZ::Aabb::CreateNull();
m_terrainHeightDirty = true;
m_terrainSettingsDirty = true;
m_terrainSurfacesDirty = true;
m_requestedSettings.m_systemActive = true;
{
@@ -115,6 +116,7 @@ void TerrainSystem::Deactivate()
m_dirtyRegion = AZ::Aabb::CreateNull();
m_terrainHeightDirty = true;
m_terrainSettingsDirty = true;
m_terrainSurfacesDirty = true;
m_requestedSettings.m_systemActive = false;
AzFramework::Terrain::TerrainDataNotificationBus::Broadcast(
@@ -549,6 +551,7 @@ void TerrainSystem::RegisterArea(AZ::EntityId areaId)
m_registeredAreas[areaId] = aabb;
m_dirtyRegion.AddAabb(aabb);
m_terrainHeightDirty = true;
m_terrainSurfacesDirty = true;
}
void TerrainSystem::UnregisterArea(AZ::EntityId areaId)
@@ -567,14 +570,17 @@ void TerrainSystem::UnregisterArea(AZ::EntityId areaId)
{
m_dirtyRegion.AddAabb(aabb);
m_terrainHeightDirty = true;
m_terrainSurfacesDirty = true;
return true;
}
return false;
});
}
void TerrainSystem::RefreshArea(AZ::EntityId areaId)
void TerrainSystem::RefreshArea(AZ::EntityId areaId, AzFramework::Terrain::TerrainDataNotifications::TerrainDataChangedMask changeMask)
{
using Terrain = AzFramework::Terrain::TerrainDataNotifications;
AZStd::unique_lock<AZStd::shared_mutex> lock(m_areaMutex);
auto areaAabb = m_registeredAreas.find(areaId);
@@ -588,11 +594,18 @@ void TerrainSystem::RefreshArea(AZ::EntityId areaId)
expandedAabb.AddAabb(newAabb);
m_dirtyRegion.AddAabb(expandedAabb);
m_terrainHeightDirty = true;
// Keep track of which types of data have changed so that we can send out the appropriate notifications later.
m_terrainHeightDirty = m_terrainHeightDirty || ((changeMask & Terrain::HeightData) == Terrain::HeightData);
m_terrainSurfacesDirty = m_terrainSurfacesDirty || ((changeMask & Terrain::SurfaceData) == Terrain::SurfaceData);
}
void TerrainSystem::OnTick(float /*deltaTime*/, AZ::ScriptTimePoint /*time*/)
{
using Terrain = AzFramework::Terrain::TerrainDataNotifications;
bool terrainSettingsChanged = false;
if (m_terrainSettingsDirty)
@@ -607,6 +620,7 @@ void TerrainSystem::OnTick(float /*deltaTime*/, AZ::ScriptTimePoint /*time*/)
m_dirtyRegion = m_currentSettings.m_worldBounds;
m_dirtyRegion.AddAabb(m_requestedSettings.m_worldBounds);
m_terrainHeightDirty = true;
m_terrainSurfacesDirty = true;
m_currentSettings.m_worldBounds = m_requestedSettings.m_worldBounds;
}
@@ -614,12 +628,13 @@ void TerrainSystem::OnTick(float /*deltaTime*/, AZ::ScriptTimePoint /*time*/)
{
m_dirtyRegion = AZ::Aabb::CreateNull();
m_terrainHeightDirty = true;
m_terrainSurfacesDirty = true;
}
m_currentSettings = m_requestedSettings;
}
if (terrainSettingsChanged || m_terrainHeightDirty)
if (terrainSettingsChanged || m_terrainHeightDirty || m_terrainSurfacesDirty)
{
// Block other threads from accessing the surface data bus while we are in GetValue (which may call into the SurfaceData bus).
// We lock our surface data mutex *before* checking / setting "isRequestInProgress" so that we prevent race conditions
@@ -629,24 +644,27 @@ void TerrainSystem::OnTick(float /*deltaTime*/, AZ::ScriptTimePoint /*time*/)
auto& surfaceDataContext = SurfaceData::SurfaceDataSystemRequestBus::GetOrCreateContext(false);
typename SurfaceData::SurfaceDataSystemRequestBus::Context::DispatchLockGuard scopeLock(surfaceDataContext.m_contextMutex);
AzFramework::Terrain::TerrainDataNotifications::TerrainDataChangedMask changeMask =
AzFramework::Terrain::TerrainDataNotifications::TerrainDataChangedMask::None;
Terrain::TerrainDataChangedMask changeMask = Terrain::TerrainDataChangedMask::None;
if (terrainSettingsChanged)
{
changeMask = static_cast<AzFramework::Terrain::TerrainDataNotifications::TerrainDataChangedMask>(
changeMask | AzFramework::Terrain::TerrainDataNotifications::TerrainDataChangedMask::Settings);
changeMask = static_cast<Terrain::TerrainDataChangedMask>(changeMask | Terrain::TerrainDataChangedMask::Settings);
}
if (m_terrainHeightDirty)
{
changeMask = static_cast<AzFramework::Terrain::TerrainDataNotifications::TerrainDataChangedMask>(
changeMask | AzFramework::Terrain::TerrainDataNotifications::TerrainDataChangedMask::HeightData);
changeMask = static_cast<Terrain::TerrainDataChangedMask>(changeMask | Terrain::TerrainDataChangedMask::HeightData);
}
if (m_terrainSurfacesDirty)
{
changeMask = static_cast<Terrain::TerrainDataChangedMask>(changeMask | Terrain::TerrainDataChangedMask::SurfaceData);
}
// Make sure to set these *before* calling OnTerrainDataChanged, since it's possible that subsystems reacting to that call will
// cause the data to become dirty again.
AZ::Aabb dirtyRegion = m_dirtyRegion;
m_terrainHeightDirty = false;
m_terrainSurfacesDirty = false;
m_dirtyRegion = AZ::Aabb::CreateNull();
AzFramework::Terrain::TerrainDataNotificationBus::Broadcast(