/* * 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 * */ #include #include #include #include #include #include #include #include #include #include namespace AZ { namespace RPI { AZ_CLASS_ALLOCATOR_IMPL(JsonMaterialPropertyValueSourceDataSerializer, SystemAllocator, 0); namespace JSR = JsonSerializationResult; template bool JsonMaterialPropertyValueSourceDataSerializer::LoadAny( MaterialPropertyValueSourceData& propertyValue, const T& defaultValue, const rapidjson::Value& inputValue, JsonDeserializerContext& context) { T value = defaultValue; JSR::ResultCode result = ContinueLoading(&value, azrtti_typeid(), inputValue, context); bool loadSuccess = (result.GetOutcome() == JSR::Outcomes::Success); if (loadSuccess) { propertyValue.m_possibleValues[azrtti_typeid()] = value; } return loadSuccess; } JsonSerializationResult::Result JsonMaterialPropertyValueSourceDataSerializer::Load(void* outputValue, const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, JsonDeserializerContext& context) { AZ_Assert(azrtti_typeid() == outputValueTypeId, "Unable to deserialize material property value to json because the provided type is %s", outputValueTypeId.ToString().c_str()); AZ_UNUSED(outputValueTypeId); MaterialPropertyValueSourceData* materialPropertyValue = reinterpret_cast(outputValue); AZ_Assert(materialPropertyValue, "Output value for MaterialPropertyValueSourceDataSerializer can't be null."); JSR::ResultCode result(JSR::Tasks::ReadField); // We will attempt to read a value with different data types, most of them will fail but this exercise will // report many warnings that are unnecessary. To avoid spamming the Logs with useless errors/warnings We will push // a silent reporter and pop it afterwards to report any real errors. auto silentReporter = []([[maybe_unused]] AZStd::string_view message, AZ::JsonSerializationResult::ResultCode resultCode, [[maybe_unused]] AZStd::string_view path) { return resultCode; }; context.PushReporter(silentReporter); bool atLeastOneSuccess = false; // Some types can be serialized into each other, e.g. 42 => true. // short-circuiting is forbidden here. (Don't write LoadAny() || LoadAny(), or atLeastOneSuccess || LoadAny()) atLeastOneSuccess |= LoadAny(*materialPropertyValue, true, inputValue, context); atLeastOneSuccess |= LoadAny(*materialPropertyValue, 0, inputValue, context); atLeastOneSuccess |= LoadAny(*materialPropertyValue, 0u, inputValue, context); atLeastOneSuccess |= LoadAny(*materialPropertyValue, 0.0f, inputValue, context); atLeastOneSuccess |= LoadAny(*materialPropertyValue, AZStd::string(), inputValue, context); // Vectors/Colors can only be read from arrays or objects. If none of the basic types (+ string) are successfully loaded, the data should be an array. if (!atLeastOneSuccess) { atLeastOneSuccess |= LoadAny(*materialPropertyValue, Vector2(0.0f), inputValue, context); atLeastOneSuccess |= LoadAny(*materialPropertyValue, Vector3(0.0f), inputValue, context); atLeastOneSuccess |= LoadAny(*materialPropertyValue, Vector4(0.0f), inputValue, context); atLeastOneSuccess |= LoadAny(*materialPropertyValue, Color(0.0f), inputValue, context); } context.PopReporter(); if (atLeastOneSuccess) { return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Success, "Successfully loaded property value."); } else { return context.Report(JSR::Tasks::ReadField, JSR::Outcomes::Unsupported, "No possible supported data type match. See MaterialPropertyDataType"); } } JsonSerializationResult::Result JsonMaterialPropertyValueSourceDataSerializer::Store(rapidjson::Value& outputValue, const void* inputValue, [[maybe_unused]] const void* defaultValue, const Uuid& valueTypeId, JsonSerializerContext& context) { AZ_Assert(azrtti_typeid() == valueTypeId, "Unable to serialize functor property value to json because the provided type is %s", valueTypeId.ToString().c_str()); AZ_UNUSED(valueTypeId); const MaterialPropertyValueSourceData* materialPropertyValue = reinterpret_cast(inputValue); AZ_Assert(materialPropertyValue, "Input value for MaterialPropertyValueSourceData can't be null."); JSR::ResultCode result(JSR::Tasks::WriteValue); MaterialPropertyValue valueToDeserialize; // Use the resolved value first. If not applicable, use the first possible source value. if (materialPropertyValue->IsResolved()) { valueToDeserialize = materialPropertyValue->m_resolvedValue; } else { for (const auto& possibleValue : materialPropertyValue->m_possibleValues) { if (possibleValue.second.IsValid()) { valueToDeserialize = possibleValue.second; } } } if (valueToDeserialize.Is()) { result.Combine(ContinueStoring(outputValue, &valueToDeserialize.GetValue(), nullptr, azrtti_typeid(), context)); } else if (valueToDeserialize.Is()) { result.Combine(ContinueStoring(outputValue, &valueToDeserialize.GetValue(), nullptr, azrtti_typeid(), context)); } else if (valueToDeserialize.Is()) { result.Combine(ContinueStoring(outputValue, &valueToDeserialize.GetValue(), nullptr, azrtti_typeid(), context)); } else if (valueToDeserialize.Is()) { result.Combine(ContinueStoring(outputValue, &valueToDeserialize.GetValue(), nullptr, azrtti_typeid(), context)); } else if (valueToDeserialize.Is()) { result.Combine(ContinueStoring(outputValue, &valueToDeserialize.GetValue(), nullptr, azrtti_typeid(), context)); } else if (valueToDeserialize.Is()) { result.Combine(ContinueStoring(outputValue, &valueToDeserialize.GetValue(), nullptr, azrtti_typeid(), context)); } else if (valueToDeserialize.Is()) { result.Combine(ContinueStoring(outputValue, &valueToDeserialize.GetValue(), nullptr, azrtti_typeid(), context)); } else if (valueToDeserialize.Is()) { result.Combine(ContinueStoring(outputValue, &valueToDeserialize.GetValue(), nullptr, azrtti_typeid(), context)); } else if (valueToDeserialize.Is()) { result.Combine(ContinueStoring(outputValue, &valueToDeserialize.GetValue(), nullptr, azrtti_typeid(), context)); } else { ContinueStoring(outputValue, 0, nullptr, azrtti_typeid(), context); result.Combine(JSR::ResultCode(JSR::Tasks::WriteValue, JSR::Outcomes::DefaultsUsed)); } if (result.GetProcessing() == JSR::Processing::Completed) { return context.Report(result, "Successfully stored property value."); } else { return context.Report(result, "Partially stored property value."); } } } // namespace RPI } // namespace AZ