@ -3,11 +3,19 @@ using System.Collections.Generic;
using System.Runtime.Serialization ;
using UniLinq ;
using UnityEngine ;
using UnityEngine.Rendering ;
namespace ConformalDecals.MaterialModifiers {
public class MaterialPropertyCollection : ScriptableObject , ISerializationCallbackReceiver {
private static readonly int OpacityId = Shader . PropertyToID ( "_DecalOpacity" ) ;
private static readonly int CutoffId = Shader . PropertyToID ( "_Cutoff" ) ;
[SerializeField] private Shader _shader ;
[SerializeField] private MaterialTextureProperty _mainTexture ;
[SerializeField] private string [ ] _serializedNames ;
[SerializeField] private MaterialProperty [ ] _serializedProperties ;
private Dictionary < string , MaterialProperty > _materialProperties ;
private Material _decalMaterial ;
private Material _previewMaterial ;
public Shader DecalShader = > _shader ;
@ -16,6 +24,8 @@ namespace ConformalDecals.MaterialModifiers {
if ( _decalMaterial = = null ) {
_decalMaterial = new Material ( _shader ) ;
UpdateMaterial ( _decalMaterial ) ;
_previewMaterial . SetInt ( DecalPropertyIDs . _Cull , ( int ) CullMode . Off ) ;
}
return _decalMaterial ;
@ -27,7 +37,9 @@ namespace ConformalDecals.MaterialModifiers {
if ( _previewMaterial = = null ) {
_previewMaterial = new Material ( _shader ) ;
UpdateMaterial ( _previewMaterial ) ;
_previewMaterial . EnableKeyword ( "DECAL_PREVIEW" ) ;
_previewMaterial . SetInt ( DecalPropertyIDs . _Cull , ( int ) CullMode . Back ) ;
}
return _previewMaterial ;
@ -50,41 +62,31 @@ namespace ConformalDecals.MaterialModifiers {
Debug . Log ( "No main texture specified! returning 1 for aspect ratio" ) ;
return 1 ;
}
return MainTexture . AspectRatio ;
}
}
[SerializeField] private string [ ] _serializedIDs ;
[SerializeField] private MaterialProperty [ ] _serializedProperties ;
[SerializeField] private Shader _shader ;
[SerializeField] private MaterialTextureProperty _mainTexture ;
private Dictionary < string , MaterialProperty > _materialProperties ;
private Material _decalMaterial ;
private Material _previewMaterial ;
public void OnBeforeSerialize ( ) {
Debug . Log ( $"Serializing MaterialPropertyCollection {this.GetInstanceID()}" ) ;
if ( _materialProperties = = null ) throw new SerializationException ( "Tried to serialize an unini nit alized MaterialPropertyCollection") ;
if ( _materialProperties = = null ) throw new SerializationException ( "Tried to serialize an uninitialized MaterialPropertyCollection" ) ;
_serialized ID s = _materialProperties . Keys . ToArray ( ) ;
_serializedNames = _materialProperties . Keys . ToArray ( ) ;
_serializedProperties = _materialProperties . Values . ToArray ( ) ;
}
public void OnAfterDeserialize ( ) {
Debug . Log ( $"Deserializing MaterialPropertyCollection {this.GetInstanceID()}" ) ;
if ( _serialized ID s = = null ) throw new SerializationException ( "ID array is null" ) ;
if ( _serializedNames = = null ) throw new SerializationException ( "ID array is null" ) ;
if ( _serializedProperties = = null ) throw new SerializationException ( "Property array is null" ) ;
if ( _serializedProperties . Length ! = _serialized ID s. Length ) throw new SerializationException ( "Material property arrays are different lengths." ) ;
if ( _serializedProperties . Length ! = _serialized Name s. Length ) throw new SerializationException ( "Material property arrays are different lengths." ) ;
_materialProperties ? ? = new Dictionary < string , MaterialProperty > ( ) ;
for ( var i = 0 ; i < _serialized ID s. Length ; i + + ) {
for ( var i = 0 ; i < _serialized Name s. Length ; i + + ) {
var property = MaterialProperty . Instantiate ( _serializedProperties [ i ] ) ;
Debug . Log ( $"insantiating {property.GetType().Name} {property.GetInstanceID()}" ) ;
_materialProperties . Add ( _serialized ID s[ i ] , property ) ;
_materialProperties . Add ( _serialized Name s[ i ] , property ) ;
if ( property is MaterialTextureProperty textureProperty ) {
_mainTexture = textureProperty ;
@ -98,7 +100,7 @@ namespace ConformalDecals.MaterialModifiers {
}
public void AddProperty ( MaterialProperty property ) {
if ( property = = null ) throw new ArgumentNullException ( "Tried to add a null property" ) ;
if ( property = = null ) throw new ArgumentNullException ( nameof ( property ) ) ;
_materialProperties . Add ( property . name , property ) ;
@ -107,16 +109,61 @@ namespace ConformalDecals.MaterialModifiers {
}
}
public T AddProperty < T > ( string propertyName ) where T : MaterialProperty {
if ( _materialProperties . ContainsKey ( propertyName ) ) throw new ArgumentException ( "property with that name already exists!" ) ;
var newProperty = MaterialProperty . CreateInstance < T > ( ) ;
newProperty . PropertyName = propertyName ;
_materialProperties . Add ( propertyName , newProperty ) ;
return newProperty ;
}
public T GetProperty < T > ( string propertyName ) where T : MaterialProperty {
if ( _materialProperties . ContainsKey ( propertyName ) & & _materialProperties [ propertyName ] is T property ) {
return property ;
}
else {
return null ;
}
}
public T AddOrGetProperty < T > ( string propertyName ) where T : MaterialProperty {
if ( _materialProperties . ContainsKey ( propertyName ) & & _materialProperties [ propertyName ] is T property ) {
return property ;
}
else {
return AddProperty < T > ( propertyName ) ;
}
}
public MaterialTextureProperty AddTextureProperty ( string propertyName , bool isMain = false ) {
var newProperty = AddProperty < MaterialTextureProperty > ( propertyName ) ;
if ( isMain ) MainTexture = newProperty ;
return newProperty ;
}
public MaterialTextureProperty GetTextureProperty ( string propertyName ) {
return GetProperty < MaterialTextureProperty > ( propertyName ) ;
}
public MaterialTextureProperty AddOrGetTextureProperty ( string propertyName , bool isMain = false ) {
if ( _materialProperties . ContainsKey ( propertyName ) & & _materialProperties [ propertyName ] is MaterialTextureProperty property ) {
return property ;
}
else {
return AddTextureProperty ( propertyName , isMain ) ;
}
}
public void ParseProperty < T > ( ConfigNode node ) where T : MaterialProperty {
var name = node . GetValue ( "name" ) ;
if ( string . IsNullOrEmpty ( name ) ) throw new ArgumentException ( "node has no name" ) ;
var propertyN ame = node . GetValue ( "name" ) ;
if ( string . IsNullOrEmpty ( propertyN ame) ) throw new ArgumentException ( "node has no name" ) ;
Debug . Log ( $"Parsing material property {name}" ) ;
Debug . Log ( $"Parsing material property { propertyN ame}") ;
T newProperty ;
if ( _materialProperties . ContainsKey ( name ) ) {
if ( _materialProperties [ name ] is T property ) {
if ( _materialProperties . ContainsKey ( propertyN ame) ) {
if ( _materialProperties [ propertyN ame] is T property ) {
newProperty = property ;
property . ParseNode ( node ) ;
}
@ -128,7 +175,7 @@ namespace ConformalDecals.MaterialModifiers {
newProperty = MaterialProperty . CreateInstance < T > ( ) ;
Debug . Log ( $"Adding new material property of type {newProperty.GetType().Name} {newProperty.GetInstanceID()}" ) ;
newProperty . ParseNode ( node ) ;
_materialProperties . Add ( n ame, newProperty ) ;
_materialProperties . Add ( propertyN ame, newProperty ) ;
}
if ( newProperty is MaterialTextureProperty textureProperty & & textureProperty . isMain ) {
@ -170,11 +217,13 @@ namespace ConformalDecals.MaterialModifiers {
}
public void SetOpacity ( float opacity ) {
DecalMaterial . SetFloat ( OpacityId , opacity ) ;
DecalMaterial . SetFloat ( DecalPropertyIDs . _DecalOpacity , opacity ) ;
PreviewMaterial . SetFloat ( DecalPropertyIDs . _DecalOpacity , opacity ) ;
}
public void SetCutoff ( float cutoff ) {
DecalMaterial . SetFloat ( CutoffId , cutoff ) ;
DecalMaterial . SetFloat ( DecalPropertyIDs . _Cutoff , cutoff ) ;
PreviewMaterial . SetFloat ( DecalPropertyIDs . _Cutoff , cutoff ) ;
}
public void UpdateMaterials ( ) {
@ -195,8 +244,11 @@ namespace ConformalDecals.MaterialModifiers {
public void UpdateMaterial ( Material material ) {
if ( material = = null ) throw new ArgumentNullException ( nameof ( material ) ) ;
foreach ( var entry in _materialProperties ) {
Debug . Log ( $"Applying material property {entry.Key} {entry.Value.PropertyName} {entry.Value.GetInstanceID()}" ) ;
entry . Value . Modify ( material ) ;
}
}