/* * 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 namespace AZ { namespace Render { AZ_CLASS_ALLOCATOR_IMPL(JsonMaterialAssignmentSerializer, AZ::SystemAllocator, 0); JsonSerializationResult::Result JsonMaterialAssignmentSerializer::Load( void* outputValue, [[maybe_unused]] const Uuid& outputValueTypeId, const rapidjson::Value& inputValue, JsonDeserializerContext& context) { namespace JSR = JsonSerializationResult; AZ_Assert( azrtti_typeid() == outputValueTypeId, "Unable to deserialize MaterialAssignment from json because the provided type is %s.", outputValueTypeId.ToString().c_str()); AZ::Render::MaterialAssignment* materialAssignment = reinterpret_cast(outputValue); AZ_Assert(materialAssignment, "Output value for JsonMaterialAssignmentSerializer can't be null."); JSR::ResultCode result(JSR::Tasks::ReadField); { result.Combine(ContinueLoadingFromJsonObjectField( &materialAssignment->m_materialAsset, azrtti_typeidm_materialAsset)>(), inputValue, "MaterialAsset", context)); } if (inputValue.HasMember("PropertyOverrides") && inputValue["PropertyOverrides"].IsObject()) { // Attempt to load material property override values for a subset of types for (const auto& inputPropertyPair : inputValue["PropertyOverrides"].GetObject()) { const AZ::Name propertyName(inputPropertyPair.name.GetString()); if (!propertyName.IsEmpty()) { AZStd::any propertyValue; if (LoadAny(propertyValue, inputPropertyPair.value, context, result) || LoadAny(propertyValue, inputPropertyPair.value, context, result) || LoadAny(propertyValue, inputPropertyPair.value, context, result) || LoadAny(propertyValue, inputPropertyPair.value, context, result) || LoadAny(propertyValue, inputPropertyPair.value, context, result) || LoadAny(propertyValue, inputPropertyPair.value, context, result) || LoadAny(propertyValue, inputPropertyPair.value, context, result) || LoadAny(propertyValue, inputPropertyPair.value, context, result) || LoadAny(propertyValue, inputPropertyPair.value, context, result) || LoadAny(propertyValue, inputPropertyPair.value, context, result) || LoadAny(propertyValue, inputPropertyPair.value, context, result) || LoadAny(propertyValue, inputPropertyPair.value, context, result) || LoadAny(propertyValue, inputPropertyPair.value, context, result) || LoadAny(propertyValue, inputPropertyPair.value, context, result) || LoadAny(propertyValue, inputPropertyPair.value, context, result) || LoadAny(propertyValue, inputPropertyPair.value, context, result) || LoadAny(propertyValue, inputPropertyPair.value, context, result) || LoadAny>(propertyValue, inputPropertyPair.value, context, result) || LoadAny>(propertyValue, inputPropertyPair.value, context, result) || LoadAny>(propertyValue, inputPropertyPair.value, context, result)) { materialAssignment->m_propertyOverrides[propertyName] = propertyValue; } } } } return context.Report( result, result.GetProcessing() != JSR::Processing::Halted ? "Succesfully loaded MaterialAssignment information." : "Failed to load MaterialAssignment information."); } JsonSerializationResult::Result JsonMaterialAssignmentSerializer::Store( rapidjson::Value& outputValue, const void* inputValue, const void* defaultValue, [[maybe_unused]] const Uuid& valueTypeId, JsonSerializerContext& context) { namespace JSR = AZ::JsonSerializationResult; AZ_Assert( azrtti_typeid() == valueTypeId, "Unable to Serialize MaterialAssignment because the provided type is %s.", valueTypeId.ToString().c_str()); const AZ::Render::MaterialAssignment* materialAssignment = reinterpret_cast(inputValue); AZ_Assert(materialAssignment, "Input value for JsonMaterialAssignmentSerializer can't be null."); const AZ::Render::MaterialAssignment* defaultMaterialAssignmentInstance = reinterpret_cast(defaultValue); outputValue.SetObject(); JSR::ResultCode result(JSR::Tasks::WriteValue); { AZ::ScopedContextPath subPathMaterialAsset(context, "m_materialAsset"); const AZ::Data::Asset* materialAsset = &materialAssignment->m_materialAsset; const AZ::Data::Asset* defaultmaterialAsset = defaultMaterialAssignmentInstance ? &defaultMaterialAssignmentInstance->m_materialAsset : nullptr; result.Combine(ContinueStoringToJsonObjectField( outputValue, "MaterialAsset", materialAsset, defaultmaterialAsset, azrtti_typeidm_materialAsset)>(), context)); } { AZ::ScopedContextPath subPathPropertyOverrides(context, "m_propertyOverrides"); if (!materialAssignment->m_propertyOverrides.empty()) { rapidjson::Value outputPropertyValueContainer; outputPropertyValueContainer.SetObject(); // Attempt to extract and store material property override values for a subset of types for (const auto& propertyPair : materialAssignment->m_propertyOverrides) { const AZ::Name& propertyName = propertyPair.first; const AZStd::any& propertyValue = propertyPair.second; if (!propertyName.IsEmpty() && !propertyValue.empty()) { rapidjson::Value outputPropertyValue; if (StoreAny(propertyValue, outputPropertyValue, context, result) || StoreAny(propertyValue, outputPropertyValue, context, result) || StoreAny(propertyValue, outputPropertyValue, context, result) || StoreAny(propertyValue, outputPropertyValue, context, result) || StoreAny(propertyValue, outputPropertyValue, context, result) || StoreAny(propertyValue, outputPropertyValue, context, result) || StoreAny(propertyValue, outputPropertyValue, context, result) || StoreAny(propertyValue, outputPropertyValue, context, result) || StoreAny(propertyValue, outputPropertyValue, context, result) || StoreAny(propertyValue, outputPropertyValue, context, result) || StoreAny(propertyValue, outputPropertyValue, context, result) || StoreAny(propertyValue, outputPropertyValue, context, result) || StoreAny(propertyValue, outputPropertyValue, context, result) || StoreAny(propertyValue, outputPropertyValue, context, result) || StoreAny(propertyValue, outputPropertyValue, context, result) || StoreAny(propertyValue, outputPropertyValue, context, result) || StoreAny(propertyValue, outputPropertyValue, context, result) || StoreAny>(propertyValue, outputPropertyValue, context, result) || StoreAny>(propertyValue, outputPropertyValue, context, result) || StoreAny>(propertyValue, outputPropertyValue, context, result)) { outputPropertyValueContainer.AddMember( rapidjson::Value::StringRefType(propertyName.GetCStr()), outputPropertyValue, context.GetJsonAllocator()); } } } if (outputPropertyValueContainer.MemberCount() > 0) { outputValue.AddMember("PropertyOverrides", outputPropertyValueContainer, context.GetJsonAllocator()); } } } return context.Report( result, result.GetProcessing() != JSR::Processing::Halted ? "Successfully stored MaterialAssignment information." : "Failed to store MaterialAssignment information."); } template bool JsonMaterialAssignmentSerializer::LoadAny( AZStd::any& propertyValue, const rapidjson::Value& inputPropertyValue, AZ::JsonDeserializerContext& context, AZ::JsonSerializationResult::ResultCode& result) { if (inputPropertyValue.IsObject() && inputPropertyValue.HasMember("Value") && inputPropertyValue.HasMember("$type")) { // Requiring explicit type info to differentiate between colors versus vectors and numeric types const AZ::Uuid baseTypeId = azrtti_typeid(); AZ::Uuid typeId = AZ::Uuid::CreateNull(); result.Combine(LoadTypeId(typeId, inputPropertyValue, context, &baseTypeId)); if (typeId == azrtti_typeid()) { T value = {}; result.Combine(ContinueLoadingFromJsonObjectField(&value, azrtti_typeid(), inputPropertyValue, "Value", context)); propertyValue = value; return true; } } return false; } template bool JsonMaterialAssignmentSerializer::StoreAny( const AZStd::any& propertyValue, rapidjson::Value& outputPropertyValue, AZ::JsonSerializerContext& context, AZ::JsonSerializationResult::ResultCode& result) { if (propertyValue.is()) { outputPropertyValue.SetObject(); // Storing explicit type info to differentiate between colors versus vectors and numeric types rapidjson::Value typeValue; result.Combine(StoreTypeId(typeValue, azrtti_typeid(), context)); outputPropertyValue.AddMember("$type", typeValue, context.GetJsonAllocator()); const T& value = AZStd::any_cast(propertyValue); result.Combine( ContinueStoringToJsonObjectField(outputPropertyValue, "Value", &value, nullptr, azrtti_typeid(), context)); return true; } return false; } } // namespace Render } // namespace AZ