material editor and exporter save source materials with relative paths

Signed-off-by: Guthrie Adams <guthadam@amazon.com>
monroegm-disable-blank-issue-2
Guthrie Adams 4 years ago
parent a544800536
commit f18f838da6

@ -209,10 +209,6 @@ namespace AZ
//! Traversal will stop once all properties have been enumerated or the callback function returns false //! Traversal will stop once all properties have been enumerated or the callback function returns false
void EnumeratePropertiesInDisplayOrder(const EnumeratePropertiesCallback& callback) const; void EnumeratePropertiesInDisplayOrder(const EnumeratePropertiesCallback& callback) const;
//! Convert the property value into the format that will be stored in the source data
//! This is primarily needed to support conversions of special types like enums and images
bool ConvertPropertyValueToSourceDataFormat(const PropertyDefinition& propertyDefinition, MaterialPropertyValue& propertyValue) const;
Outcome<Data::Asset<MaterialTypeAsset>> CreateMaterialTypeAsset(Data::AssetId assetId, AZStd::string_view materialTypeSourceFilePath = "", bool elevateWarnings = true) const; Outcome<Data::Asset<MaterialTypeAsset>> CreateMaterialTypeAsset(Data::AssetId assetId, AZStd::string_view materialTypeSourceFilePath = "", bool elevateWarnings = true) const;
//! Possibly renames @propertyId based on the material version update steps. //! Possibly renames @propertyId based on the material version update steps.

