/* * 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 #include #include #include #include namespace AZ { namespace Render { namespace EditorMaterialComponentUtil { bool LoadMaterialEditDataFromAssetId(const AZ::Data::AssetId& assetId, MaterialEditData& editData) { editData = MaterialEditData(); if (!assetId.IsValid()) { AZ_Warning("AZ::Render::EditorMaterialComponentUtil", false, "Attempted to load material data for invalid asset id."); return false; } editData.m_materialAssetId = assetId; // Load the originating product asset from which the new source has set will be generated auto materialAssetOutcome = AZ::RPI::AssetUtils::LoadAsset(editData.m_materialAssetId); if (!materialAssetOutcome) { AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Failed to load material asset: %s", editData.m_materialAssetId.ToString().c_str()); return false; } editData.m_materialAsset = materialAssetOutcome.GetValue(); editData.m_materialTypeAsset = editData.m_materialAsset->GetMaterialTypeAsset(); editData.m_materialParentAsset = {}; editData.m_materialSourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(editData.m_materialAsset.GetId()); if (AzFramework::StringFunc::Path::IsExtension( editData.m_materialSourcePath.c_str(), AZ::RPI::MaterialSourceData::Extension)) { if (!AZ::RPI::JsonUtils::LoadObjectFromFile(editData.m_materialSourcePath, editData.m_materialSourceData)) { AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Material source data could not be loaded: '%s'.", editData.m_materialSourcePath.c_str()); return false; } } if (!editData.m_materialSourceData.m_parentMaterial.empty()) { // There is a parent for this material auto parentMaterialResult = AZ::RPI::AssetUtils::LoadAsset(editData.m_materialSourcePath, editData.m_materialSourceData.m_parentMaterial); if (!parentMaterialResult) { AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Parent material asset could not be loaded: '%s'.", editData.m_materialSourceData.m_parentMaterial.c_str()); return false; } editData.m_materialParentAsset = parentMaterialResult.GetValue(); editData.m_materialParentSourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(editData.m_materialParentAsset.GetId()); } // We need a valid path to the material type source data to get the property layout and assign to the new material editData.m_materialTypeSourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(editData.m_materialTypeAsset.GetId()); if (editData.m_materialTypeSourcePath.empty()) { AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Failed to locate source material type asset: %s", editData.m_materialAssetId.ToString().c_str()); return false; } // Load the material type source data auto materialTypeOutcome = AZ::RPI::MaterialUtils::LoadMaterialTypeSourceData(editData.m_materialTypeSourcePath); if (!materialTypeOutcome.IsSuccess()) { AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Failed to load material type source data: %s", editData.m_materialTypeSourcePath.c_str()); return false; } editData.m_materialTypeSourceData = materialTypeOutcome.TakeValue(); return true; } bool SaveSourceMaterialFromEditData(const AZStd::string& path, const MaterialEditData& editData) { if (path.empty() || !editData.m_materialAsset.IsReady() || !editData.m_materialTypeAsset.IsReady() || editData.m_materialTypeSourcePath.empty()) { AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Can not export: %s", path.c_str()); return false; } // Construct the material source data object that will be exported AZ::RPI::MaterialSourceData exportData; exportData.m_materialTypeVersion = editData.m_materialTypeAsset->GetVersion(); exportData.m_materialType = AtomToolsFramework::GetExteralReferencePath(path, editData.m_materialTypeSourcePath); exportData.m_parentMaterial = AtomToolsFramework::GetExteralReferencePath(path, editData.m_materialParentSourcePath); // Copy all of the properties from the material asset to the source data that will be exported bool result = true; editData.m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& propertyIdContext, const AZ::RPI::MaterialTypeSourceData::PropertyDefinition* propertyDefinition) { AZ::Name propertyId(propertyIdContext + propertyDefinition->GetName()); const AZ::RPI::MaterialPropertyIndex propertyIndex = editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId); AZ::RPI::MaterialPropertyValue propertyValue = editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]; AZ::RPI::MaterialPropertyValue propertyValueDefault = propertyDefinition->m_value; if (editData.m_materialParentAsset.IsReady()) { propertyValueDefault = editData.m_materialParentAsset->GetPropertyValues()[propertyIndex.GetIndex()]; } // Check for and apply any property overrides before saving property values auto propertyOverrideItr = editData.m_materialPropertyOverrideMap.find(propertyId); if (propertyOverrideItr != editData.m_materialPropertyOverrideMap.end()) { propertyValue = AZ::RPI::MaterialPropertyValue::FromAny(propertyOverrideItr->second); } if (!AtomToolsFramework::ConvertToExportFormat(path, propertyId, *propertyDefinition, propertyValue)) { AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Failed to export: %s", path.c_str()); result = false; return false; } // Don't export values if they are the same as the material type or parent if (propertyValueDefault == propertyValue) { return true; } // TODO: Support populating the Material Editor with nested property groups, not just the top level. AZStd::string_view groupName = propertyId.GetStringView().substr(0, propertyId.GetStringView().size() - propertyDefinition->GetName().size() - 1); exportData.SetPropertyValue(RPI::MaterialPropertyId{groupName, propertyDefinition->GetName()}, propertyValue); return true; }); return result && AZ::RPI::JsonUtils::SaveObjectToFile(path, exportData); } } // namespace EditorMaterialComponentUtil } // namespace Render } // namespace AZ //#include