3
0

SurfaceDataSystemComponent.cpp 26 KB

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