@ -300,48 +300,6 @@ namespace AZ
} }
} }
bool MaterialTypeSourceData::ConvertPropertyValueToSourceDataFormat(const PropertyDefinition& propertyDefinition, MaterialPropertyValue& propertyValue) const
{
if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Enum && propertyValue.Is<uint32_t>())
{
const uint32_t index = propertyValue.GetValue<uint32_t>();
if (index >= propertyDefinition.m_enumValues.size())
{
AZ_Error("Material source data", false, "Invalid value for material enum property: '%s'.", propertyDefinition.m_name.c_str());
return false;
}
propertyValue = propertyDefinition.m_enumValues[index];
return true;
}
// Image asset references must be converted from asset IDs to a relative source file path
if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Image && propertyValue.Is<Data::Asset<ImageAsset>>())
{
const Data::Asset<ImageAsset>& imageAsset = propertyValue.GetValue<Data::Asset<ImageAsset>>();
Data::AssetInfo imageAssetInfo;
if (imageAsset.GetId().IsValid())
{
bool result = false;
AZStd::string rootFilePath;
const AZStd::string platformName = ""; // Empty for default
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(result, &AzToolsFramework::AssetSystem::AssetSystemRequest::GetAssetInfoById,
imageAsset.GetId(), imageAsset.GetType(), platformName, imageAssetInfo, rootFilePath);
if (!result)
{
AZ_Error("Material source data", false, "Image asset could not be found for property: '%s'.", propertyDefinition.m_name.c_str());
return false;
}
}
propertyValue = imageAssetInfo.m_relativePath;
return true;
}
return true;
}
Outcome<Data::Asset<MaterialTypeAsset>> MaterialTypeSourceData::CreateMaterialTypeAsset(Data::AssetId assetId, AZStd::string_view materialTypeSourceFilePath, bool elevateWarnings) const Outcome<Data::Asset<MaterialTypeAsset>> MaterialTypeSourceData::CreateMaterialTypeAsset(Data::AssetId assetId, AZStd::string_view materialTypeSourceFilePath, bool elevateWarnings) const
{ {
MaterialTypeAssetCreator materialTypeAssetCreator; MaterialTypeAssetCreator materialTypeAssetCreator;

@ -7,11 +7,12 @@
*/ */
#pragma once #pragma once
#include <AzCore/std/any.h>
#include <AtomToolsFramework/DynamicProperty/DynamicProperty.h>
#include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h> #include <Atom/RPI.Edit/Material/MaterialTypeSourceData.h>
#include <Atom/RPI.Reflect/Material/MaterialPropertyDescriptor.h> #include <Atom/RPI.Reflect/Material/MaterialPropertyDescriptor.h>
#include <Atom/RPI.Reflect/Material/MaterialPropertyValue.h> #include <Atom/RPI.Reflect/Material/MaterialPropertyValue.h>
#include <AtomToolsFramework/DynamicProperty/DynamicProperty.h>
#include <AzCore/IO/Path/Path.h>
#include <AzCore/std/any.h>
namespace AzToolsFramework namespace AzToolsFramework
{ {
@ -41,6 +42,13 @@ namespace AtomToolsFramework
//! Compare equality of data types and values of editor property stored in AZStd::any //! Compare equality of data types and values of editor property stored in AZStd::any
bool ArePropertyValuesEqual(const AZStd::any& valueA, const AZStd::any& valueB); bool ArePropertyValuesEqual(const AZStd::any& valueA, const AZStd::any& valueB);
//! Convert the property value into the format that will be stored in the source data
//! This is primarily needed to support conversions of special types like enums and images
bool ConvertToExportFormat(
const AZ::IO::BasicPath<AZStd::string>& exportFolder,
const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& propertyDefinition,
AZ::RPI::MaterialPropertyValue& propertyValue);
//! Traverse up the instance data node hierarchy to find the containing dynamic property object //! Traverse up the instance data node hierarchy to find the containing dynamic property object
const AtomToolsFramework::DynamicProperty* FindDynamicPropertyForInstanceDataNode(const AzToolsFramework::InstanceDataNode* pNode); const AtomToolsFramework::DynamicProperty* FindDynamicPropertyForInstanceDataNode(const AzToolsFramework::InstanceDataNode* pNode);
} // namespace AtomToolsFramework } // namespace AtomToolsFramework

@ -6,9 +6,10 @@
* *
*/ */
#include <AtomToolsFramework/Util/MaterialPropertyUtil.h>
#include <AtomToolsFramework/DynamicProperty/DynamicProperty.h> #include <AtomToolsFramework/DynamicProperty/DynamicProperty.h>
#include <AtomToolsFramework/Util/MaterialPropertyUtil.h>
#include <Atom/RPI.Edit/Common/AssetUtils.h>
#include <Atom/RPI.Reflect/Image/ImageAsset.h> #include <Atom/RPI.Reflect/Image/ImageAsset.h>
#include <Atom/RPI.Reflect/Image/StreamingImageAsset.h> #include <Atom/RPI.Reflect/Image/StreamingImageAsset.h>
#include <Atom/RPI.Reflect/Material/MaterialAsset.h> #include <Atom/RPI.Reflect/Material/MaterialAsset.h>
@ -18,6 +19,7 @@
#include <AzCore/Math/Vector2.h> #include <AzCore/Math/Vector2.h>
#include <AzCore/Math/Vector3.h> #include <AzCore/Math/Vector3.h>
#include <AzCore/Math/Vector4.h> #include <AzCore/Math/Vector4.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/UI/PropertyEditor/InstanceDataHierarchy.h> #include <AzToolsFramework/UI/PropertyEditor/InstanceDataHierarchy.h>
namespace AtomToolsFramework namespace AtomToolsFramework
@ -163,6 +165,47 @@ namespace AtomToolsFramework
return false; return false;
} }
bool ConvertToExportFormat(
const AZ::IO::BasicPath<AZStd::string>& exportFolder,
const AZ::RPI::MaterialTypeSourceData::PropertyDefinition& propertyDefinition,
AZ::RPI::MaterialPropertyValue& propertyValue)
{
if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Enum && propertyValue.Is<uint32_t>())
{
const uint32_t index = propertyValue.GetValue<uint32_t>();
if (index >= propertyDefinition.m_enumValues.size())
{
AZ_Error("AtomToolsFramework", false, "Invalid value for material enum property: '%s'.", propertyDefinition.m_name.c_str());
return false;
}
propertyValue = propertyDefinition.m_enumValues[index];
return true;
}
// Image asset references must be converted from asset IDs to a relative source file path
if (propertyDefinition.m_dataType == AZ::RPI::MaterialPropertyDataType::Image)
{
if (propertyValue.Is<AZ::Data::Asset<AZ::RPI::ImageAsset>>())
{
const auto& imageAsset = propertyValue.GetValue<AZ::Data::Asset<AZ::RPI::ImageAsset>>();
const auto& sourcePath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(imageAsset.GetId());
propertyValue = AZ::IO::PathView(sourcePath).LexicallyRelative(exportFolder).StringAsPosix();
return true;
}
if (propertyValue.Is<AZ::Data::Instance<AZ::RPI::Image>>())
{
const auto& image = propertyValue.GetValue<AZ::Data::Instance<AZ::RPI::Image>>();
const auto& sourcePath = image ? AZ::RPI::AssetUtils::GetSourcePathByAssetId(image->GetAssetId()) : "";
propertyValue = AZ::IO::PathView(sourcePath).LexicallyRelative(exportFolder).StringAsPosix();
return true;
}
}
return true;
}
const AtomToolsFramework::DynamicProperty* FindDynamicPropertyForInstanceDataNode(const AzToolsFramework::InstanceDataNode* pNode) const AtomToolsFramework::DynamicProperty* FindDynamicPropertyForInstanceDataNode(const AzToolsFramework::InstanceDataNode* pNode)
{ {
// Traverse up the hierarchy from the input node to search for an instance corresponding to material inspector property // Traverse up the hierarchy from the input node to search for an instance corresponding to material inspector property
@ -172,7 +215,8 @@ namespace AtomToolsFramework
const AZ::SerializeContext::ClassData* classData = currentNode->GetClassMetadata(); const AZ::SerializeContext::ClassData* classData = currentNode->GetClassMetadata();
if (context && classData) if (context && classData)
{ {
if (context->CanDowncast(classData->m_typeId, azrtti_typeid<AtomToolsFramework::DynamicProperty>(), classData->m_azRtti, nullptr)) if (context->CanDowncast(
classData->m_typeId, azrtti_typeid<AtomToolsFramework::DynamicProperty>(), classData->m_azRtti, nullptr))
{ {
return static_cast<const AtomToolsFramework::DynamicProperty*>(currentNode->FirstInstance()); return static_cast<const AtomToolsFramework::DynamicProperty*>(currentNode->FirstInstance());
} }

@ -228,22 +228,22 @@ namespace MaterialEditor
return false; return false;
} }
AZ::IO::BasicPath<AZStd::string> exportFolder(m_absolutePath);
exportFolder.RemoveFilename();
// create source data from properties // create source data from properties
MaterialSourceData sourceData; MaterialSourceData sourceData;
sourceData.m_materialType = m_materialSourceData.m_materialType; sourceData.m_propertyLayoutVersion = m_materialTypeSourceData.m_propertyLayout.m_version;
sourceData.m_parentMaterial = m_materialSourceData.m_parentMaterial; sourceData.m_materialType = AZ::IO::PathView(m_materialSourceData.m_materialType).LexicallyRelative(exportFolder).StringAsPosix();
sourceData.m_parentMaterial = AZ::IO::PathView(m_materialSourceData.m_parentMaterial).LexicallyRelative(exportFolder).StringAsPosix();
AZ_Assert(m_materialAsset && m_materialAsset->GetMaterialTypeAsset(), "When IsOpen() is true, these assets should not be null.");
sourceData.m_materialTypeVersion = m_materialAsset->GetMaterialTypeAsset()->GetVersion();
// Force save data to store forward slashes
AzFramework::StringFunc::Replace(sourceData.m_materialType, "\\", "/");
AzFramework::StringFunc::Replace(sourceData.m_parentMaterial, "\\", "/");
// populate sourceData with modified or overwritten properties // populate sourceData with modified or overwritten properties
const bool savedProperties = SavePropertiesToSourceData(sourceData, [](const AtomToolsFramework::DynamicProperty& property) { const bool savedProperties = SavePropertiesToSourceData(
return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue); exportFolder, sourceData,
}); [](const AtomToolsFramework::DynamicProperty& property)
{
return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue);
});
if (!savedProperties) if (!savedProperties)
{ {
@ -302,22 +302,22 @@ namespace MaterialEditor
return false; return false;
} }
AZ::IO::BasicPath<AZStd::string> exportFolder(normalizedSavePath);
exportFolder.RemoveFilename();
// create source data from properties // create source data from properties
MaterialSourceData sourceData; MaterialSourceData sourceData;
sourceData.m_materialType = m_materialSourceData.m_materialType; sourceData.m_propertyLayoutVersion = m_materialTypeSourceData.m_propertyLayout.m_version;
sourceData.m_parentMaterial = m_materialSourceData.m_parentMaterial; sourceData.m_materialType = AZ::IO::PathView(m_materialSourceData.m_materialType).LexicallyRelative(exportFolder).StringAsPosix();
sourceData.m_parentMaterial = AZ::IO::PathView(m_materialSourceData.m_parentMaterial).LexicallyRelative(exportFolder).StringAsPosix();
AZ_Assert(m_materialAsset && m_materialAsset->GetMaterialTypeAsset(), "When IsOpen() is true, these assets should not be null.");
sourceData.m_materialTypeVersion = m_materialAsset->GetMaterialTypeAsset()->GetVersion();
// Force save data to store forward slashes
AzFramework::StringFunc::Replace(sourceData.m_materialType, "\\", "/");
AzFramework::StringFunc::Replace(sourceData.m_parentMaterial, "\\", "/");
// populate sourceData with modified or overwritten properties // populate sourceData with modified or overwritten properties
const bool savedProperties = SavePropertiesToSourceData(sourceData, [](const AtomToolsFramework::DynamicProperty& property) { const bool savedProperties = SavePropertiesToSourceData(
return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue); exportFolder, sourceData,
}); [](const AtomToolsFramework::DynamicProperty& property)
{
return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_parentValue);
});
if (!savedProperties) if (!savedProperties)
{ {
@ -375,17 +375,18 @@ namespace MaterialEditor
return false; return false;
} }
AZ::IO::BasicPath<AZStd::string> exportFolder(normalizedSavePath);
exportFolder.RemoveFilename();
// create source data from properties // create source data from properties
MaterialSourceData sourceData; MaterialSourceData sourceData;
sourceData.m_materialType = m_materialSourceData.m_materialType; sourceData.m_propertyLayoutVersion = m_materialTypeSourceData.m_propertyLayout.m_version;
sourceData.m_materialType = AZ::IO::PathView(m_materialSourceData.m_materialType).LexicallyRelative(exportFolder).StringAsPosix();
AZ_Assert(m_materialAsset && m_materialAsset->GetMaterialTypeAsset(), "When IsOpen() is true, these assets should not be null.");
sourceData.m_materialTypeVersion = m_materialAsset->GetMaterialTypeAsset()->GetVersion();
// Only assign a parent path if the source was a .material // Only assign a parent path if the source was a .material
if (AzFramework::StringFunc::Path::IsExtension(m_relativePath.c_str(), MaterialSourceData::Extension)) if (AzFramework::StringFunc::Path::IsExtension(m_relativePath.c_str(), MaterialSourceData::Extension))
{ {
sourceData.m_parentMaterial = m_relativePath; sourceData.m_parentMaterial = AZ::IO::PathView(m_absolutePath).LexicallyRelative(exportFolder).StringAsPosix();
} }
// Force save data to store forward slashes // Force save data to store forward slashes
@ -393,9 +394,12 @@ namespace MaterialEditor
AzFramework::StringFunc::Replace(sourceData.m_parentMaterial, "\\", "/"); AzFramework::StringFunc::Replace(sourceData.m_parentMaterial, "\\", "/");
// populate sourceData with modified properties // populate sourceData with modified properties
const bool savedProperties = SavePropertiesToSourceData(sourceData, [](const AtomToolsFramework::DynamicProperty& property) { const bool savedProperties = SavePropertiesToSourceData(
return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_originalValue); exportFolder, sourceData,
}); [](const AtomToolsFramework::DynamicProperty& property)
{
return !AtomToolsFramework::ArePropertyValuesEqual(property.GetValue(), property.GetConfig().m_originalValue);
});
if (!savedProperties) if (!savedProperties)
{ {
@ -590,7 +594,10 @@ namespace MaterialEditor
} }
} }
bool MaterialDocument::SavePropertiesToSourceData(AZ::RPI::MaterialSourceData& sourceData, PropertyFilterFunction propertyFilter) const bool MaterialDocument::SavePropertiesToSourceData(
const AZ::IO::BasicPath<AZStd::string>& exportFolder,
AZ::RPI::MaterialSourceData& sourceData,
PropertyFilterFunction propertyFilter) const
{ {
using namespace AZ; using namespace AZ;
using namespace RPI; using namespace RPI;
@ -598,7 +605,7 @@ namespace MaterialEditor
bool result = true; bool result = true;
// populate sourceData with properties that meet the filter // populate sourceData with properties that meet the filter
m_materialTypeSourceData.EnumerateProperties([this, &sourceData, &propertyFilter, &result](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition) { m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition) {
const MaterialPropertyId propertyId(groupName, propertyName); const MaterialPropertyId propertyId(groupName, propertyName);
@ -608,7 +615,7 @@ namespace MaterialEditor
MaterialPropertyValue propertyValue = AtomToolsFramework::ConvertToRuntimeType(it->second.GetValue()); MaterialPropertyValue propertyValue = AtomToolsFramework::ConvertToRuntimeType(it->second.GetValue());
if (propertyValue.IsValid()) if (propertyValue.IsValid())
{ {
if (!m_materialTypeSourceData.ConvertPropertyValueToSourceDataFormat(propertyDefinition, propertyValue)) if (!AtomToolsFramework::ConvertToExportFormat(exportFolder, propertyDefinition, propertyValue))
{ {
AZ_Error("MaterialDocument", false, "Material document property could not be converted: '%s' in '%s'.", propertyId.GetFullName().GetCStr(), m_absolutePath.c_str()); AZ_Error("MaterialDocument", false, "Material document property could not be converted: '%s' in '%s'.", propertyId.GetFullName().GetCStr(), m_absolutePath.c_str());
result = false; result = false;
@ -662,8 +669,6 @@ namespace MaterialEditor
return false; return false;
} }
AZStd::string materialTypeSourceFilePath;
// The material document and inspector are constructed from source data // The material document and inspector are constructed from source data
if (AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), MaterialSourceData::Extension)) if (AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), MaterialSourceData::Extension))
{ {
@ -676,27 +681,29 @@ namespace MaterialEditor
// We must also always load the material type data for a complete, ordered set of the // We must also always load the material type data for a complete, ordered set of the
// groups and properties that will be needed for comparison and building the inspector // groups and properties that will be needed for comparison and building the inspector
materialTypeSourceFilePath = AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_materialType); if (!m_materialSourceData.m_parentMaterial.empty())
auto materialTypeOutcome = MaterialUtils::LoadMaterialTypeSourceData(materialTypeSourceFilePath);
if (!materialTypeOutcome.IsSuccess())
{ {
AZ_Error("MaterialDocument", false, "Material type source data could not be loaded: '%s'.", materialTypeSourceFilePath.c_str()); m_materialSourceData.m_parentMaterial =
return false; AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_parentMaterial);
} }
m_materialTypeSourceData = materialTypeOutcome.GetValue();
if (!m_materialSourceData.m_materialType.empty())
if (MaterialSourceData::ApplyVersionUpdatesResult::Failed == m_materialSourceData.ApplyVersionUpdates(m_absolutePath)) {
m_materialSourceData.m_materialType = AssetUtils::ResolvePathReference(m_absolutePath, m_materialSourceData.m_materialType);
}
auto materialTypeOutcome = MaterialUtils::LoadMaterialTypeSourceData(m_materialSourceData.m_materialType);
if (!materialTypeOutcome.IsSuccess())
{ {
AZ_Error("MaterialDocument", false, "Material source data could not be auto updated to the latest version of the material type: '%s'.", m_materialSourceData.m_materialType.c_str()); AZ_Error("MaterialDocument", false, "Material type source data could not be loaded: '%s'.", m_materialSourceData.m_materialType.c_str());
return false; return false;
} }
m_materialTypeSourceData = materialTypeOutcome.GetValue();
} }
else if (AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), MaterialTypeSourceData::Extension)) else if (AzFramework::StringFunc::Path::IsExtension(m_absolutePath.c_str(), MaterialTypeSourceData::Extension))
{ {
materialTypeSourceFilePath = m_absolutePath;
// Load the material type source data, which will be used for enumerating properties and building material source data // Load the material type source data, which will be used for enumerating properties and building material source data
auto materialTypeOutcome = MaterialUtils::LoadMaterialTypeSourceData(materialTypeSourceFilePath); auto materialTypeOutcome = MaterialUtils::LoadMaterialTypeSourceData(m_absolutePath);
if (!materialTypeOutcome.IsSuccess()) if (!materialTypeOutcome.IsSuccess())
{ {
AZ_Error("MaterialDocument", false, "Material type source data could not be loaded: '%s'.", m_absolutePath.c_str()); AZ_Error("MaterialDocument", false, "Material type source data could not be loaded: '%s'.", m_absolutePath.c_str());
@ -706,7 +713,7 @@ namespace MaterialEditor
// The document represents a material, not a material type. // The document represents a material, not a material type.
// If the input data is a material type file we have to generate the material source data by referencing it. // If the input data is a material type file we have to generate the material source data by referencing it.
m_materialSourceData.m_materialType = m_relativePath; m_materialSourceData.m_materialType = m_absolutePath;
m_materialSourceData.m_parentMaterial.clear(); m_materialSourceData.m_parentMaterial.clear();
} }
else else
@ -877,7 +884,8 @@ namespace MaterialEditor
m_properties[propertyConfig.m_id] = AtomToolsFramework::DynamicProperty(propertyConfig); m_properties[propertyConfig.m_id] = AtomToolsFramework::DynamicProperty(propertyConfig);
} }
const MaterialFunctorSourceData::EditorContext editorContext = MaterialFunctorSourceData::EditorContext(materialTypeSourceFilePath, m_materialAsset->GetMaterialPropertiesLayout()); const MaterialFunctorSourceData::EditorContext editorContext =
MaterialFunctorSourceData::EditorContext(m_materialSourceData.m_materialType, m_materialAsset->GetMaterialPropertiesLayout());
for (Ptr<MaterialFunctorSourceDataHolder> functorData : m_materialTypeSourceData.m_materialFunctorSourceData) for (Ptr<MaterialFunctorSourceDataHolder> functorData : m_materialTypeSourceData.m_materialFunctorSourceData)
{ {
MaterialFunctorSourceData::FunctorResult result2 = functorData->CreateFunctor(editorContext); MaterialFunctorSourceData::FunctorResult result2 = functorData->CreateFunctor(editorContext);

@ -104,7 +104,10 @@ namespace MaterialEditor
void SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid sourceUUID) override; void SourceFileChanged(AZStd::string relativePath, AZStd::string scanFolder, AZ::Uuid sourceUUID) override;
////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////
bool SavePropertiesToSourceData(AZ::RPI::MaterialSourceData& sourceData, PropertyFilterFunction propertyFilter) const; bool SavePropertiesToSourceData(
const AZ::IO::BasicPath<AZStd::string>& exportFolder,
AZ::RPI::MaterialSourceData& sourceData,
PropertyFilterFunction propertyFilter) const;
bool OpenInternal(AZStd::string_view loadPath); bool OpenInternal(AZStd::string_view loadPath);

@ -17,6 +17,7 @@
#include <Atom/RPI.Reflect/Material/MaterialAsset.h> #include <Atom/RPI.Reflect/Material/MaterialAsset.h>
#include <Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h> #include <Atom/RPI.Reflect/Material/MaterialPropertiesLayout.h>
#include <Atom/RPI.Reflect/Material/MaterialTypeAsset.h> #include <Atom/RPI.Reflect/Material/MaterialTypeAsset.h>
#include <AtomToolsFramework/Util/MaterialPropertyUtil.h>
#include <AzFramework/API/ApplicationAPI.h> #include <AzFramework/API/ApplicationAPI.h>
#include <AzToolsFramework/API/EditorAssetSystemAPI.h> #include <AzToolsFramework/API/EditorAssetSystemAPI.h>
#include <AzToolsFramework/API/ToolsApplicationAPI.h> #include <AzToolsFramework/API/ToolsApplicationAPI.h>
@ -97,29 +98,38 @@ namespace AZ
bool SaveSourceMaterialFromEditData(const AZStd::string& path, const MaterialEditData& editData) bool SaveSourceMaterialFromEditData(const AZStd::string& path, const MaterialEditData& editData)
{ {
AZ::IO::BasicPath<AZStd::string> exportFolder(path);
exportFolder.RemoveFilename();
// Construct the material source data object that will be exported // Construct the material source data object that will be exported
AZ::RPI::MaterialSourceData exportData; AZ::RPI::MaterialSourceData exportData;
// Converting absolute material paths to relative paths // Converting absolute material paths to relative paths
bool result = false; if (!editData.m_materialTypeSourcePath.empty())
AZ::Data::AssetInfo info;
AZStd::string watchFolder;
AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath,
editData.m_materialTypeSourcePath.c_str(), info, watchFolder);
if (!result)
{ {
AZ_Error( bool result = false;
"AZ::Render::EditorMaterialComponentUtil", false, AZ::Data::AssetInfo info;
"Failed to get material type source file info while attempting to export: %s", path.c_str()); AZStd::string watchFolder;
return false; AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
} result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath,
editData.m_materialTypeSourcePath.c_str(), info, watchFolder);
if (!result)
{
AZ_Error(
"AZ::Render::EditorMaterialComponentUtil", false,
"Failed to get material type source file info while attempting to export: %s", path.c_str());
return false;
}
exportData.m_materialType = info.m_relativePath; exportData.m_materialType =
AZ::IO::PathView(editData.m_materialTypeSourcePath).LexicallyRelative(exportFolder).StringAsPosix();
}
if (!editData.m_materialParentSourcePath.empty()) if (!editData.m_materialParentSourcePath.empty())
{ {
result = false; bool result = false;
AZ::Data::AssetInfo info;
AZStd::string watchFolder;
AzToolsFramework::AssetSystemRequestBus::BroadcastResult( AzToolsFramework::AssetSystemRequestBus::BroadcastResult(
result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath, result, &AzToolsFramework::AssetSystemRequestBus::Events::GetSourceInfoBySourcePath,
editData.m_materialParentSourcePath.c_str(), info, watchFolder); editData.m_materialParentSourcePath.c_str(), info, watchFolder);
@ -131,17 +141,19 @@ namespace AZ
return false; return false;
} }
exportData.m_parentMaterial = info.m_relativePath; exportData.m_parentMaterial =
AZ::IO::PathView(editData.m_materialParentSourcePath).LexicallyRelative(exportFolder).StringAsPosix();
} }
// Copy all of the properties from the material asset to the source data that will be exported // Copy all of the properties from the material asset to the source data that will be exported
result = true; bool result = true;
editData.m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition) { editData.m_materialTypeSourceData.EnumerateProperties([&](const AZStd::string& groupName, const AZStd::string& propertyName, const auto& propertyDefinition){
const AZ::RPI::MaterialPropertyId propertyId(groupName, propertyName); const AZ::RPI::MaterialPropertyId propertyId(groupName, propertyName);
const AZ::RPI::MaterialPropertyIndex propertyIndex = const AZ::RPI::MaterialPropertyIndex propertyIndex =
editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId.GetFullName()); editData.m_materialAsset->GetMaterialPropertiesLayout()->FindPropertyIndex(propertyId.GetFullName());
AZ::RPI::MaterialPropertyValue propertyValue = editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()]; AZ::RPI::MaterialPropertyValue propertyValue =
editData.m_materialAsset->GetPropertyValues()[propertyIndex.GetIndex()];
AZ::RPI::MaterialPropertyValue propertyValueDefault = propertyDefinition.m_value; AZ::RPI::MaterialPropertyValue propertyValueDefault = propertyDefinition.m_value;
if (editData.m_materialParentAsset.IsReady()) if (editData.m_materialParentAsset.IsReady())
@ -151,12 +163,12 @@ namespace AZ
// Check for and apply any property overrides before saving property values // Check for and apply any property overrides before saving property values
auto propertyOverrideItr = editData.m_materialPropertyOverrideMap.find(propertyId.GetFullName()); auto propertyOverrideItr = editData.m_materialPropertyOverrideMap.find(propertyId.GetFullName());
if(propertyOverrideItr != editData.m_materialPropertyOverrideMap.end()) if (propertyOverrideItr != editData.m_materialPropertyOverrideMap.end())
{ {
propertyValue = AZ::RPI::MaterialPropertyValue::FromAny(propertyOverrideItr->second); propertyValue = AZ::RPI::MaterialPropertyValue::FromAny(propertyOverrideItr->second);
} }
if (!editData.m_materialTypeSourceData.ConvertPropertyValueToSourceDataFormat(propertyDefinition, propertyValue)) if (!AtomToolsFramework::ConvertToExportFormat(exportFolder, propertyDefinition, propertyValue))
{ {
AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Failed to export: %s", path.c_str()); AZ_Error("AZ::Render::EditorMaterialComponentUtil", false, "Failed to export: %s", path.c_str());
result = false; result = false;

Loading…
Cancel
Save