3
0

MaterialPropertyValueSourceDataTests.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363
  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 <AzTest/AzTest.h>
  9. #include <Common/RPITestFixture.h>
  10. #include <Common/JsonTestUtils.h>
  11. #include <Common/TestUtils.h>
  12. #include <Tests/Serialization/Json/JsonSerializerConformityTests.h>
  13. #include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
  14. #include <Atom/RPI.Edit/Material/MaterialFunctorSourceData.h>
  15. #include <Atom/RPI.Edit/Material/MaterialPropertyValueSourceData.h>
  16. #include <Atom/RPI.Edit/Material/MaterialPropertyValueSourceDataSerializer.h>
  17. #include <Atom/RPI.Reflect/Material/MaterialTypeAsset.h>
  18. #include <Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h>
  19. #include <Atom/RPI.Reflect/Material/MaterialTypeAssetCreator.h>
  20. #include <Atom/RPI.Reflect/Material/MaterialNameContext.h>
  21. namespace JsonSerializationTests
  22. {
  23. class MaterialPropertyValueSourceDataSerializerTestDescription :
  24. public JsonSerializerConformityTestDescriptor<AZ::RPI::MaterialPropertyValueSourceData>
  25. {
  26. public:
  27. void Reflect(AZStd::unique_ptr<AZ::SerializeContext>& context) override
  28. {
  29. AZ::RPI::MaterialPropertyValueSourceData::Reflect(context.get());
  30. }
  31. void Reflect(AZStd::unique_ptr<AZ::JsonRegistrationContext>& context) override
  32. {
  33. context->Serializer<AZ::RPI::JsonMaterialPropertyValueSourceDataSerializer>()->HandlesType<AZ::RPI::MaterialPropertyValueSourceData>();
  34. }
  35. AZStd::shared_ptr<AZ::BaseJsonSerializer> CreateSerializer() override
  36. {
  37. return AZStd::make_shared<AZ::RPI::JsonMaterialPropertyValueSourceDataSerializer>();
  38. }
  39. AZStd::shared_ptr<AZ::RPI::MaterialPropertyValueSourceData> CreateDefaultInstance() override
  40. {
  41. return AZStd::make_shared<AZ::RPI::MaterialPropertyValueSourceData>();
  42. }
  43. AZStd::shared_ptr<AZ::RPI::MaterialPropertyValueSourceData> CreateFullySetInstance() override
  44. {
  45. auto result = AZStd::make_shared<AZ::RPI::MaterialPropertyValueSourceData>();
  46. result->SetValue(42);
  47. return result;
  48. }
  49. AZStd::string_view GetJsonForFullySetInstance() override
  50. {
  51. return R"(42)";
  52. }
  53. void ConfigureFeatures(JsonSerializerConformityTestDescriptorFeatures& features) override
  54. {
  55. features.EnableJsonType(rapidjson::kFalseType);
  56. features.EnableJsonType(rapidjson::kTrueType);
  57. features.EnableJsonType(rapidjson::kArrayType);
  58. features.EnableJsonType(rapidjson::kStringType);
  59. features.EnableJsonType(rapidjson::kNumberType);
  60. features.m_fixedSizeArray = true;
  61. features.m_supportsPartialInitialization = false;
  62. features.m_supportsInjection = false;
  63. }
  64. bool AreEqual(
  65. const AZ::RPI::MaterialPropertyValueSourceData& lhs,
  66. const AZ::RPI::MaterialPropertyValueSourceData& rhs) override
  67. {
  68. return AZ::RPI::MaterialPropertyValueSourceData::AreSimilar(lhs, rhs);
  69. }
  70. };
  71. using MaterialPropertyValueSourceDataSerializerTestTypes = ::testing::Types<MaterialPropertyValueSourceDataSerializerTestDescription>;
  72. IF_JSON_CONFORMITY_ENABLED(INSTANTIATE_TYPED_TEST_CASE_P(MaterialPropertyValueSourceDataTests, JsonSerializerConformityTests, MaterialPropertyValueSourceDataSerializerTestTypes));
  73. } // namespace JsonSerializationTests
  74. namespace UnitTest
  75. {
  76. using namespace AZ;
  77. using namespace RPI;
  78. class MaterialPropertyValueSourceDataTests
  79. : public RPITestFixture
  80. {
  81. protected:
  82. //! A dummy material creator filled with necessary data.
  83. //! It is kept alive between SetUp and TearDown, so that MaterialPropertyValueSourceData can have access to the layout and resolve its value.
  84. MaterialTypeAssetCreator m_materialTypeCreator;
  85. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  86. // Samples used for testing MaterialFunctor
  87. class ValueFunctor final
  88. : public MaterialFunctor
  89. {
  90. public:
  91. AZ_CLASS_ALLOCATOR(ValueFunctor, SystemAllocator)
  92. AZ_RTTI(MaterialPropertyValueSourceDataTests::ValueFunctor, "{07CE498C-6E97-45C9-8B2D-18BC03724055}", AZ::RPI::MaterialFunctor);
  93. static void Reflect(ReflectContext* context)
  94. {
  95. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  96. {
  97. serializeContext->Class<ValueFunctor, AZ::RPI::MaterialFunctor>()
  98. ->Version(1)
  99. ->Field("propertyIndex", &ValueFunctor::m_propertyIndex)
  100. ->Field("propertyValue", &ValueFunctor::m_propertyValue)
  101. ;
  102. }
  103. }
  104. MaterialPropertyIndex m_propertyIndex;
  105. MaterialPropertyValue m_propertyValue;
  106. };
  107. class ValueFunctorSourceData final
  108. : public MaterialFunctorSourceData
  109. {
  110. public:
  111. AZ_CLASS_ALLOCATOR(ValueFunctorSourceData, AZ::SystemAllocator)
  112. AZ_RTTI(ValueFunctorSourceData, "{777CE7A5-3023-4C63-BA43-5763DF51D82D}", AZ::RPI::MaterialFunctorSourceData);
  113. static void Reflect(ReflectContext* context)
  114. {
  115. if (auto* serializeContext = azrtti_cast<SerializeContext*>(context))
  116. {
  117. serializeContext->Class<ValueFunctorSourceData>()
  118. ->Version(1)
  119. ->Field("propertyName", &ValueFunctorSourceData::m_propertyName)
  120. ->Field("propertyValue", &ValueFunctorSourceData::m_propertyValue)
  121. ;
  122. }
  123. }
  124. AZStd::string m_propertyName;
  125. MaterialPropertyValueSourceData m_propertyValue;
  126. using MaterialFunctorSourceData::CreateFunctor;
  127. FunctorResult CreateFunctor(const RuntimeContext& context) const override
  128. {
  129. Ptr<ValueFunctor> functor = aznew ValueFunctor;
  130. functor->m_propertyIndex = context.FindMaterialPropertyIndex(Name(m_propertyName));
  131. EXPECT_TRUE(functor->m_propertyIndex.IsValid());
  132. m_propertyValue.Resolve(*context.GetMaterialPropertiesLayout(), AZ::Name(m_propertyName));
  133. functor->m_propertyValue = m_propertyValue.GetValue();
  134. return Success(Ptr<MaterialFunctor>(functor));
  135. }
  136. };
  137. /////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  138. void Reflect(ReflectContext* context) override
  139. {
  140. RPITestFixture::Reflect(context);
  141. MaterialPropertyValueSourceData::Reflect(context);
  142. MaterialFunctorSourceDataHolder::Reflect(context);
  143. ValueFunctorSourceData::Reflect(context);
  144. ValueFunctor::Reflect(context);
  145. }
  146. void SetUp() override
  147. {
  148. RPITestFixture::SetUp();
  149. m_materialTypeCreator.Begin(Data::AssetId(Uuid::CreateRandom()));
  150. m_materialTypeCreator.BeginMaterialProperty(AZ::Name{"general.Bool"}, MaterialPropertyDataType::Bool);
  151. m_materialTypeCreator.EndMaterialProperty();
  152. m_materialTypeCreator.BeginMaterialProperty(AZ::Name{"general.Int"}, MaterialPropertyDataType::Int);
  153. m_materialTypeCreator.EndMaterialProperty();
  154. m_materialTypeCreator.BeginMaterialProperty(AZ::Name{"general.UInt"}, MaterialPropertyDataType::UInt);
  155. m_materialTypeCreator.EndMaterialProperty();
  156. m_materialTypeCreator.BeginMaterialProperty(AZ::Name{"general.Float"}, MaterialPropertyDataType::Float);
  157. m_materialTypeCreator.EndMaterialProperty();
  158. m_materialTypeCreator.BeginMaterialProperty(AZ::Name{"general.Vector2"}, MaterialPropertyDataType::Vector2);
  159. m_materialTypeCreator.EndMaterialProperty();
  160. m_materialTypeCreator.BeginMaterialProperty(AZ::Name{"general.Vector3"}, MaterialPropertyDataType::Vector3);
  161. m_materialTypeCreator.EndMaterialProperty();
  162. m_materialTypeCreator.BeginMaterialProperty(AZ::Name{"general.Vector4"}, MaterialPropertyDataType::Vector4);
  163. m_materialTypeCreator.EndMaterialProperty();
  164. m_materialTypeCreator.BeginMaterialProperty(AZ::Name{"general.Color"}, MaterialPropertyDataType::Color);
  165. m_materialTypeCreator.EndMaterialProperty();
  166. m_materialTypeCreator.BeginMaterialProperty(AZ::Name{"general.Image"}, MaterialPropertyDataType::Image);
  167. m_materialTypeCreator.EndMaterialProperty();
  168. m_materialTypeCreator.BeginMaterialProperty(AZ::Name{ "general.Enum" }, MaterialPropertyDataType::Enum);
  169. m_materialTypeCreator.SetMaterialPropertyEnumNames(AZStd::vector<AZStd::string>({ "DummyEnum" }));
  170. m_materialTypeCreator.EndMaterialProperty();
  171. }
  172. void TearDown() override
  173. {
  174. {
  175. Data::Asset<MaterialTypeAsset> testAsset;
  176. m_materialTypeCreator.End(testAsset);
  177. }
  178. RPITestFixture::TearDown();
  179. }
  180. };
  181. TEST_F(MaterialPropertyValueSourceDataTests, MaterialFunctorTest)
  182. {
  183. AZStd::unordered_map<MaterialPropertyDataType, const char *> typeValue =
  184. {
  185. {MaterialPropertyDataType::Bool, "true"},
  186. {MaterialPropertyDataType::Int, "-42"},
  187. {MaterialPropertyDataType::UInt, "42"},
  188. {MaterialPropertyDataType::Float, "42.0"},
  189. {MaterialPropertyDataType::Vector2, "[42.0, 42.0]"},
  190. {MaterialPropertyDataType::Vector3, "[42.0, 42.0, 42.0]"},
  191. {MaterialPropertyDataType::Vector4, "[42.0, 42.0, 42.0, 42.0]"},
  192. {MaterialPropertyDataType::Color, "[0.0, 0.0, 0.0, 1.0]"},
  193. {MaterialPropertyDataType::Image, "\"DummyImagePath.png\""},
  194. {MaterialPropertyDataType::Enum, "\"DummyEnum\""},
  195. };
  196. AZStd::array<Ptr<MaterialFunctor>, static_cast<uint32_t>(MaterialPropertyDataType::Count)> valueFunctors;
  197. valueFunctors.fill(nullptr);
  198. char inputJson[2048];
  199. AZStd::string outputJson;
  200. uint32_t propertyTypeCount = static_cast<uint32_t>(MaterialPropertyDataType::Count);
  201. static_assert(static_cast<uint32_t>(MaterialPropertyDataType::Invalid) == 0u, "If MaterialPropertyDataType::Invalid has changed its order, the following logic should change accordingly.");
  202. // Test through each type, serialization and deserialization.
  203. // Collect the functors and test the serialized value later.
  204. for (uint32_t i = static_cast<uint32_t>(MaterialPropertyDataType::Invalid) + 1u; i < propertyTypeCount; ++i)
  205. {
  206. MaterialPropertyDataType type = static_cast<MaterialPropertyDataType>(i);
  207. azsnprintf(inputJson, AZ_ARRAY_SIZE(inputJson),
  208. R"(
  209. {
  210. "propertyName": "general.%s",
  211. "propertyValue": %s
  212. }
  213. )",
  214. ToString(type),
  215. typeValue[type]
  216. );
  217. // Stored as base class.
  218. Ptr<ValueFunctorSourceData> functorData = aznew ValueFunctorSourceData;
  219. JsonTestResult loadResult = LoadTestDataFromJson(*functorData, inputJson);
  220. MaterialNameContext nameContext;
  221. // Where type resolving happens.
  222. MaterialFunctorSourceData::FunctorResult functorResult = functorData->CreateFunctor(
  223. MaterialFunctorSourceData::RuntimeContext(
  224. "Dummy.materialtype",
  225. m_materialTypeCreator.GetMaterialPropertiesLayout(),
  226. m_materialTypeCreator.GetMaterialShaderResourceGroupLayout(),
  227. &nameContext
  228. )
  229. );
  230. valueFunctors[i] = functorResult.GetValue();
  231. // Store back to json after type is resolved.
  232. outputJson.clear();
  233. JsonTestResult storeResult = StoreTestDataToJson(*functorData, outputJson);
  234. ExpectSimilarJson(inputJson, outputJson);
  235. }
  236. MaterialPropertyValue& value = static_cast<ValueFunctor*>(valueFunctors[static_cast<uint32_t>(MaterialPropertyDataType::Bool)].get())->m_propertyValue;
  237. EXPECT_TRUE(value == true);
  238. value = static_cast<ValueFunctor*>(valueFunctors[static_cast<uint32_t>(MaterialPropertyDataType::Int)].get())->m_propertyValue;
  239. EXPECT_TRUE(value == -42);
  240. value = static_cast<ValueFunctor*>(valueFunctors[static_cast<uint32_t>(MaterialPropertyDataType::UInt)].get())->m_propertyValue;
  241. EXPECT_TRUE(value == 42u);
  242. value = static_cast<ValueFunctor*>(valueFunctors[static_cast<uint32_t>(MaterialPropertyDataType::Float)].get())->m_propertyValue;
  243. EXPECT_TRUE(value == 42.0f);
  244. value = static_cast<ValueFunctor*>(valueFunctors[static_cast<uint32_t>(MaterialPropertyDataType::Vector2)].get())->m_propertyValue;
  245. EXPECT_TRUE(value == Vector2(42.0f, 42.0f));
  246. value = static_cast<ValueFunctor*>(valueFunctors[static_cast<uint32_t>(MaterialPropertyDataType::Vector3)].get())->m_propertyValue;
  247. EXPECT_TRUE(value == Vector3(42.0f, 42.0f, 42.0f));
  248. value = static_cast<ValueFunctor*>(valueFunctors[static_cast<uint32_t>(MaterialPropertyDataType::Vector4)].get())->m_propertyValue;
  249. EXPECT_TRUE(value == Vector4(42.0f, 42.0f, 42.0f, 42.0f));
  250. value = static_cast<ValueFunctor*>(valueFunctors[static_cast<uint32_t>(MaterialPropertyDataType::Color)].get())->m_propertyValue;
  251. EXPECT_TRUE(value == Color(0.0f, 0.0f, 0.0f, 1.0f));
  252. value = static_cast<ValueFunctor*>(valueFunctors[static_cast<uint32_t>(MaterialPropertyDataType::Image)].get())->m_propertyValue;
  253. EXPECT_TRUE(value == AZStd::string("DummyImagePath.png"));
  254. value = static_cast<ValueFunctor*>(valueFunctors[static_cast<uint32_t>(MaterialPropertyDataType::Enum)].get())->m_propertyValue;
  255. EXPECT_TRUE(value == AZStd::string("DummyEnum"));
  256. }
  257. TEST_F(MaterialPropertyValueSourceDataTests, DataSimilarityTest)
  258. {
  259. MaterialPropertyValueSourceData emptyValue;
  260. MaterialPropertyValueSourceData onlyResolvedValue[2];
  261. MaterialPropertyValueSourceData onlyPossibleValue[2];
  262. MaterialPropertyValueSourceData fullValue[2];
  263. // Load data
  264. static const char* source[] = { R"(42)", R"(43)" };
  265. constexpr int32_t value[] = { 42, 43 };
  266. for (int32_t i = 0; i < 2; ++i)
  267. {
  268. LoadTestDataFromJson(onlyPossibleValue[i], source[i]);
  269. LoadTestDataFromJson(fullValue[i], source[i]);
  270. onlyResolvedValue[i].SetValue(value[i]);
  271. fullValue[i].SetValue(value[i]);
  272. }
  273. // Group them into 2 based on the source data.
  274. // Within each set, AreSimilar should return true.
  275. // Between two sets, assuming different source data, AreSimilar should return false.
  276. MaterialPropertyValueSourceData* setA[] = {
  277. &onlyResolvedValue[0],
  278. &onlyPossibleValue[0],
  279. &fullValue[0]
  280. };
  281. MaterialPropertyValueSourceData* setB[] = {
  282. &onlyResolvedValue[1],
  283. &onlyPossibleValue[1],
  284. &fullValue[1]
  285. };
  286. EXPECT_TRUE(AZ::RPI::MaterialPropertyValueSourceData::AreSimilar(emptyValue, emptyValue));
  287. for (int32_t i = 0; i < 3; ++i)
  288. {
  289. for (int32_t j = 0; j < 3; ++j)
  290. {
  291. // Test within each set and between them, including comparing to the element itself.
  292. EXPECT_TRUE(AZ::RPI::MaterialPropertyValueSourceData::AreSimilar(*setA[i], *setA[j]));
  293. EXPECT_TRUE(AZ::RPI::MaterialPropertyValueSourceData::AreSimilar(*setB[i], *setB[j]));
  294. EXPECT_FALSE(AZ::RPI::MaterialPropertyValueSourceData::AreSimilar(*setA[i], *setB[j]));
  295. }
  296. // Test against empty.
  297. EXPECT_FALSE(AZ::RPI::MaterialPropertyValueSourceData::AreSimilar(*setA[i], emptyValue));
  298. EXPECT_FALSE(AZ::RPI::MaterialPropertyValueSourceData::AreSimilar(*setB[i], emptyValue));
  299. }
  300. }
  301. }