GradientSignalTestMocks.h 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236
  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. #pragma once
  9. #include <AzTest/AzTest.h>
  10. #include <AzCore/Asset/AssetManager.h>
  11. #include <AzCore/Casting/lossy_cast.h>
  12. #include <AzCore/Component/Entity.h>
  13. #include <AzCore/Component/ComponentApplication.h>
  14. #include <AzCore/Component/TransformBus.h>
  15. #include <AzCore/Memory/PoolAllocator.h>
  16. #include <AzCore/std/hash.h>
  17. #include <AzCore/UnitTest/TestTypes.h>
  18. #include <GradientSignal/Components/PerlinGradientComponent.h>
  19. #include <GradientSignal/Ebuses/GradientRequestBus.h>
  20. #include <GradientSignal/Ebuses/GradientPreviewContextRequestBus.h>
  21. #include <GradientSignal/GradientSampler.h>
  22. #include <LmbrCentral/Shape/ShapeComponentBus.h>
  23. #include <SurfaceData/SurfaceDataProviderRequestBus.h>
  24. #include <SurfaceData/SurfaceDataSystemRequestBus.h>
  25. #include <SurfaceData/Tests/SurfaceDataTestMocks.h>
  26. namespace UnitTest
  27. {
  28. struct MockGradientRequestsBus
  29. : public GradientSignal::GradientRequestBus::Handler
  30. {
  31. MockGradientRequestsBus(const AZ::EntityId& id)
  32. {
  33. BusConnect(id);
  34. }
  35. ~MockGradientRequestsBus()
  36. {
  37. BusDisconnect();
  38. }
  39. float m_GetValue = 0.0f;
  40. float GetValue([[maybe_unused]] const GradientSignal::GradientSampleParams& sampleParams) const override
  41. {
  42. return m_GetValue;
  43. }
  44. bool IsEntityInHierarchy(const AZ::EntityId &) const override
  45. {
  46. return false;
  47. }
  48. };
  49. struct MockGradientArrayRequestsBus
  50. : public GradientSignal::GradientRequestBus::Handler
  51. {
  52. MockGradientArrayRequestsBus(const AZ::EntityId& id, const AZStd::vector<float>& data, int rowSize)
  53. : m_getValue(data), m_rowSize(rowSize)
  54. {
  55. BusConnect(id);
  56. // We expect each value to get requested exactly once.
  57. m_positionsRequested.reserve(data.size());
  58. }
  59. ~MockGradientArrayRequestsBus()
  60. {
  61. BusDisconnect();
  62. }
  63. float GetValue(const GradientSignal::GradientSampleParams& sampleParams) const override
  64. {
  65. const auto& pos = sampleParams.m_position;
  66. // Because gradients repeat infinitely by default, we mod by rowSize to bring the position into the correct range.
  67. // The extra "+ rowSize) % rowSize" piece is so that negative values come into the correct range as well.
  68. // If we just took the absolute value first, the mod would cause us to reverse the lookup on the negative side instead
  69. // of continuing it.
  70. int posX = ((static_cast<int>(pos.GetX()) % m_rowSize) + m_rowSize) % m_rowSize;
  71. int posY = ((static_cast<int>(pos.GetY()) % m_rowSize) + m_rowSize) % m_rowSize;
  72. const int index = (posY * m_rowSize) + posX;
  73. m_positionsRequested.push_back(sampleParams.m_position);
  74. return m_getValue[index];
  75. }
  76. bool IsEntityInHierarchy(const AZ::EntityId &) const override
  77. {
  78. return false;
  79. }
  80. AZStd::vector<float> m_getValue;
  81. int m_rowSize;
  82. mutable AZStd::vector<AZ::Vector3> m_positionsRequested;
  83. };
  84. struct MockGradientPreviewContextRequestBus
  85. : public GradientSignal::GradientPreviewContextRequestBus::Handler
  86. {
  87. MockGradientPreviewContextRequestBus(const AZ::EntityId& id, const AZ::Aabb& previewBounds, bool constrainToShape)
  88. : m_previewBounds(previewBounds)
  89. , m_constrainToShape(constrainToShape)
  90. , m_id(id)
  91. {
  92. BusConnect(id);
  93. }
  94. ~MockGradientPreviewContextRequestBus()
  95. {
  96. BusDisconnect();
  97. }
  98. AZ::EntityId GetPreviewEntity() const override { return m_id; }
  99. AZ::Aabb GetPreviewBounds() const override { return m_previewBounds; }
  100. bool GetConstrainToShape() const override { return m_constrainToShape; }
  101. protected:
  102. AZ::EntityId m_id;
  103. AZ::Aabb m_previewBounds;
  104. bool m_constrainToShape;
  105. };
  106. // Mock out a SurfaceProvider component so that we can control exactly what surface weights get returned
  107. // at which points for our unit tests.
  108. struct MockSurfaceProviderComponent
  109. : public AZ::Component
  110. , public SurfaceData::SurfaceDataProviderRequestBus::Handler
  111. {
  112. public:
  113. AZ_COMPONENT(MockSurfaceProviderComponent, "{18C71877-DB29-4CEC-B34C-B4B44E05203D}", AZ::Component);
  114. void Activate() override
  115. {
  116. SurfaceData::SurfaceDataRegistryEntry providerRegistryEntry;
  117. providerRegistryEntry.m_entityId = GetEntityId();
  118. providerRegistryEntry.m_bounds = m_bounds;
  119. providerRegistryEntry.m_tags = m_tags;
  120. // Run through the set of surface points that have been set on this component to find out the maximum number
  121. // that we'll return for any given input point.
  122. providerRegistryEntry.m_maxPointsCreatedPerInput = 1;
  123. for (auto& pointEntry : m_surfacePoints)
  124. {
  125. for (size_t index = 0; index < pointEntry.second.GetInputPositionSize(); index++)
  126. {
  127. providerRegistryEntry.m_maxPointsCreatedPerInput =
  128. AZ::GetMax(providerRegistryEntry.m_maxPointsCreatedPerInput, pointEntry.second.GetSize(index));
  129. }
  130. }
  131. m_providerHandle = AZ::Interface<SurfaceData::SurfaceDataSystem>::Get()->RegisterSurfaceDataProvider(providerRegistryEntry);
  132. SurfaceData::SurfaceDataProviderRequestBus::Handler::BusConnect(m_providerHandle);
  133. }
  134. void Deactivate() override
  135. {
  136. AZ::Interface<SurfaceData::SurfaceDataSystem>::Get()->UnregisterSurfaceDataProvider(m_providerHandle);
  137. m_providerHandle = SurfaceData::InvalidSurfaceDataRegistryHandle;
  138. SurfaceData::SurfaceDataProviderRequestBus::Handler::BusDisconnect();
  139. }
  140. static void Reflect([[maybe_unused]] AZ::ReflectContext* reflect)
  141. {
  142. }
  143. static void GetProvidedServices(AZ::ComponentDescriptor::DependencyArrayType& provided)
  144. {
  145. provided.push_back(AZ_CRC_CE("SurfaceDataProviderService"));
  146. }
  147. void GetSurfacePoints(const AZ::Vector3& inPosition, SurfaceData::SurfacePointList& surfacePointList) const override
  148. {
  149. auto surfacePoints = m_surfacePoints.find(AZStd::make_pair(inPosition.GetX(), inPosition.GetY()));
  150. if (surfacePoints != m_surfacePoints.end())
  151. {
  152. // If we have an entry for this input position, run through all of its points and add them to the passed-in list.
  153. surfacePoints->second.EnumeratePoints(
  154. [inPosition, &surfacePointList](
  155. [[maybe_unused]] size_t inPositionIndex, const AZ::Vector3& position, const AZ::Vector3& normal,
  156. const SurfaceData::SurfaceTagWeights& weights) -> bool
  157. {
  158. surfacePointList.AddSurfacePoint(AZ::EntityId(), inPosition, position, normal, weights);
  159. return true;
  160. });
  161. }
  162. }
  163. // m_surfacePoints is a mapping of locations to surface tags / weights that should be returned.
  164. AZStd::unordered_map<AZStd::pair<float, float>, SurfaceData::SurfacePointList> m_surfacePoints;
  165. // m_bounds is the AABB to use for our mock surface provider.
  166. AZ::Aabb m_bounds;
  167. // m_tags are the possible set of tags that this provider will return.
  168. SurfaceData::SurfaceTagVector m_tags;
  169. SurfaceData::SurfaceDataRegistryHandle m_providerHandle = SurfaceData::InvalidSurfaceDataRegistryHandle;
  170. };
  171. // Mock the GradientSignal::PerlinGradientComponent so that its can inject a fixed permutation table for
  172. // the perlin noise algorithm for consistent unit test results across all platforms
  173. class MockGradientSignal : public GradientSignal::PerlinGradientComponent
  174. {
  175. public:
  176. AZ_COMPONENT(MockGradientSignal, "{72B18966-6B4A-42C7-86AE-72AB6B1B84C5}", GradientSignal::PerlinGradientComponent);
  177. MockGradientSignal() = default;
  178. MockGradientSignal(const GradientSignal::PerlinGradientConfig& configuration)
  179. : GradientSignal::PerlinGradientComponent(configuration)
  180. {
  181. }
  182. static void Reflect(AZ::ReflectContext*) {}
  183. void Activate() override
  184. {
  185. GradientSignal::PerlinGradientComponent::Activate();
  186. m_perlinImprovedNoise.reset(aznew GradientSignal::PerlinImprovedNoise(m_testPermutationTable));
  187. }
  188. void SetPerlinNoisePermutationTableForTest(const AZStd::array<int, 512>& permutationTable)
  189. {
  190. AZStd::copy(permutationTable.cbegin(), permutationTable.cend(), m_testPermutationTable.begin());
  191. }
  192. AZStd::array<int, 512> m_testPermutationTable;
  193. };
  194. }