Files
o3de/Gems/Vegetation/Code/Source/AreaSystemComponent.h
T
Artur K 56904d1799 Cry Legacy: the Lessening (#5961)
* Generic Cleanup

Removals:

* Unused cvars,member variables and defines
* Windows media center edition support routines
* CSystem - removed debug_GetCallStackRaw/GetRootWindowMessageHandler/
UnloadDLL/ShutdownModuleLibraries

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Fix CryMessageBox return values in Windows build

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Remove named selection group and a few smaller unused functionalities

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Remove ObjectManager export functionality + 2 deprecated functions

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Remove object legacy freeze/hide support from ObjectManager

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Remove ObjectManager duplicate name dection, as well as object renaming

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Remove ObjectManager serialization and selection callbacks

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* ObjectManager - remove MoveObjects/HitTestObject/EndEditParams and related members/functions

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Remove a bunch of unused clone related functionality + misc

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* ObjectManager - misc removals

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* ObjectManager - more removals

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Remove unused object selection/retrieval in ObjectManager and LoadObjects in ObjectLoader

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* CBaseObject - remove unused material layers mask support

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* More CBaseObject cleanups.

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* CBaseObject - remove SubObj functions and IMouseCreateCallback

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Remove unused procedural floor management, helper scale and tags.

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* CBaseObject - remove more unused methods.

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Removals in multiple places.

CBaseObject - unused `OBJTYPE_DUMMY` flag removed, member `IsSameClass`
CObjectArchive removed unused methods/members
CObjectManager removed unused `Update` method

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* More removals

IDisplayViewport - HitTestLine/GetGridStep/setHitcontext/
GetConstructionPlane
Unused Cry_Matrix44 template specializations.

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* O3DE.exe Project-Centric "Open Editor" fix (#5852)

* The O3DE.exe Open Editor button now attempts to open the Editor in the
build directory of the project being opened.

If their is no Editor within the build directory of the Project, it uses
the Editor.exe in the current O3DE.exe executable directory if it exists

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Engine .gitignore now ignores the build directory if placed in the
AutomatedTesting project

Previously it was just ignoring a `[Bb]uild` directory if it was
directly within the engine root.
This change matches the behavior of the project templates.

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Renamed the ProjectUtils GetEditorDirectory function to
GetEditorExecutablePath

Added a platform specific implementation for retrieving the path to the
Editor executable in the GetEditorExectuablePath function.

It first attempts to locate the Editor via checking the project build
directory for an Editor executable before falling back to checking the
binary directory of the currently running O3DE executable.

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>

* Correct the MacOS GetEditorExecutablePath to return the Editor path

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>
Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Adding missing C++20 std::erase implementations (#5735)

There were already implementations for std::erase_if.
This adds the counterpart AZStd::erase versions

resolves #5734

Signed-off-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>
Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* More removals and refactors

`ShowMessage` and `CryMessageBox` return void now
Simplify code in `CSystem::WarningV`
Remove unused `CryGetTicksPerSec`
Remove unused WinBase functionality
Replace `nanosleep` call in WinBase with `std::this_thread::sleep_for`
Remove unused Win32Wrapper routines
Remove unused IFunctorBase.h and IEntityObjectListener.h
Fix VectorAndArray.cpp compilation
Use QMessageBox instead of CryMessageBox in the editor.
Remove empty ArchiveVars platform specific files

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Fix test code.

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Remove an unused  function

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* CBaseObject and undo description removals.

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* A bunch of removals

* Remove IRenderNode
* Remove editor's KDTree
* Remove StatObjBus, InstanceStatObjEventBus::ReleaseData is redundant (
same functionality in the only available handler is triggered by
`OnCryEditorCloseScene`)
* Remove CExportManager::AddStatObj/AddMeshes/AddMesh,
IExportManager::ExportSingleStatObj
* Remove CIconManager/IIconManager::GetObject
* Remove CBaseObject::IntersectRayMesh
* Remove IIndexedMesh and related structs.
* Unused IUndoObject::GetDescription and all derived implementations.
* Unused CUndoBaseLibrary/CUndoBaseLibraryManager
* Unused Matrix34_tpl typedefs
* Legacy Xml classes cleanup

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* Remove unused `Vec3ToVector3D` helper

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

* fix - remove unused static variable

Signed-off-by: nemerle <96597+nemerle@users.noreply.github.com>

Co-authored-by: lumberyard-employee-dm <56135373+lumberyard-employee-dm@users.noreply.github.com>
2021-11-29 11:21:06 -07:00

489 lines
23 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
*
*/
#pragma once
#include <AzCore/Component/Component.h>
#include <Vegetation/Ebuses/AreaSystemRequestBus.h>
#include <Vegetation/Ebuses/AreaRequestBus.h>
#include <Vegetation/Ebuses/SystemConfigurationBus.h>
#include <AzCore/std/parallel/semaphore.h>
#include <AzCore/Component/TickBus.h>
#include <AzCore/std/parallel/thread.h>
#include <GradientSignal/Ebuses/SectorDataRequestBus.h>
#include <SurfaceData/SurfaceDataSystemNotificationBus.h>
#include <CrySystemBus.h>
#include <ISystem.h>
#include <AzFramework/Terrain/TerrainDataRequestBus.h>
namespace Vegetation
{
struct DebugData;
enum class SnapMode : AZ::u8
{
Corner = 0,
Center
};
/**
* The configuration for managing areas mostly the dimensions of the sectors
*/
class AreaSystemConfig
: public AZ::ComponentConfig
{
public:
AZ_CLASS_ALLOCATOR(AreaSystemConfig, AZ::SystemAllocator, 0);
AZ_RTTI(AreaSystemConfig, "{14CCBE43-52DD-4F56-92A8-2BB011A0F7A2}", AZ::ComponentConfig);
static void Reflect(AZ::ReflectContext* context);
bool operator == (const AreaSystemConfig& other) const
{
return m_viewRectangleSize == other.m_viewRectangleSize
&& m_sectorDensity == other.m_sectorDensity
&& m_sectorSizeInMeters == other.m_sectorSizeInMeters
&& m_threadProcessingIntervalMs == other.m_threadProcessingIntervalMs
&& m_sectorSearchPadding == other.m_sectorSearchPadding
&& m_sectorPointSnapMode == other.m_sectorPointSnapMode;
}
int m_viewRectangleSize = 13;
int m_sectorDensity = 20;
int m_sectorSizeInMeters = 16;
int m_threadProcessingIntervalMs = 500;
int m_sectorSearchPadding = 0;
SnapMode m_sectorPointSnapMode = SnapMode::Corner;
private:
static const int s_maxViewRectangleSize;
static const int s_maxSectorDensity;
static const int s_maxSectorSizeInMeters;
static const int s_maxInstancesPerMeter;
static const int64_t s_maxVegetationInstances;
AZ::Outcome<void, AZStd::string> ValidateViewArea(void* newValue, const AZ::Uuid& valueType);
AZ::Outcome<void, AZStd::string> ValidateSectorDensity(void* newValue, const AZ::Uuid& valueType);
AZ::Outcome<void, AZStd::string> ValidateSectorSize(void* newValue, const AZ::Uuid& valueType);
};
/**
* Manages an sectors and claims while the camera scrolls through the 3D world
*/
class AreaSystemComponent
: public AZ::Component
, private AZ::TickBus::Handler
, private AreaSystemRequestBus::Handler
, private GradientSignal::SectorDataRequestBus::Handler
, private SystemConfigurationRequestBus::Handler
, private CrySystemEventBus::Handler
, private ISystemEventListener
, private SurfaceData::SurfaceDataSystemNotificationBus::Handler
, private AzFramework::Terrain::TerrainDataNotificationBus::Handler
{
public:
friend class EditorAreaSystemComponent;
AZ_COMPONENT(AreaSystemComponent, "{7CE8E791-6BC6-4C88-8727-A476DE00F9A1}");
static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& services);
static void Reflect(AZ::ReflectContext* context);
AreaSystemComponent(const AreaSystemConfig& configuration);
AreaSystemComponent() = default;
~AreaSystemComponent() = default;
//////////////////////////////////////////////////////////////////////////
// AZ::Component interface implementation
void Init() override;
void Activate() override;
void Deactivate() override;
bool ReadInConfig(const AZ::ComponentConfig* baseConfig) override;
bool WriteOutConfig(AZ::ComponentConfig* outBaseConfig) const override;
//////////////////////////////////////////////////////////////////////////
// AreaSystemRequestBus
void RegisterArea(AZ::EntityId areaId, AZ::u32 layer, AZ::u32 priority, const AZ::Aabb& bounds) override;
void UnregisterArea(AZ::EntityId areaId) override;
void RefreshArea(AZ::EntityId areaId, AZ::u32 layer, AZ::u32 priority, const AZ::Aabb& bounds) override;
void RefreshAllAreas() override;
void ClearAllAreas() override;
void MuteArea(AZ::EntityId areaId) override;
void UnmuteArea(AZ::EntityId areaId) override;
void EnumerateInstancesInOverlappingSectors(const AZ::Aabb& bounds, AreaSystemEnumerateCallback callback) const override;
void EnumerateInstancesInAabb(const AZ::Aabb& bounds, AreaSystemEnumerateCallback callback) const override;
AZStd::size_t GetInstanceCountInAabb(const AZ::Aabb& bounds) const override;
AZStd::vector<Vegetation::InstanceData> GetInstancesInAabb(const AZ::Aabb& bounds) const override;
//////////////////////////////////////////////////////////////////////////
// GradientSignal::SectorDataRequestBus
void GetPointsPerMeter(float& value) const override;
//////////////////////////////////////////////////////////////////////////
// AZ::TickBus
void OnTick(float deltaTime, AZ::ScriptTimePoint time) override;
//////////////////////////////////////////////////////////////////////////
// SystemConfigurationRequestBus
void UpdateSystemConfig(const AZ::ComponentConfig* config) override;
void GetSystemConfig(AZ::ComponentConfig* config) const override;
//////////////////////////////////////////////////////////////////////////
// SurfaceData::SurfaceDataSystemNotificationBus
void OnSurfaceChanged(const AZ::EntityId& entityId, const AZ::Aabb& oldBounds, const AZ::Aabb& newBounds) override;
////////////////////////////////////////////////////////////////////////////
// CrySystemEvents
void OnCrySystemInitialized(ISystem& system, const SSystemInitParams& systemInitParams) override;
void OnCrySystemShutdown(ISystem& system) override;
void OnCryEditorBeginLevelExport() override;
void OnCryEditorEndLevelExport(bool /*success*/) override;
void OnCryEditorCloseScene() override;
//////////////////////////////////////////////////////////////////////////
// ISystemEventListener
void OnSystemEvent(ESystemEvent event, UINT_PTR wparam, UINT_PTR lparam) override;
//////////////////////////////////////////////////////////////////////////
// TerrainDataNotificationBus
void OnTerrainDataCreateBegin() override;
void OnTerrainDataDestroyBegin() override;
private:
using ClaimContainer = AZStd::unordered_map<ClaimHandle, InstanceData>;
using ClaimContainerEntry = AZStd::pair<ClaimHandle, InstanceData>;
using SectorId = AZStd::pair<int, int>;
// SectorInfo contains basic sector information and the set of "plantable points" in the sector that have been claimed
struct SectorInfo
{
AZ_CLASS_ALLOCATOR(SectorInfo, AZ::SystemAllocator, 0);
SectorId m_id = {};
AZ::Aabb m_bounds = {};
//! Keeps track of points that have been claimed. This is not cleared at the start of an update pass
ClaimContainer m_claimedWorldPoints;
//! Keeps track of previous state of sector while filling to avoid redundant instance destroy/create calls
ClaimContainer m_claimedWorldPointsBeforeFill;
ClaimContext m_baseContext;
int GetSectorX() const { return m_id.first; }
int GetSectorY() const { return m_id.second; }
};
// VegetationAreaInfo contains the basic information we need for tracking which vegetation areas to apply
// to which sectors, and in which order.
struct VegetationAreaInfo
{
AZ_CLASS_ALLOCATOR(VegetationAreaInfo, AZ::SystemAllocator, 0);
AZ::EntityId m_id;
AZ::Aabb m_bounds = {};
AZ::u32 m_layer = {};
AZ::u32 m_priority = {};
};
using VegetationAreaMap = AZStd::unordered_map<AZ::EntityId, VegetationAreaInfo>;
using VegetationAreaSet = AZStd::unordered_set<AZ::EntityId>;
using VegetationAreaVector = AZStd::vector<VegetationAreaInfo>;
using UnregisteredVegetationAreaMap = AZStd::unordered_map<SectorId, AZStd::unordered_set<AZ::EntityId>>;
//! Helper class to track whether or not a visible sector is dirty. Different instances of this
//! class are used to track different reasons for being dirty.
//! This is a class instead of just an unordered_set<> so that we can also encapsulate the optimization
//! of tracking when *all* sectors are dirty.
class DirtySectors
{
public:
DirtySectors() = default;
~DirtySectors() = default;
void MarkDirty(const SectorId& id);
void MarkAllDirty();
bool IsAllDirty() const { return m_allSectorsDirty; }
bool IsNoneDirty() const { return (!m_allSectorsDirty) && m_dirtySet.empty(); }
bool IsDirty(const SectorId& id) const;
void Clear();
private:
using DirtySectorSet = AZStd::unordered_set<SectorId>;
DirtySectorSet m_dirtySet;
//! Flag when *all* existing sectors are dirty
bool m_allSectorsDirty = false;
};
// ViewRect is a helper struct to manage the "scrolling view rectangle". This view rectangle controls the
// set of active spawned vegetation.
struct ViewRect
{
int m_x = 0;
int m_y = 0;
int m_width = 0;
int m_height = 0;
AZ::Aabb m_viewRectBounds = AZ::Aabb::CreateNull();
ViewRect() = default;
ViewRect(int inX, int inY, int inW, int inH, AZ::Aabb viewRectBounds)
: m_x(inX)
, m_y(inY)
, m_width(inW)
, m_height(inH)
, m_viewRectBounds(viewRectBounds)
{
}
bool IsInside(const SectorId& sector) const;
ViewRect Overlap(const ViewRect& b) const;
bool operator !=(const ViewRect& b);
bool operator ==(const ViewRect& b);
size_t GetNumSectors() const;
int GetMinXSector() const { return m_x; }
int GetMinYSector() const { return m_y; }
int GetMaxXSector() const { return m_x + m_width - 1; }
int GetMaxYSector() const { return m_y + m_height - 1; }
SectorId GetMinSector() const { return SectorId(GetMinXSector(), GetMinYSector()); }
SectorId GetMaxSector() const { return SectorId(GetMaxXSector(), GetMaxYSector()); }
AZ::Aabb GetViewRectBounds() const { return m_viewRectBounds; }
};
// Forward declarations, these get defined further down.
class UpdateContext;
class PersistentThreadData;
// Thread-local copies of main state. We make copies of this to ensure that we can process sectors safely on
// the vegetation thread while these values potentially get changed on the main thread without needing to wrap
// all access with mutexes.
struct CachedMainThreadData
{
float m_worldToSector = 0.0f;
ViewRect m_currViewRect = {};
int m_sectorSizeInMeters = 0;
int m_sectorDensity = 0;
SnapMode m_sectorPointSnapMode = SnapMode::Corner;
};
// VegetationThreadTasks is the task queue that's used equally by the main thread and the vegetation thread.
// The main thread generally queues the tasks, and the vegetation thread processes them.
// Any data used from this class requires mutexes, atomics, or other thread protection.
class VegetationThreadTasks
{
public:
void QueueVegetationTask(AZStd::function<void(UpdateContext* context, PersistentThreadData* threadData, VegetationThreadTasks * vegTasks)> func);
void ProcessVegetationThreadTasks(UpdateContext* context, PersistentThreadData* threadData);
bool VegetationThreadTasksPending()
{
AZStd::lock_guard<decltype(m_vegetationThreadTaskMutex)> lock(m_vegetationThreadTaskMutex);
return !m_vegetationThreadTasks.empty();
}
//! Get sector by 2d veg map coordinates.
const SectorInfo* GetSector(const SectorId& sectorId) const;
SectorInfo* GetSector(const SectorId& sectorId);
SectorInfo* CreateSector(const SectorId& sectorId, int sectorDensity, int sectorSizeInMeters, SnapMode sectorPointSnapMode);
void UpdateSectorPoints(SectorInfo& sectorInfo, int sectorDensity, int sectorSizeInMeters, SnapMode sectorPointSnapMode);
void FillSector(SectorInfo& sectorInfo, const VegetationAreaVector& activeAreas);
void DeleteSector(const SectorId& sectorId);
void ClearSectors();
//! Gets the AABB for a sector
static AZ::Aabb GetSectorBounds(const SectorId& sectorId, int sectorSizeInMeters);
void FetchDebugData();
void MarkDirtySectors(const AZ::Aabb& bounds, DirtySectors& dirtySet, float worldToSector, const ViewRect& viewRect);
void AddUnregisteredVegetationArea(const VegetationAreaInfo& area, float worldToSector, const ViewRect& viewRect);
//! 2D Array rolling window of sectors that store vegetation objects.
using SectorRollingWindow = AZStd::unordered_map<SectorId, SectorInfo>;
mutable AZStd::recursive_mutex m_sectorRollingWindowMutex;
SectorRollingWindow m_sectorRollingWindow;
private:
// claiming logic
void CreateClaim(SectorInfo& sectorInfo, const ClaimHandle handle, const InstanceData& instanceData);
ClaimHandle CreateClaimHandle(const SectorInfo& sectorInfo, uint32_t index) const;
void ReleaseUnusedClaims(SectorInfo& sectorInfo);
void ReleaseUnregisteredClaims(SectorInfo& sectorInfo);
//! Creates a new sector
void UpdateSectorCallbacks(SectorInfo& sectorInfo);
static void EmptySector(SectorInfo& sectorInfo);
// Calls the given function on each sector in the box
template<class Fn>
static void EnumerateSectorsInAabb(const AZ::Aabb& bounds, float worldToSector, const ViewRect& viewRect, Fn&& fn);
//! Queued list of vegetation area state update requests. These get queued on the main thread, and processed
//! on the vegetation thread.
mutable AZStd::recursive_mutex m_vegetationThreadTaskMutex;
using VegetationThreadTaskList = AZStd::list<AZStd::function<void(UpdateContext* context, PersistentThreadData* threadData, VegetationThreadTasks* vegTasks)>>;
VegetationThreadTaskList m_vegetationThreadTasks;
//! Map from sectors to areas affecting that sector which have been unregistered and need to have their claims released
//! Note: This is only updated from the vegetation thread when processing vegetation tasks.
UnregisteredVegetationAreaMap m_unregisteredVegetationAreaSet;
//! Cached pointer to the debug data.
//! Note: This doesn't have an associated mutex because DebugData itself consists purely of atomics
DebugData* m_debugData = nullptr;
};
//! Helper struct to hold the state data used by the vegetation thread. This contains all the data
//! that should persist between thread runs, which lets us completely shut down the thread when there's
//! no work to do.
//! This also contains the vegetation thread mutex and state variables, which are accessed by both threads
//! to manage synchronization.
class PersistentThreadData
{
public:
// This mutex is active the entire time the vegetation thread is running. Its main purpose
// is to ensure we don't have component activations / deactivations that occur while the vegetation
// thread is still processing.
mutable AZStd::recursive_mutex m_vegetationThreadMutex;
// Current state of the vegetation thread
enum class VegetationThreadState
{
Stopped,
Running,
InterruptRequested
};
AZStd::atomic<VegetationThreadState> m_vegetationThreadState{ VegetationThreadState::Stopped };
// Current state of data synchronization between main thread and vegetation thread
enum class VegetationDataSyncState
{
Synchronized,
Dirty,
Updating
};
AZStd::atomic<VegetationDataSyncState> m_vegetationDataSyncState{ VegetationDataSyncState::Synchronized };
//! Reset the states that can get recalculated when the vegetation thread is run.
//! This does *not* reset the states on registered vegetation area lists, since those only
//! get filled out once.
void Init()
{
m_activeAreasDirty = true;
m_activeAreas.clear();
m_activeAreasInBubble.clear();
m_dirtySectorContents.Clear();
m_dirtySectorSurfacePoints.Clear();
}
void InterruptVegetationThread();
// The following state is public because it's accessed by queued vegetation tasks and UpdateContext. It should
// eventually be encapsulated a little better.
//! set of sectors that need their contents refreshed
DirtySectors m_dirtySectorContents;
//! set of sectors that need their surface points recalculated (which implies also needing the contents refreshed)
DirtySectors m_dirtySectorSurfacePoints;
VegetationAreaMap m_globalVegetationAreaMap;
VegetationAreaSet m_ignoredVegetationAreaSet;
//! Determines when to refresh the set of active areas
bool m_activeAreasDirty = true;
protected:
// Only UpdateContext is allowed to directly access the persisted thread state.
friend class UpdateContext;
// This is effectively a local variable in UpdateActiveVegetationAreas, but is kept
// persistent to avoid potentially frequent reallocation.
VegetationAreaVector m_activeAreas;
//! The set of active vegetation areas that overlap the current view rectangle
VegetationAreaVector m_activeAreasInBubble;
};
// UpdateContext is the logic that normally runs on the vegetation thread. It processes all of the logic needed to update and fill
// any vegetation sectors that are currently within the view rectangle. Occasionally the logic will be triggered on the main thread
// in cases such as shutdown when the vegetation thread isn't running any we need to perform the cleanup synchronously.
class UpdateContext
{
public:
UpdateContext() = default;
void Run(PersistentThreadData* threadData, VegetationThreadTasks* vegTasks, CachedMainThreadData* cachedMainThreadData);
void UpdateActiveVegetationAreas(PersistentThreadData* threadData, const ViewRect& viewRect);
const CachedMainThreadData& GetCachedMainThreadData() { return m_cachedMainThreadData; }
private:
bool UpdateSectorWorkLists(PersistentThreadData* threadData, VegetationThreadTasks* vegTasks);
bool UpdateOneSector(PersistentThreadData* threadData, VegetationThreadTasks* vegTasks);
enum class UpdateMode
{
Create,
RebuildSurfaceCacheAndFill,
Fill
};
// The sorted work list of sectors to delete. The list is recreated every time UpdateSectorWorkLists() is run.
AZStd::vector<SectorId> m_deleteWorkList;
// The sorted work list of sectors to create / update. This is incrementally modified when UpdateSectorWorkLists()
// is run, because any previously-requested updates that are still in view need to be preserved. They can't simply
// be recalculated.
AZStd::vector<AZStd::pair<SectorId, UpdateMode>> m_updateWorkList;
// Sector counts of the number of expected sectors in the view rectangle vs the number of sectors
// currently active. These are used to "load balance" sector deletes and creates so that we don't have
// too many sectors active at any one point in time.
size_t m_viewRectSectorCount = 0;
// Thread-local copy of the main thread's m_cachedMainThreadData. This way we can read from it on the vegetation
// thread without requiring mutexes.
CachedMainThreadData m_cachedMainThreadData;
};
bool ApplyPendingConfigChanges();
void ReleaseData();
void ReleaseAllClaims();
void ReleaseWithoutCleanup();
bool CalculateViewRect();
//! Get sector id by world coordinates.
static SectorId GetSectorId(const AZ::Vector3& worldPos, float worldToSector);
// All of this state data should only get accessed by the main thread. A subset of this data gets copied
// into CachedMainThreadData for the vegetation thread to be able to query in a lockless manner.
AreaSystemConfig m_configuration;
float m_worldToSector = 0.0f; //! world to sector scaling ratio.
ViewRect m_currViewRect = {};
float m_vegetationThreadTaskTimer = 0.0f;
ISystem* m_system = nullptr;
bool m_configDirty = false;
AreaSystemConfig m_pendingConfigUpdate;
// The vegetation task queue gets read/written from both threads, and uses atomics + mutexes for synchronization.
VegetationThreadTasks m_vegTasks;
// This state should only get read or written from the vegetation thread, except for component initialization.
PersistentThreadData m_threadData;
// This state gets written to from the main thread, and gets copied and read from the vegetation thread.
CachedMainThreadData m_cachedMainThreadData;
};
}