@ -58,6 +58,10 @@ namespace AZ
serializeContext - > Class < GroupDefinition > ( ) - > Version ( 4 ) ;
serializeContext - > Class < PropertyDefinition > ( ) - > Version ( 1 ) ;
serializeContext - > RegisterGenericType < AZStd : : unique_ptr < PropertyGroup > > ( ) ;
serializeContext - > RegisterGenericType < AZStd : : unique_ptr < PropertyDefinition > > ( ) ;
serializeContext - > RegisterGenericType < AZStd : : vector < AZStd : : unique_ptr < PropertyGroup > > > ( ) ;
serializeContext - > RegisterGenericType < AZStd : : vector < AZStd : : unique_ptr < PropertyDefinition > > > ( ) ;
serializeContext - > RegisterGenericType < PropertyConnectionList > ( ) ;
serializeContext - > Class < VersionUpdatesRenameOperationDefinition > ( )
@ -84,11 +88,22 @@ namespace AZ
- > Field ( " options " , & ShaderVariantReferenceData : : m_shaderOptionValues )
;
serializeContext - > Class < PropertyGroup > ( )
- > Version ( 1 )
- > Field ( " name " , & PropertyGroup : : m_name )
- > Field ( " displayName " , & PropertyGroup : : m_displayName )
- > Field ( " description " , & PropertyGroup : : m_description )
- > Field ( " properties " , & PropertyGroup : : m_properties )
- > Field ( " propertyGroups " , & PropertyGroup : : m_propertyGroups )
- > Field ( " functors " , & PropertyGroup : : m_materialFunctorSourceData )
;
serializeContext - > Class < PropertyLayout > ( )
- > Version ( 2 ) // Material Version Update
- > Field ( " version " , & PropertyLayout : : m_versionOld )
- > Field ( " groups " , & PropertyLayout : : m_groups )
- > Field ( " properties " , & PropertyLayout : : m_properties )
- > Version ( 3 ) // Added propertyGroups
- > Field ( " version " , & PropertyLayout : : m_versionOld ) //< Deprecated, preserved for backward compatibility, replaced by MaterialTypeSourceData::version
- > Field ( " groups " , & PropertyLayout : : m_groupsOld ) //< Deprecated, preserved for backward compatibility, replaced by propertyGroups
- > Field ( " properties " , & PropertyLayout : : m_propertiesOld ) //< Deprecated, preserved for backward compatibility, replaced by propertyGroups
- > Field ( " propertyGroups " , & PropertyLayout : : m_propertyGroups )
;
serializeContext - > RegisterGenericType < UvNameMap > ( ) ;
@ -117,78 +132,194 @@ namespace AZ
const float MaterialTypeSourceData : : PropertyDefinition : : DefaultMax = std : : numeric_limits < float > : : max ( ) ;
const float MaterialTypeSourceData : : PropertyDefinition : : DefaultStep = 0.1f ;
const MaterialTypeSourceData : : GroupDefinition * MaterialTypeSourceData : : FindGroup ( AZStd : : string_view groupName ) const
/*static*/ MaterialTypeSourceData : : PropertyGroup * MaterialTypeSourceData : : PropertyGroup : : AddPropertyGroup ( AZStd : : string_view name , AZStd : : vector < AZStd : : unique_ptr < PropertyGroup > > & toPropertyGroupList )
{
for ( const GroupDefinition & group : m_propertyLayout . m_groups )
auto iter = AZStd : : find_if ( toPropertyGroupList . begin ( ) , toPropertyGroupList . end ( ) , [ name ] ( const AZStd : : unique_ptr < PropertyGroup > & existingPropertyGroup )
{
if ( group . m_name = = groupName )
return existingPropertyGroup - > m_name = = name ;
} ) ;
if ( iter ! = toPropertyGroupList . end ( ) )
{
return & group ;
AZ_Error ( " Material source data " , false , " PropertyGroup named '%.*s' already exists " , AZ_STRING_ARG ( name ) ) ;
return nullptr ;
}
if ( ! MaterialPropertyId : : IsValidName ( name ) )
{
AZ_Error ( " Material source data " , false , " '%.*s' is not a valid identifier " , AZ_STRING_ARG ( name ) ) ;
return nullptr ;
}
toPropertyGroupList . push_back ( AZStd : : make_unique < PropertyGroup > ( ) ) ;
toPropertyGroupList . back ( ) - > m_name = name ;
return toPropertyGroupList . back ( ) . get ( ) ;
}
MaterialTypeSourceData : : PropertyDefinition * MaterialTypeSourceData : : PropertyGroup : : AddProperty ( AZStd : : string_view name )
{
auto propertyIter = AZStd : : find_if ( m_properties . begin ( ) , m_properties . end ( ) , [ name ] ( const AZStd : : unique_ptr < PropertyDefinition > & existingProperty )
{
return existingProperty - > GetName ( ) = = name ;
} ) ;
if ( propertyIter ! = m_properties . end ( ) )
{
AZ_Error ( " Material source data " , false , " PropertyGroup '%s' already contains a property named '%.*s' " , m_name . c_str ( ) , AZ_STRING_ARG ( name ) ) ;
return nullptr ;
}
bool MaterialTypeSourceData : : ApplyPropertyRenames ( MaterialPropertyId & propertyId ) const
auto propertyGroupIter = AZStd : : find_if ( m_propertyGroups . begin ( ) , m_propertyGroups . end ( ) , [ name ] ( const AZStd : : unique_ptr < PropertyGroup > & existingPropertyGroup )
{
bool renamed = false ;
return existingPropertyGroup - > m_name = = name ;
} ) ;
for ( const VersionUpdateDefinition & versionUpdate : m_versionUpdates )
if ( propertyGroupIter ! = m_propertyGroups . end ( ) )
{
for ( const VersionUpdatesRenameOperationDefinition & action : versionUpdate . m_actions )
AZ_Error ( " Material source data " , false , " Property name '%.*s' collides with a PropertyGroup of the same name " , AZ_STRING_ARG ( name ) ) ;
return nullptr ;
}
if ( ! MaterialPropertyId : : IsValidName ( name ) )
{
AZ_Error ( " Material source data " , false , " '%.*s' is not a valid identifier " , AZ_STRING_ARG ( name ) ) ;
return nullptr ;
}
m_properties . emplace_back ( AZStd : : make_unique < PropertyDefinition > ( name ) ) ;
return m_properties . back ( ) . get ( ) ;
}
MaterialTypeSourceData : : PropertyGroup * MaterialTypeSourceData : : PropertyGroup : : AddPropertyGroup ( AZStd : : string_view name )
{
if ( action . m_operation = = " rename " )
auto iter = AZStd : : find_if ( m_properties . begin ( ) , m_properties . end ( ) , [ name ] ( const AZStd : : unique_ptr < PropertyDefinition > & existingProperty )
{
if ( action . m_renameFrom = = propertyId . GetStringView ( ) )
return existingProperty - > GetName ( ) = = name ;
} ) ;
if ( iter ! = m_properties . end ( ) )
{
propertyId = MaterialPropertyId : : Parse ( action . m_renameTo ) ;
renamed = true ;
AZ_Error ( " Material source data " , false , " PropertyGroup name '%.*s' collides with a Property of the same name " , AZ_STRING_ARG ( name ) ) ;
return nullptr ;
}
return AddPropertyGroup ( name , m_propertyGroups ) ;
}
else
MaterialTypeSourceData : : PropertyGroup * MaterialTypeSourceData : : AddPropertyGroup ( AZStd : : string_view propertyGroupId )
{
AZStd : : vector < AZStd : : string_view > splitPropertyGroupId = SplitId ( propertyGroupId ) ;
if ( splitPropertyGroupId . size ( ) = = 1 )
{
return PropertyGroup : : AddPropertyGroup ( propertyGroupId , m_propertyLayout . m_propertyGroups ) ;
}
PropertyGroup * parentPropertyGroup = FindPropertyGroup ( splitPropertyGroupId [ 0 ] ) ;
if ( ! parentPropertyGroup )
{
AZ_Warning ( " Material source data " , false , " Unsupported material version update operation '%s' " , action . m_operation . c_str ( ) ) ;
AZ_Error ( " Material source data " , false , " PropertyGroup '%.*s' does not exists " , AZ_STRING_ARG ( splitPropertyGroupId [ 0 ] ) ) ;
return nullptr ;
}
return parentPropertyGroup - > AddPropertyGroup ( splitPropertyGroupId [ 1 ] ) ;
}
MaterialTypeSourceData : : PropertyDefinition * MaterialTypeSourceData : : AddProperty ( AZStd : : string_view propertyId )
{
AZStd : : vector < AZStd : : string_view > splitPropertyId = SplitId ( propertyId ) ;
if ( splitPropertyId . size ( ) = = 1 )
{
AZ_Error ( " Material source data " , false , " Property id '%.*s' is invalid. Properties must be added to a PropertyGroup (i.e. \" general.%.*s \" ). " , AZ_STRING_ARG ( propertyId ) , AZ_STRING_ARG ( propertyId ) ) ;
return nullptr ;
}
PropertyGroup * parentPropertyGroup = FindPropertyGroup ( splitPropertyId [ 0 ] ) ;
if ( ! parentPropertyGroup )
{
AZ_Error ( " Material source data " , false , " PropertyGroup '%.*s' does not exists " , AZ_STRING_ARG ( splitPropertyId [ 0 ] ) ) ;
return nullptr ;
}
return renamed ;
return parentPropertyGroup- > AddProperty ( splitPropertyId [ 1 ] ) ;
}
const MaterialTypeSourceData : : PropertyDefinition * MaterialTypeSourceData : : FindProperty ( AZStd : : string_view groupName , AZStd : : string_view propertyName ) const
const MaterialTypeSourceData : : PropertyGroup * MaterialTypeSourceData : : FindPropertyGroup ( AZStd : : span < const AZStd : : string_view > parsedPropertyGroupId , AZStd : : span < const AZStd : : unique_ptr < PropertyGroup > > inPropertyGroupList ) const
{
for ( const auto & propertyGroup : inPropertyGroupList )
{
if ( propertyGroup - > m_name ! = parsedPropertyGroupId [ 0 ] )
{
continue ;
}
else if ( parsedPropertyGroupId . size ( ) = = 1 )
{
auto groupIter = m_propertyLayout . m_properties . find ( groupName ) ;
if ( groupIter ! = m_propertyLayout . m_properties . end ( ) )
return propertyGroup . get ( ) ;
}
else
{
for ( const PropertyDefinition & property : groupIter - > second )
AZStd : : span < const AZStd : : string_view > subPath { parsedPropertyGroupId . begin ( ) + 1 , parsedPropertyGroupId . end ( ) } ;
if ( ! subPath . empty ( ) )
{
if ( property . m_name = = propertyName )
const MaterialTypeSourceData : : PropertyGroup * propertySubset = FindPropertyGroup ( subPath , propertyGroup - > m_propertyGroups ) ;
if ( propertySubset )
{
return & property ;
return propertySubset ;
}
}
}
}
// Property has not been found, try looking for renames in the version history
return nullptr ;
}
MaterialTypeSourceData : : PropertyGroup * MaterialTypeSourceData : : FindPropertyGroup ( AZStd : : span < AZStd : : string_view > parsedPropertyGroupId , AZStd : : span < AZStd : : unique_ptr < PropertyGroup > > inPropertyGroupList )
{
return const_cast < PropertyGroup * > ( const_cast < const MaterialTypeSourceData * > ( this ) - > FindPropertyGroup ( parsedPropertyGroupId , inPropertyGroupList ) ) ;
}
const MaterialTypeSourceData : : PropertyGroup * MaterialTypeSourceData : : FindPropertyGroup ( AZStd : : string_view propertyGroupId ) const
{
AZStd : : vector < AZStd : : string_view > tokens = TokenizeId ( propertyGroupId ) ;
return FindPropertyGroup ( tokens , m_propertyLayout . m_propertyGroups ) ;
}
MaterialPropertyId propertyId = MaterialPropertyId { groupName , propertyName } ;
ApplyPropertyRenames ( propertyId ) ;
MaterialTypeSourceData : : PropertyGroup * MaterialTypeSourceData : : FindPropertyGroup ( AZStd : : string_view propertyGroupId )
{
AZStd : : vector < AZStd : : string_view > tokens = TokenizeId ( propertyGroupId ) ;
return FindPropertyGroup ( tokens , m_propertyLayout . m_propertyGroups ) ;
}
// Do the search again with the new names
const MaterialTypeSourceData : : PropertyDefinition * MaterialTypeSourceData : : FindProperty (
AZStd : : span < const AZStd : : string_view > parsedPropertyId ,
AZStd : : span < const AZStd : : unique_ptr < PropertyGroup > > inPropertyGroupList ) const
{
for ( const auto & propertyGroup : inPropertyGroupList )
{
if ( propertyGroup - > m_name = = parsedPropertyId [ 0 ] )
{
AZStd : : span < const AZStd : : string_view > subPath { parsedPropertyId . begin ( ) + 1 , parsedPropertyId . end ( ) } ;
AZStd : : vector < AZStd : : string > tokens ;
AZ : : StringFunc : : Tokenize ( propertyId . GetStringView ( ) , tokens , " . " , true , true ) ;
if ( tokens . size ( ) = = 2 )
if ( subPath . size ( ) = = 1 )
{
groupIter = m_propertyLayout . m_properties . find ( tokens [ 0 ] ) ;
if ( groupIter ! = m_propertyLayout . m_properties . end ( ) )
for ( AZStd : : unique_ptr < PropertyDefinition > & property : propertyGroup - > m_properties )
{
for ( const PropertyDefinition & property : groupIter - > second )
if ( property - > GetName ( ) = = subPath [ 0 ] )
{
if ( property . m_name = = tokens [ 1 ] )
return property . get ( ) ;
}
}
}
else if ( subPath . size ( ) > 1 )
{
return & property ;
const MaterialTypeSourceData : : PropertyDefinition * property = FindProperty ( subPath , propertyGroup - > m_propertyGroups ) ;
if ( property )
{
return property ;
}
}
}
@ -197,6 +328,152 @@ namespace AZ
return nullptr ;
}
MaterialTypeSourceData : : PropertyDefinition * MaterialTypeSourceData : : FindProperty ( AZStd : : span < AZStd : : string_view > parsedPropertyId , AZStd : : span < AZStd : : unique_ptr < PropertyGroup > > inPropertyGroupList )
{
return const_cast < MaterialTypeSourceData : : PropertyDefinition * > ( const_cast < const MaterialTypeSourceData * > ( this ) - > FindProperty ( parsedPropertyId , inPropertyGroupList ) ) ;
}
const MaterialTypeSourceData : : PropertyDefinition * MaterialTypeSourceData : : FindProperty ( AZStd : : string_view propertyId ) const
{
AZStd : : vector < AZStd : : string_view > tokens = TokenizeId ( propertyId ) ;
return FindProperty ( tokens , m_propertyLayout . m_propertyGroups ) ;
}
MaterialTypeSourceData : : PropertyDefinition * MaterialTypeSourceData : : FindProperty ( AZStd : : string_view propertyId )
{
AZStd : : vector < AZStd : : string_view > tokens = TokenizeId ( propertyId ) ;
return FindProperty ( tokens , m_propertyLayout . m_propertyGroups ) ;
}
AZStd : : vector < AZStd : : string_view > MaterialTypeSourceData : : TokenizeId ( AZStd : : string_view id )
{
AZStd : : vector < AZStd : : string_view > tokens ;
AzFramework : : StringFunc : : TokenizeVisitor ( id , [ & tokens ] ( AZStd : : string_view t )
{
tokens . push_back ( t ) ;
} ,
" ./ " , true , true ) ;
return tokens ;
}
AZStd : : vector < AZStd : : string_view > MaterialTypeSourceData : : SplitId ( AZStd : : string_view id )
{
AZStd : : vector < AZStd : : string_view > parts ;
parts . reserve ( 2 ) ;
size_t lastDelim = id . rfind ( ' . ' , id . size ( ) - 1 ) ;
if ( lastDelim = = AZStd : : string : : npos )
{
parts . push_back ( id ) ;
}
else
{
parts . push_back ( AZStd : : string_view { id . begin ( ) , id . begin ( ) + lastDelim } ) ;
parts . push_back ( AZStd : : string_view { id . begin ( ) + lastDelim + 1 , id . end ( ) } ) ;
}
return parts ;
}
bool MaterialTypeSourceData : : EnumeratePropertyGroups ( const EnumeratePropertyGroupsCallback & callback , AZStd : : string propertyNameContext , const AZStd : : vector < AZStd : : unique_ptr < PropertyGroup > > & inPropertyGroupList ) const
{
for ( auto & propertyGroup : inPropertyGroupList )
{
if ( ! callback ( propertyNameContext , propertyGroup . get ( ) ) )
{
return false ; // Stop processing
}
const AZStd : : string propertyNameContext2 = propertyNameContext + propertyGroup - > m_name + " . " ;
if ( ! EnumeratePropertyGroups ( callback , propertyNameContext2 , propertyGroup - > m_propertyGroups ) )
{
return false ; // Stop processing
}
}
return true ;
}
bool MaterialTypeSourceData : : EnumeratePropertyGroups ( const EnumeratePropertyGroupsCallback & callback ) const
{
if ( ! callback )
{
return false ;
}
return EnumeratePropertyGroups ( callback , { } , m_propertyLayout . m_propertyGroups ) ;
}
bool MaterialTypeSourceData : : EnumerateProperties ( const EnumeratePropertiesCallback & callback , AZStd : : string propertyNameContext , const AZStd : : vector < AZStd : : unique_ptr < PropertyGroup > > & inPropertyGroupList ) const
{
for ( auto & propertyGroup : inPropertyGroupList )
{
const AZStd : : string propertyNameContext2 = propertyNameContext + propertyGroup - > m_name + " . " ;
for ( auto & property : propertyGroup - > m_properties )
{
if ( ! callback ( propertyNameContext2 , property . get ( ) ) )
{
return false ; // Stop processing
}
}
if ( ! EnumerateProperties ( callback , propertyNameContext2 , propertyGroup - > m_propertyGroups ) )
{
return false ; // Stop processing
}
}
return true ;
}
bool MaterialTypeSourceData : : EnumerateProperties ( const EnumeratePropertiesCallback & callback ) const
{
if ( ! callback )
{
return false ;
}
return EnumerateProperties ( callback , { } , m_propertyLayout . m_propertyGroups ) ;
}
bool MaterialTypeSourceData : : ConvertToNewDataFormat ( )
{
for ( const auto & group : GetOldFormatGroupDefinitionsInDisplayOrder ( ) )
{
auto propertyListItr = m_propertyLayout . m_propertiesOld . find ( group . m_name ) ;
if ( propertyListItr ! = m_propertyLayout . m_propertiesOld . end ( ) )
{
const auto & propertyList = propertyListItr - > second ;
for ( auto & propertyDefinition : propertyList )
{
PropertyGroup * propertyGroup = FindPropertyGroup ( group . m_name ) ;
if ( ! propertyGroup )
{
m_propertyLayout . m_propertyGroups . emplace_back ( AZStd : : make_unique < PropertyGroup > ( ) ) ;
m_propertyLayout . m_propertyGroups . back ( ) - > m_name = group . m_name ;
m_propertyLayout . m_propertyGroups . back ( ) - > m_displayName = group . m_displayName ;
m_propertyLayout . m_propertyGroups . back ( ) - > m_description = group . m_description ;
propertyGroup = m_propertyLayout . m_propertyGroups . back ( ) . get ( ) ;
}
PropertyDefinition * newProperty = propertyGroup - > AddProperty ( propertyDefinition . GetName ( ) ) ;
* newProperty = propertyDefinition ;
}
}
}
m_propertyLayout . m_groupsOld . clear ( ) ;
m_propertyLayout . m_propertiesOld . clear ( ) ;
return true ;
}
void MaterialTypeSourceData : : ResolveUvEnums ( )
{
AZStd : : vector < AZStd : : string > enumValues ;
@ -206,26 +483,26 @@ namespace AZ
enumValues . push_back ( uvNamePair . second ) ;
}
for ( auto & group : m_propertyLayout . m_properties )
{
for ( PropertyDefinition & property : group . second )
EnumerateProperties ( [ & enumValues ] ( const AZStd : : string & , const MaterialTypeSourceData : : PropertyDefinition * property )
{
if ( property . m_dataType = = AZ : : RPI : : MaterialPropertyDataType : : Enum & & property . m_enumIsUv )
if ( property - > m_dataType = = AZ : : RPI : : MaterialPropertyDataType : : Enum & & property - > m_enumIsUv )
{
property . m_enumValues = enumValues ;
}
}
// const_cast is safe because this is internal to the MaterialTypeSourceData. It isn't worth complicating things
// by adding another version of EnumerateProperties.
const_cast < MaterialTypeSourceData : : PropertyDefinition * > ( property ) - > m_enumValues = enumValues ;
}
return true ;
} ) ;
}
AZStd : : vector < MaterialTypeSourceData : : GroupDefinition > MaterialTypeSourceData : : Get GroupDefinitionsInDisplayOrder( ) const
AZStd : : vector < MaterialTypeSourceData : : GroupDefinition > MaterialTypeSourceData : : Get OldFormat GroupDefinitionsInDisplayOrder( ) const
{
AZStd : : vector < MaterialTypeSourceData : : GroupDefinition > groupDefinitions ;
groupDefinitions . reserve ( m_propertyLayout . m_properties . size ( ) ) ;
groupDefinitions . reserve ( m_propertyLayout . m_properties Old . size ( ) ) ;
// Some groups are defined explicitly in the .materialtype file's "groups" section. This is the primary way groups are sorted in the UI.
AZStd : : unordered_set < AZStd : : string > foundGroups ;
for ( const auto & groupDefinition : m_propertyLayout . m_groups )
for ( const auto & groupDefinition : m_propertyLayout . m_groups Old )
{
if ( foundGroups . insert ( groupDefinition . m_name ) . second )
{
@ -238,7 +515,7 @@ namespace AZ
}
// Some groups are defined implicitly, in the "properties" section where a group name is used but not explicitly defined in the "groups" section.
for ( const auto & propertyListPair : m_propertyLayout . m_properties )
for ( const auto & propertyListPair : m_propertyLayout . m_properties Old )
{
const AZStd : : string & groupName = propertyListPair . first ;
if ( foundGroups . insert ( groupName ) . second )
@ -252,54 +529,183 @@ namespace AZ
return groupDefinitions ;
}
void MaterialTypeSourceData : : EnumerateProperties ( const EnumeratePropertiesCallback & callback ) const
bool MaterialTypeSourceData : : BuildPropertyList (
const AZStd : : string & materialTypeSourceFilePath ,
MaterialTypeAssetCreator & materialTypeAssetCreator ,
AZStd : : vector < AZStd : : string > & propertyNameContext ,
const MaterialTypeSourceData : : PropertyGroup * propertyGroup ) const
{
if ( ! callback )
for ( const AZStd : : unique_ptr < PropertyDefinition > & property : propertyGroup - > m_properties )
{
// Register the property...
MaterialPropertyId propertyId { propertyNameContext , property - > GetName ( ) } ;
if ( ! propertyId . IsValid ( ) )
{
return ;
// MaterialPropertyId reports an error message
return false ;
}
for ( const auto & propertyListPair : m_propertyLayout . m_properties )
auto propertyGroupIter = AZStd : : find_if ( propertyGroup - > GetPropertyGroups ( ) . begin ( ) , propertyGroup - > GetPropertyGroups ( ) . end ( ) ,
[ & property ] ( const AZStd : : unique_ptr < PropertyGroup > & existingPropertyGroup )
{
const AZStd : : string & groupName = propertyListPair . first ;
const auto & propertyList = propertyListPair . second ;
for ( const auto & propertyDefinition : propertyList )
return existingPropertyGroup - > GetName ( ) = = property - > GetName ( ) ;
} ) ;
if ( propertyGroupIter ! = propertyGroup - > GetPropertyGroups ( ) . end ( ) )
{
AZ_Error ( " Material source data " , false , " Material property '%s' collides with a PropertyGroup with the same ID. " , propertyId . GetCStr ( ) ) ;
return false ;
}
materialTypeAssetCreator . BeginMaterialProperty ( propertyId , property - > m_dataType ) ;
if ( property - > m_dataType = = MaterialPropertyDataType : : Enum )
{
materialTypeAssetCreator . SetMaterialPropertyEnumNames ( property - > m_enumValues ) ;
}
for ( auto & output : property - > m_outputConnections )
{
switch ( output . m_type )
{
case MaterialPropertyOutputType : : ShaderInput :
{
materialTypeAssetCreator . ConnectMaterialPropertyToShaderInput ( Name { output . m_fieldName } ) ;
break ;
}
case MaterialPropertyOutputType : : ShaderOption :
{
if ( output . m_shaderIndex > = 0 )
{
const AZStd : : string & propertyName = propertyDefinition . m_name ;
if ( ! callback ( groupName , propertyName , propertyDefinition ) )
materialTypeAssetCreator . ConnectMaterialPropertyToShaderOption ( Name { output . m_fieldName } , output . m_shaderIndex ) ;
}
else
{
return ;
materialTypeAssetCreator . ConnectMaterialPropertyToShaderOptions ( Name { output . m_fieldName } ) ;
}
break ;
}
case MaterialPropertyOutputType : : Invalid :
// Don't add any output mappings, this is the case when material functors are expected to process the property
break ;
default :
AZ_Assert ( false , " Unsupported MaterialPropertyOutputType " ) ;
return false ;
}
}
void MaterialTypeSourceData : : EnumeratePropertiesInDisplayOrder ( const EnumeratePropertiesCallback & callback ) const
materialTypeAssetCreator . EndMaterialProperty ( ) ;
// Parse and set the property's value...
if ( ! property - > m_value . IsValid ( ) )
{
AZ_Warning ( " Material source data " , false , " Source data for material property value is invalid. " ) ;
}
else
{
switch ( property - > m_dataType )
{
case MaterialPropertyDataType : : Image :
{
Data : : Asset < ImageAsset > imageAsset ;
MaterialUtils : : GetImageAssetResult result = MaterialUtils : : GetImageAssetReference (
imageAsset , materialTypeSourceFilePath , property - > m_value . GetValue < AZStd : : string > ( ) ) ;
if ( result = = MaterialUtils : : GetImageAssetResult : : Missing )
{
if ( ! callback )
materialTypeAssetCreator . ReportError (
" Material property '%s': Could not find the image '%s' " , propertyId . GetCStr ( ) ,
property - > m_value . GetValue < AZStd : : string > ( ) . data ( ) ) ;
}
else
{
materialTypeAssetCreator . SetPropertyValue ( propertyId , imageAsset ) ;
}
}
break ;
case MaterialPropertyDataType : : Enum :
{
MaterialPropertyIndex propertyIndex = materialTypeAssetCreator . GetMaterialPropertiesLayout ( ) - > FindPropertyIndex ( propertyId ) ;
const MaterialPropertyDescriptor * propertyDescriptor = materialTypeAssetCreator . GetMaterialPropertiesLayout ( ) - > GetPropertyDescriptor ( propertyIndex ) ;
AZ : : Name enumName = AZ : : Name ( property - > m_value . GetValue < AZStd : : string > ( ) ) ;
uint32_t enumValue = propertyDescriptor - > GetEnumValue ( enumName ) ;
if ( enumValue = = MaterialPropertyDescriptor : : InvalidEnumValue )
{
materialTypeAssetCreator . ReportError ( " Enum value '%s' couldn't be found in the 'enumValues' list " , enumName . GetCStr ( ) ) ;
}
else
{
materialTypeAssetCreator . SetPropertyValue ( propertyId , enumValue ) ;
}
}
break ;
default :
materialTypeAssetCreator . SetPropertyValue ( propertyId , property - > m_value ) ;
break ;
}
}
}
for ( const AZStd : : unique_ptr < PropertyGroup > & propertySubset : propertyGroup - > m_propertyGroups )
{
propertyNameContext . push_back ( propertySubset - > m_name ) ;
bool success = BuildPropertyList (
materialTypeSourceFilePath ,
materialTypeAssetCreator ,
propertyNameContext ,
propertySubset . get ( ) ) ;
propertyNameContext . pop_back ( ) ;
if ( ! success )
{
return ;
return false ;
}
}
for ( const auto & groupDefinition : GetGroupDefinitionsInDisplayOrder ( ) )
// We cannot create the MaterialFunctor until after all the properties are added because
// CreateFunctor() may need to look up properties in the MaterialPropertiesLayout
for ( auto & functorData : propertyGroup - > m_materialFunctorSourceData )
{
const AZStd : : string & groupName = groupDefinition . m_name ;
const auto propertyListItr = m_propertyLayout . m_properties . find ( groupName ) ;
if ( propertyListItr ! = m_propertyLayout . m_properties . end ( ) )
MaterialFunctorSourceData : : FunctorResult result = functorData - > CreateFunctor (
MaterialFunctorSourceData : : RuntimeContext (
materialTypeSourceFilePath ,
materialTypeAssetCreator . GetMaterialPropertiesLayout ( ) ,
materialTypeAssetCreator . GetMaterialShaderResourceGroupLayout ( ) ,
materialTypeAssetCreator . GetShaderCollection ( )
)
) ;
if ( result . IsSuccess ( ) )
{
const auto & propertyList = propertyListItr - > second ;
for ( const auto & propertyDefinition : propertyList )
Ptr < MaterialFunctor > & functor = result . GetValue ( ) ;
if ( functor ! = nullptr )
{
const AZStd : : string & propertyName = propertyDefinition . m_name ;
if ( ! callback ( groupName , propertyName , propertyDefinition ) )
materialTypeAssetCreator . AddMaterialFunctor ( functor ) ;
for ( const AZ : : Name & optionName : functorData - > GetActualSourceData ( ) - > GetShaderOptionDependencies ( ) )
{
return ;
materialTypeAssetCreator . ClaimShaderOptionOwnership ( Name { optionName . GetCStr ( ) } ) ;
}
}
}
else
{
materialTypeAssetCreator . ReportError ( " Failed to create MaterialFunctor " ) ;
return false ;
}
}
return true ;
}
Outcome < Data : : Asset < MaterialTypeAsset > > MaterialTypeSourceData : : CreateMaterialTypeAsset ( Data : : AssetId assetId , AZStd : : string_view materialTypeSourceFilePath , bool elevateWarnings ) const
{
MaterialTypeAssetCreator materialTypeAssetCreator ;
@ -389,110 +795,18 @@ namespace AZ
}
}
for ( auto & groupIter : m_propertyLayout . m_properties )
{
const AZStd : : string & groupName = groupIter . first ;
for ( const PropertyDefinition & property : groupIter . second )
{
// Register the property...
MaterialPropertyId propertyId { groupName , property . m_name } ;
if ( ! propertyId . IsValid ( ) )
{
materialTypeAssetCreator . ReportWarning ( " Cannot create material property with invalid ID '%s'. " , propertyId . GetCStr ( ) ) ;
continue ;
}
materialTypeAssetCreator . BeginMaterialProperty ( propertyId , property . m_dataType ) ;
if ( property . m_dataType = = MaterialPropertyDataType : : Enum )
for ( const AZStd : : unique_ptr < PropertyGroup > & propertyGroup : m_propertyLayout . m_propertyGroups )
{
materialTypeAssetCreator . SetMaterialPropertyEnumNames ( property . m_enumValues ) ;
}
AZStd : : vector < AZStd : : string > propertyNameContext ;
propertyNameContext . push_back ( propertyGroup - > m_name ) ;
bool success = BuildPropertyList ( materialTypeSourceFilePath , materialTypeAssetCreator , propertyNameContext , propertyGroup . get ( ) ) ;
for ( auto & output : property . m_outputConnections )
{
switch ( output . m_type )
{
case MaterialPropertyOutputType : : ShaderInput :
materialTypeAssetCreator . ConnectMaterialPropertyToShaderInput ( Name { output . m_fieldName . data ( ) } ) ;
break ;
case MaterialPropertyOutputType : : ShaderOption :
if ( output . m_shaderIndex > = 0 )
{
materialTypeAssetCreator . ConnectMaterialPropertyToShaderOption ( Name { output . m_fieldName . data ( ) } , output . m_shaderIndex ) ;
}
else
if ( ! success )
{
materialTypeAssetCreator . ConnectMaterialPropertyToShaderOptions ( Name { output . m_fieldName . data ( ) } ) ;
}
break ;
case MaterialPropertyOutputType : : Invalid :
// Don't add any output mappings, this is the case when material functors are expected to process the property
break ;
default :
AZ_Assert ( false , " Unsupported MaterialPropertyOutputType " ) ;
return Failure ( ) ;
}
}
materialTypeAssetCreator . EndMaterialProperty ( ) ;
// Parse and set the property's value...
if ( ! property . m_value . IsValid ( ) )
{
AZ_Warning ( " Material source data " , false , " Source data for material property value is invalid. " ) ;
}
else
{
switch ( property . m_dataType )
{
case MaterialPropertyDataType : : Image :
{
Data : : Asset < ImageAsset > imageAsset ;
MaterialUtils : : GetImageAssetResult result = MaterialUtils : : GetImageAssetReference (
imageAsset , materialTypeSourceFilePath , property . m_value . GetValue < AZStd : : string > ( ) ) ;
if ( result = = MaterialUtils : : GetImageAssetResult : : Missing )
{
materialTypeAssetCreator . ReportError (
" Material property '%s': Could not find the image '%s' " , propertyId . GetCStr ( ) ,
property . m_value . GetValue < AZStd : : string > ( ) . data ( ) ) ;
}
else
{
materialTypeAssetCreator . SetPropertyValue ( propertyId , imageAsset ) ;
}
}
break ;
case MaterialPropertyDataType : : Enum :
{
MaterialPropertyIndex propertyIndex = materialTypeAssetCreator . GetMaterialPropertiesLayout ( ) - > FindPropertyIndex ( propertyId ) ;
const MaterialPropertyDescriptor * propertyDescriptor = materialTypeAssetCreator . GetMaterialPropertiesLayout ( ) - > GetPropertyDescriptor ( propertyIndex ) ;
AZ : : Name enumName = AZ : : Name ( property . m_value . GetValue < AZStd : : string > ( ) ) ;
uint32_t enumValue = propertyDescriptor ? propertyDescriptor - > GetEnumValue ( enumName ) : MaterialPropertyDescriptor : : InvalidEnumValue ;
if ( enumValue = = MaterialPropertyDescriptor : : InvalidEnumValue )
{
materialTypeAssetCreator . ReportError ( " Enum value '%s' couldn't be found in the 'enumValues' list " , enumName . GetCStr ( ) ) ;
}
else
{
materialTypeAssetCreator . SetPropertyValue ( propertyId , enumValue ) ;
}
}
break ;
default :
materialTypeAssetCreator . SetPropertyValue ( propertyId , property . m_value ) ;
break ;
}
}
}
}
// We cannot create the MaterialFunctor until after all the properties are added because
// CreateFunctor() may need to look up properties in the MaterialPropertiesLayout
for ( auto & functorData : m_materialFunctorSourceData )