SurfaceDataSystemComponent.cpp 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581
  1. /*
  2. * Copyright (c) Contributors to the Open 3D Engine Project.
  3. * For complete copyright and license terms please see the LICENSE at the root of this distribution.
  4. *
  5. * SPDX-License-Identifier: Apache-2.0 OR MIT
  6. *
  7. */
  8. #include <AzCore/Debug/Profiler.h>
  9. #include <AzCore/RTTI/BehaviorContext.h>
  10. #include <AzCore/Serialization/SerializeContext.h>
  11. #include <AzCore/Serialization/EditContext.h>
  12. #include <AzCore/std/sort.h>
  13. #include <SurfaceData/Components/SurfaceDataSystemComponent.h>
  14. #include <SurfaceData/SurfaceDataConstants.h>
  15. #include <SurfaceData/SurfaceTag.h>
  16. #include <SurfaceData/SurfaceDataSystemNotificationBus.h>
  17. #include <SurfaceData/SurfaceDataProviderRequestBus.h>
  18. #include <SurfaceData/Utility/SurfaceDataUtility.h>
  19. #include <SurfaceDataProfiler.h>
  20. AZ_DEFINE_BUDGET(SurfaceData);
  21. namespace SurfaceData
  22. {
  23. void SurfaceDataSystemComponent::Reflect(AZ::ReflectContext* context)
  24. {
  25. SurfaceTag::Reflect(context);
  26. if (AZ::SerializeContext* serialize = azrtti_cast<AZ::SerializeContext*>(context))
  27. {
  28. serialize->Class<SurfaceDataSystemComponent, AZ::Component>()
  29. ->Version(0)
  30. ;
  31. if (AZ::EditContext* ec = serialize->GetEditContext())
  32. {
  33. ec->Class<SurfaceDataSystemComponent>("Surface Data System", "Manages registration of surface data providers and forwards intersection data requests to them")
  34. ->ClassElement(AZ::Edit::ClassElements::EditorData, "")
  35. ->Attribute(AZ::Edit::Attributes::AutoExpand, true)
  36. ;
  37. }
  38. }
  39. if (auto behaviorContext = azrtti_cast<AZ::BehaviorContext*>(context))
  40. {
  41. behaviorContext->Class<SurfacePointList>()
  42. ->Constructor()
  43. ->Attribute(AZ::Script::Attributes::Category, "Vegetation")
  44. ->Attribute(AZ::Script::Attributes::Module, "surface_data")
  45. ;
  46. behaviorContext->Class<SurfaceDataSystemComponent>()
  47. ->RequestBus("SurfaceDataSystemRequestBus")
  48. ;
  49. behaviorContext->EBus<SurfaceDataSystemRequestBus>("SurfaceDataSystemRequestBus")
  50. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
  51. ->Attribute(AZ::Script::Attributes::Category, "Vegetation")
  52. ->Attribute(AZ::Script::Attributes::Module, "surface_data")
  53. ->Event(
  54. "GetSurfacePoints",
  55. [](SurfaceData::SurfaceDataSystem* handler, const AZ::Vector3& inPosition, const SurfaceTagVector& desiredTags) -> AZStd::vector<AzFramework::SurfaceData::SurfacePoint>
  56. {
  57. AZStd::vector<AzFramework::SurfaceData::SurfacePoint> result;
  58. SurfaceData::SurfacePointList surfacePointList;
  59. handler->GetSurfacePoints(inPosition, desiredTags, surfacePointList);
  60. surfacePointList.EnumeratePoints(
  61. [&result](
  62. [[maybe_unused]] size_t inPositionIndex, const AZ::Vector3& position, const AZ::Vector3& normal, const SurfaceData::SurfaceTagWeights& masks)-> bool
  63. {
  64. AzFramework::SurfaceData::SurfacePoint point;
  65. point.m_position = position;
  66. point.m_normal = normal;
  67. point.m_surfaceTags = masks.GetSurfaceTagWeightList();
  68. result.emplace_back(point);
  69. return true;
  70. });
  71. return result;
  72. })
  73. ->Event("RefreshSurfaceData", &SurfaceDataSystemRequestBus::Events::RefreshSurfaceData)
  74. ->Event("GetSurfaceDataProviderHandle", &SurfaceDataSystemRequestBus::Events::GetSurfaceDataProviderHandle)
  75. ->Event("GetSurfaceDataModifierHandle", &SurfaceDataSystemRequestBus::Events::GetSurfaceDataModifierHandle)
  76. ;
  77. behaviorContext->EBus<SurfaceDataSystemNotificationBus>("SurfaceDataSystemNotificationBus")
  78. ->Attribute(AZ::Script::Attributes::Scope, AZ::Script::Attributes::ScopeFlags::Common)
  79. ->Attribute(AZ::Script::Attributes::Category, "Vegetation")
  80. ->Attribute(AZ::Script::Attributes::Module, "surface_data")
  81. ->Event("OnSurfaceChanged", &SurfaceDataSystemNotificationBus::Events::OnSurfaceChanged)
  82. ;
  83. }
  84. }
  85. void SurfaceDataSystemComponent::GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  86. {
  87. provided.push_back(AZ_CRC_CE("SurfaceDataSystemService"));
  88. }
  89. void SurfaceDataSystemComponent::GetIncompatibleServices(AZ::ComponentDescriptor::DependencyArrayType& incompatible)
  90. {
  91. incompatible.push_back(AZ_CRC_CE("SurfaceDataSystemService"));
  92. }
  93. void SurfaceDataSystemComponent::GetRequiredServices(AZ::ComponentDescriptor::DependencyArrayType& required)
  94. {
  95. (void)required;
  96. }
  97. void SurfaceDataSystemComponent::GetDependentServices(AZ::ComponentDescriptor::DependencyArrayType& dependent)
  98. {
  99. (void)dependent;
  100. }
  101. void SurfaceDataSystemComponent::Init()
  102. {
  103. }
  104. void SurfaceDataSystemComponent::Activate()
  105. {
  106. AZ::Interface<SurfaceDataSystem>::Register(this);
  107. SurfaceDataSystemRequestBus::Handler::BusConnect();
  108. }
  109. void SurfaceDataSystemComponent::Deactivate()
  110. {
  111. SurfaceDataSystemRequestBus::Handler::BusDisconnect();
  112. AZ::Interface<SurfaceDataSystem>::Unregister(this);
  113. }
  114. SurfaceDataRegistryHandle SurfaceDataSystemComponent::RegisterSurfaceDataProvider(const SurfaceDataRegistryEntry& entry)
  115. {
  116. const SurfaceDataRegistryHandle handle = RegisterSurfaceDataProviderInternal(entry);
  117. if (handle != InvalidSurfaceDataRegistryHandle)
  118. {
  119. // Get the set of surface tags that can be affected by adding the surface data provider.
  120. // This includes all of the provider's tags, as well as any surface modifier tags that exist in the bounds,
  121. // because new surface points have the potential of getting the modifier tags applied as well.
  122. SurfaceTagSet affectedSurfaceTags = GetAffectedSurfaceTags(entry.m_bounds, entry.m_tags);
  123. // Send in the entry's bounds as both the old and new bounds, since a null Aabb for old bounds
  124. // would cause a full refresh for any system listening, instead of just a refresh within the bounds.
  125. SurfaceDataSystemNotificationBus::Broadcast(
  126. &SurfaceDataSystemNotificationBus::Events::OnSurfaceChanged, entry.m_entityId, entry.m_bounds, entry.m_bounds,
  127. affectedSurfaceTags);
  128. }
  129. return handle;
  130. }
  131. void SurfaceDataSystemComponent::UnregisterSurfaceDataProvider(const SurfaceDataRegistryHandle& handle)
  132. {
  133. const SurfaceDataRegistryEntry entry = UnregisterSurfaceDataProviderInternal(handle);
  134. if (entry.m_entityId.IsValid())
  135. {
  136. // Get the set of surface tags that can be affected by adding the surface data provider.
  137. // This includes all of the provider's tags, as well as any surface modifier tags that exist in the bounds,
  138. // because the removed surface points have the potential of getting the modifier tags applied as well.
  139. SurfaceTagSet affectedSurfaceTags = GetAffectedSurfaceTags(entry.m_bounds, entry.m_tags);
  140. // Send in the entry's bounds as both the old and new bounds, since a null Aabb for old bounds
  141. // would cause a full refresh for any system listening, instead of just a refresh within the bounds.
  142. SurfaceDataSystemNotificationBus::Broadcast(
  143. &SurfaceDataSystemNotificationBus::Events::OnSurfaceChanged, entry.m_entityId, entry.m_bounds, entry.m_bounds,
  144. affectedSurfaceTags);
  145. }
  146. }
  147. void SurfaceDataSystemComponent::UpdateSurfaceDataProvider(const SurfaceDataRegistryHandle& handle, const SurfaceDataRegistryEntry& entry)
  148. {
  149. AZ::Aabb oldBounds = AZ::Aabb::CreateNull();
  150. if (UpdateSurfaceDataProviderInternal(handle, entry, oldBounds))
  151. {
  152. // Get the set of surface tags that can be affected by adding the surface data provider.
  153. // This includes all of the provider's tags, as well as any surface modifier tags that exist in the bounds,
  154. // because the affected surface points have the potential of getting the modifier tags applied as well.
  155. // For now, we'll just merge the old and new bounds into a larger region. If this causes too much refreshing to occur,
  156. // this could eventually be improved by getting the tags from both sets of bounds separately and combining them.
  157. AZ::Aabb surfaceTagBounds = oldBounds;
  158. surfaceTagBounds.AddAabb(entry.m_bounds);
  159. SurfaceTagSet affectedSurfaceTags = GetAffectedSurfaceTags(surfaceTagBounds, entry.m_tags);
  160. SurfaceDataSystemNotificationBus::Broadcast(
  161. &SurfaceDataSystemNotificationBus::Events::OnSurfaceChanged, entry.m_entityId, oldBounds, entry.m_bounds,
  162. affectedSurfaceTags);
  163. }
  164. }
  165. SurfaceDataRegistryHandle SurfaceDataSystemComponent::RegisterSurfaceDataModifier(const SurfaceDataRegistryEntry& entry)
  166. {
  167. const SurfaceDataRegistryHandle handle = RegisterSurfaceDataModifierInternal(entry);
  168. if (handle != InvalidSurfaceDataRegistryHandle)
  169. {
  170. // Get the set of surface tags that can be affected by adding a surface data modifier. Since this doesn't create
  171. // any new surface points, we only need to broadcast the modifier tags themselves as the ones that changed.
  172. const SurfaceTagSet affectedSurfaceTags = ConvertTagVectorToSet(entry.m_tags);
  173. // Send in the entry's bounds as both the old and new bounds, since a null Aabb for old bounds
  174. // would cause a full refresh for any system listening, instead of just a refresh within the bounds.
  175. SurfaceDataSystemNotificationBus::Broadcast(
  176. &SurfaceDataSystemNotificationBus::Events::OnSurfaceChanged, entry.m_entityId,
  177. entry.m_bounds, entry.m_bounds, affectedSurfaceTags);
  178. }
  179. return handle;
  180. }
  181. void SurfaceDataSystemComponent::UnregisterSurfaceDataModifier(const SurfaceDataRegistryHandle& handle)
  182. {
  183. const SurfaceDataRegistryEntry entry = UnregisterSurfaceDataModifierInternal(handle);
  184. if (entry.m_entityId.IsValid())
  185. {
  186. // Get the set of surface tags that can be affected by removing a surface data modifier. Since this doesn't create
  187. // any new surface points, we only need to broadcast the modifier tags themselves as the ones that changed.
  188. const SurfaceTagSet affectedSurfaceTags = ConvertTagVectorToSet(entry.m_tags);
  189. // Send in the entry's bounds as both the old and new bounds, since a null Aabb for old bounds
  190. // would cause a full refresh for any system listening, instead of just a refresh within the bounds.
  191. SurfaceDataSystemNotificationBus::Broadcast(
  192. &SurfaceDataSystemNotificationBus::Events::OnSurfaceChanged, entry.m_entityId, entry.m_bounds, entry.m_bounds,
  193. affectedSurfaceTags);
  194. }
  195. }
  196. void SurfaceDataSystemComponent::UpdateSurfaceDataModifier(const SurfaceDataRegistryHandle& handle, const SurfaceDataRegistryEntry& entry)
  197. {
  198. AZ::Aabb oldBounds = AZ::Aabb::CreateNull();
  199. // Get the previous set of surface tags for this modifier.
  200. SurfaceTagSet affectedSurfaceTags;
  201. {
  202. AZStd::shared_lock<decltype(m_registrationMutex)> registrationLock(m_registrationMutex);
  203. auto entryItr = m_registeredSurfaceDataModifiers.find(handle);
  204. if (entryItr != m_registeredSurfaceDataModifiers.end())
  205. {
  206. affectedSurfaceTags = ConvertTagVectorToSet(entryItr->second.m_tags);
  207. }
  208. }
  209. // Merge in the new set of surface tags for this modifier. Since modifiers don't create
  210. // any new surface points, we only need to broadcast the modifier tags themselves as the ones that changed.
  211. for (auto& tag : entry.m_tags)
  212. {
  213. affectedSurfaceTags.emplace(tag);
  214. }
  215. if (UpdateSurfaceDataModifierInternal(handle, entry, oldBounds))
  216. {
  217. SurfaceDataSystemNotificationBus::Broadcast(
  218. &SurfaceDataSystemNotificationBus::Events::OnSurfaceChanged, entry.m_entityId, oldBounds, entry.m_bounds,
  219. affectedSurfaceTags);
  220. }
  221. }
  222. void SurfaceDataSystemComponent::RefreshSurfaceData(const SurfaceDataRegistryHandle& providerHandle, const AZ::Aabb& dirtyBounds)
  223. {
  224. auto entryItr = m_registeredSurfaceDataProviders.find(providerHandle);
  225. if (entryItr != m_registeredSurfaceDataProviders.end())
  226. {
  227. // Get the set of surface tags that can be affected by refreshing a surface data provider.
  228. // This includes all of the provider's tags, as well as any surface modifier tags that exist in the bounds,
  229. // because the affected surface points have the potential of getting the modifier tags applied as well.
  230. SurfaceTagSet affectedSurfaceTags = GetAffectedSurfaceTags(dirtyBounds, entryItr->second.m_tags);
  231. SurfaceDataSystemNotificationBus::Broadcast(
  232. &SurfaceDataSystemNotificationBus::Events::OnSurfaceChanged, AZ::EntityId(), dirtyBounds, dirtyBounds, affectedSurfaceTags);
  233. }
  234. }
  235. SurfaceDataRegistryHandle SurfaceDataSystemComponent::GetSurfaceDataProviderHandle(const AZ::EntityId& providerEntityId)
  236. {
  237. AZStd::shared_lock<decltype(m_registrationMutex)> registrationLock(m_registrationMutex);
  238. for (auto& [providerHandle, providerEntry] : m_registeredSurfaceDataProviders)
  239. {
  240. if (providerEntry.m_entityId == providerEntityId)
  241. {
  242. return providerHandle;
  243. }
  244. }
  245. return {};
  246. }
  247. SurfaceDataRegistryHandle SurfaceDataSystemComponent::GetSurfaceDataModifierHandle(const AZ::EntityId& modifierEntityId)
  248. {
  249. AZStd::shared_lock<decltype(m_registrationMutex)> registrationLock(m_registrationMutex);
  250. for (auto& [modifierHandle, modifierEntry] : m_registeredSurfaceDataModifiers)
  251. {
  252. if (modifierEntry.m_entityId == modifierEntityId)
  253. {
  254. return modifierHandle;
  255. }
  256. }
  257. return {};
  258. }
  259. void SurfaceDataSystemComponent::GetSurfacePoints(const AZ::Vector3& inPosition, const SurfaceTagVector& desiredTags, SurfacePointList& surfacePointList) const
  260. {
  261. GetSurfacePointsFromListInternal(
  262. AZStd::span<const AZ::Vector3>(&inPosition, 1), AZ::Aabb::CreateFromPoint(inPosition), desiredTags, surfacePointList);
  263. }
  264. void SurfaceDataSystemComponent::GetSurfacePointsFromRegion(const AZ::Aabb& inRegion, const AZ::Vector2 stepSize,
  265. const SurfaceTagVector& desiredTags, SurfacePointList& surfacePointLists) const
  266. {
  267. const size_t totalQueryPositions = aznumeric_cast<size_t>(ceil(inRegion.GetXExtent() / stepSize.GetX())) *
  268. aznumeric_cast<size_t>(ceil(inRegion.GetYExtent() / stepSize.GetY()));
  269. AZStd::vector<AZ::Vector3> inPositions;
  270. inPositions.reserve(totalQueryPositions);
  271. // Initialize our list-per-position list with every input position to query from the region.
  272. // This is inclusive on the min sides of inRegion, and exclusive on the max sides.
  273. for (float y = inRegion.GetMin().GetY(); y < inRegion.GetMax().GetY(); y += stepSize.GetY())
  274. {
  275. for (float x = inRegion.GetMin().GetX(); x < inRegion.GetMax().GetX(); x += stepSize.GetX())
  276. {
  277. inPositions.emplace_back(x, y, AZ::Constants::FloatMax);
  278. }
  279. }
  280. GetSurfacePointsFromListInternal(inPositions, inRegion, desiredTags, surfacePointLists);
  281. }
  282. void SurfaceDataSystemComponent::GetSurfacePointsFromList(
  283. AZStd::span<const AZ::Vector3> inPositions,
  284. const SurfaceTagVector& desiredTags,
  285. SurfacePointList& surfacePointLists) const
  286. {
  287. AZ::Aabb inBounds = AZ::Aabb::CreateNull();
  288. for (auto& position : inPositions)
  289. {
  290. inBounds.AddPoint(position);
  291. }
  292. GetSurfacePointsFromListInternal(inPositions, inBounds, desiredTags, surfacePointLists);
  293. }
  294. void SurfaceDataSystemComponent::GetSurfacePointsFromListInternal(
  295. AZStd::span<const AZ::Vector3> inPositions, const AZ::Aabb& inPositionBounds,
  296. const SurfaceTagVector& desiredTags, SurfacePointList& surfacePointLists) const
  297. {
  298. SURFACE_DATA_PROFILE_FUNCTION_VERBOSE
  299. AZStd::shared_lock<decltype(m_registrationMutex)> registrationLock(m_registrationMutex);
  300. const bool useTagFilters = HasValidTags(desiredTags);
  301. const bool hasModifierTags = useTagFilters && HasAnyMatchingTags(desiredTags, m_registeredModifierTags);
  302. // Clear our output structure.
  303. surfacePointLists.Clear();
  304. auto ProviderIsApplicable = [useTagFilters, hasModifierTags, &desiredTags, &inPositionBounds]
  305. (const SurfaceDataRegistryEntry& provider) -> bool
  306. {
  307. bool hasInfiniteBounds = !provider.m_bounds.IsValid();
  308. // Only allow surface providers that match our tag filters. However, if we aren't using tag filters,
  309. // or if there's at least one surface modifier that can *add* a filtered tag to a created point, then
  310. // allow all the surface providers.
  311. if (!useTagFilters || hasModifierTags || HasAnyMatchingTags(desiredTags, provider.m_tags))
  312. {
  313. // Only allow surface providers that overlap the input position area.
  314. if (hasInfiniteBounds || AabbOverlaps2D(provider.m_bounds, inPositionBounds))
  315. {
  316. return true;
  317. }
  318. }
  319. return false;
  320. };
  321. // Gather up the subset of surface providers that overlap the input positions.
  322. size_t maxPointsCreatedPerInput = 0;
  323. for (const auto& [providerHandle, provider] : m_registeredSurfaceDataProviders)
  324. {
  325. if (ProviderIsApplicable(provider))
  326. {
  327. maxPointsCreatedPerInput += provider.m_maxPointsCreatedPerInput;
  328. }
  329. }
  330. // If we don't have any surface providers that will create any new surface points, then there's nothing more to do.
  331. if (maxPointsCreatedPerInput == 0)
  332. {
  333. return;
  334. }
  335. // Notify our output structure that we're starting to build up the list of output points.
  336. // This will reserve memory and allocate temporary structures to help build up the list efficiently.
  337. AZStd::span<const SurfaceTag> tagFilters;
  338. if (useTagFilters)
  339. {
  340. tagFilters = desiredTags;
  341. }
  342. {
  343. SURFACE_DATA_PROFILE_SCOPE_VERBOSE("GetSurfacePointsFromListInternal: StartListConstruction");
  344. surfacePointLists.StartListConstruction(inPositions, maxPointsCreatedPerInput, tagFilters);
  345. }
  346. // Loop through each data provider and generate surface points from the set of input positions.
  347. // Any generated points that have the same XY coordinates and extremely similar Z values will get combined together.
  348. {
  349. SURFACE_DATA_PROFILE_SCOPE_VERBOSE("GetSurfacePointsFromListInternal: GetSurfacePointsFromList");
  350. for (const auto& [providerHandle, provider] : m_registeredSurfaceDataProviders)
  351. {
  352. if (ProviderIsApplicable(provider))
  353. {
  354. SurfaceDataProviderRequestBus::Event(
  355. providerHandle, &SurfaceDataProviderRequestBus::Events::GetSurfacePointsFromList, inPositions, surfacePointLists);
  356. }
  357. }
  358. }
  359. // Once we have our list of surface points created, run through the list of surface data modifiers to potentially add
  360. // surface tags / values onto each point. The difference between this and the above loop is that surface data *providers*
  361. // create new surface points, but surface data *modifiers* simply annotate points that have already been created. The modifiers
  362. // are used to annotate points that occur within a volume. A common example is marking points as "underwater" for points that occur
  363. // within a water volume.
  364. {
  365. SURFACE_DATA_PROFILE_SCOPE_VERBOSE("GetSurfacePointsFromListInternal: ModifySurfaceWeights");
  366. for (const auto& [modifierHandle, modifier] : m_registeredSurfaceDataModifiers)
  367. {
  368. bool hasInfiniteBounds = !modifier.m_bounds.IsValid();
  369. if (hasInfiniteBounds || AabbOverlaps2D(modifier.m_bounds, surfacePointLists.GetSurfacePointAabb()))
  370. {
  371. surfacePointLists.ModifySurfaceWeights(modifierHandle);
  372. }
  373. }
  374. }
  375. // Notify the output structure that we're done building up the list.
  376. // This will filter out any remaining points that don't match the desired tag list. This can happen when a surface provider
  377. // doesn't add a desired tag, and a surface modifier has the *potential* to add it, but then doesn't.
  378. // It may also compact the memory and free any temporary structures.
  379. surfacePointLists.EndListConstruction();
  380. }
  381. SurfaceDataRegistryHandle SurfaceDataSystemComponent::RegisterSurfaceDataProviderInternal(const SurfaceDataRegistryEntry& entry)
  382. {
  383. AZ_Assert(entry.m_maxPointsCreatedPerInput > 0, "Surface data providers should always create at least 1 point.");
  384. AZStd::unique_lock<decltype(m_registrationMutex)> registrationLock(m_registrationMutex);
  385. SurfaceDataRegistryHandle handle = ++m_registeredSurfaceDataProviderHandleCounter;
  386. m_registeredSurfaceDataProviders[handle] = entry;
  387. return handle;
  388. }
  389. SurfaceDataRegistryEntry SurfaceDataSystemComponent::UnregisterSurfaceDataProviderInternal(const SurfaceDataRegistryHandle& handle)
  390. {
  391. AZStd::unique_lock<decltype(m_registrationMutex)> registrationLock(m_registrationMutex);
  392. SurfaceDataRegistryEntry entry;
  393. auto entryItr = m_registeredSurfaceDataProviders.find(handle);
  394. if (entryItr != m_registeredSurfaceDataProviders.end())
  395. {
  396. entry = entryItr->second;
  397. m_registeredSurfaceDataProviders.erase(entryItr);
  398. }
  399. return entry;
  400. }
  401. bool SurfaceDataSystemComponent::UpdateSurfaceDataProviderInternal(const SurfaceDataRegistryHandle& handle, const SurfaceDataRegistryEntry& entry, AZ::Aabb& oldBounds)
  402. {
  403. AZ_Assert(entry.m_maxPointsCreatedPerInput > 0, "Surface data providers should always create at least 1 point.");
  404. AZStd::unique_lock<decltype(m_registrationMutex)> registrationLock(m_registrationMutex);
  405. auto entryItr = m_registeredSurfaceDataProviders.find(handle);
  406. if (entryItr != m_registeredSurfaceDataProviders.end())
  407. {
  408. oldBounds = entryItr->second.m_bounds;
  409. entryItr->second = entry;
  410. return true;
  411. }
  412. return false;
  413. }
  414. SurfaceDataRegistryHandle SurfaceDataSystemComponent::RegisterSurfaceDataModifierInternal(const SurfaceDataRegistryEntry& entry)
  415. {
  416. AZ_Assert(entry.m_maxPointsCreatedPerInput == 0, "Surface data modifiers cannot create any points.");
  417. AZStd::unique_lock<decltype(m_registrationMutex)> registrationLock(m_registrationMutex);
  418. SurfaceDataRegistryHandle handle = ++m_registeredSurfaceDataModifierHandleCounter;
  419. m_registeredSurfaceDataModifiers[handle] = entry;
  420. m_registeredModifierTags.insert(entry.m_tags.begin(), entry.m_tags.end());
  421. return handle;
  422. }
  423. SurfaceDataRegistryEntry SurfaceDataSystemComponent::UnregisterSurfaceDataModifierInternal(const SurfaceDataRegistryHandle& handle)
  424. {
  425. AZStd::unique_lock<decltype(m_registrationMutex)> registrationLock(m_registrationMutex);
  426. SurfaceDataRegistryEntry entry;
  427. auto entryItr = m_registeredSurfaceDataModifiers.find(handle);
  428. if (entryItr != m_registeredSurfaceDataModifiers.end())
  429. {
  430. entry = entryItr->second;
  431. m_registeredSurfaceDataModifiers.erase(entryItr);
  432. }
  433. return entry;
  434. }
  435. bool SurfaceDataSystemComponent::UpdateSurfaceDataModifierInternal(const SurfaceDataRegistryHandle& handle, const SurfaceDataRegistryEntry& entry, AZ::Aabb& oldBounds)
  436. {
  437. AZ_Assert(entry.m_maxPointsCreatedPerInput == 0, "Surface data modifiers cannot create any points.");
  438. AZStd::unique_lock<decltype(m_registrationMutex)> registrationLock(m_registrationMutex);
  439. auto entryItr = m_registeredSurfaceDataModifiers.find(handle);
  440. if (entryItr != m_registeredSurfaceDataModifiers.end())
  441. {
  442. oldBounds = entryItr->second.m_bounds;
  443. entryItr->second = entry;
  444. m_registeredModifierTags.insert(entry.m_tags.begin(), entry.m_tags.end());
  445. return true;
  446. }
  447. return false;
  448. }
  449. SurfaceTagSet SurfaceDataSystemComponent::GetTagsFromBounds(
  450. const AZ::Aabb& bounds, const SurfaceDataRegistryMap& registeredEntries) const
  451. {
  452. SurfaceTagSet tags;
  453. const bool inputHasInfiniteBounds = !bounds.IsValid();
  454. for (const auto& [entryHandle, entry] : registeredEntries)
  455. {
  456. const bool entryHasInfiniteBounds = !entry.m_bounds.IsValid();
  457. if (inputHasInfiniteBounds || entryHasInfiniteBounds || AabbOverlaps2D(entry.m_bounds, bounds))
  458. {
  459. for (auto& entryTag : entry.m_tags)
  460. {
  461. tags.emplace(entryTag);
  462. }
  463. }
  464. }
  465. return tags;
  466. }
  467. SurfaceTagSet SurfaceDataSystemComponent::GetProviderTagsFromBounds(const AZ::Aabb& bounds) const
  468. {
  469. return GetTagsFromBounds(bounds, m_registeredSurfaceDataProviders);
  470. }
  471. SurfaceTagSet SurfaceDataSystemComponent::GetModifierTagsFromBounds(const AZ::Aabb& bounds) const
  472. {
  473. return GetTagsFromBounds(bounds, m_registeredSurfaceDataModifiers);
  474. }
  475. SurfaceTagSet SurfaceDataSystemComponent::ConvertTagVectorToSet(const SurfaceTagVector& surfaceTags) const
  476. {
  477. SurfaceTagSet tags;
  478. for (auto& tag : surfaceTags)
  479. {
  480. tags.emplace(tag);
  481. }
  482. return tags;
  483. }
  484. SurfaceTagSet SurfaceDataSystemComponent::GetAffectedSurfaceTags(const AZ::Aabb& bounds, const SurfaceTagVector& providerTags) const
  485. {
  486. // Get all of the surface tags that can be affected by surface provider changes within the given bounds.
  487. // Because a change to a surface provider can cause changes to a surface modifier as well, we need to merge all of the
  488. // surface provider tags with all of the potential surface modifier tags in the given bounds.
  489. // Get all of the modifier tags that occur in the bounds.
  490. SurfaceTagSet tagSet = GetModifierTagsFromBounds(bounds);
  491. // Merge the provider tags with them.
  492. for (auto& tag : providerTags)
  493. {
  494. tagSet.emplace(tag);
  495. }
  496. return tagSet;
  497. }
  498. } // namespace SurfaceData