using System.Collections.Generic; using UnityEngine; namespace EPOOutline { /// /// Holds an information about how pass should be rendered. /// [System.Serializable] public class SerializedPass : ISerializationCallbackReceiver { /// /// The type of shader property. /// public enum PropertyType { /// /// Color. /// Color = 0, /// /// Vector. /// Vector = 1, /// /// Float. /// Float = 2, /// /// Float but limited with a range. /// Range = 3, /// /// Texture. /// TexEnv = 4 } [System.Serializable] private class SerializedPropertyKeyValuePair { [SerializeField] public string PropertyName; [SerializeField] public SerializedPassProperty Property; } [System.Serializable] private class SerializedPassProperty { #pragma warning disable CS0649 [SerializeField] public Color ColorValue; [SerializeField] public float FloatValue; [SerializeField] public Vector4 VectorValue; [SerializeField] public PropertyType PropertyType; #pragma warning restore CS0649 } [SerializeField] private Shader shader; /// /// The that will be used for rendering the pass. /// public Shader Shader { get => shader; set { propertiesIsDirty = true; shader = value; } } [SerializeField] private List serializedProperties = new List(); private Dictionary propertiesById = new Dictionary(); private Dictionary propertiesByName = new Dictionary(); private Material material; private bool propertiesIsDirty = false; internal Material Material { get { if (shader == null) return null; if (material == null || material.shader != shader) { if (material != null) GameObject.DestroyImmediate(material); material = new Material(shader); } if (!propertiesIsDirty) return material; foreach (var property in propertiesById) { switch (property.Value.PropertyType) { case PropertyType.Color: material.SetColor(property.Key, property.Value.ColorValue); break; case PropertyType.Vector: material.SetVector(property.Key, property.Value.VectorValue); break; case PropertyType.Float: material.SetFloat(property.Key, property.Value.FloatValue); break; case PropertyType.Range: material.SetFloat(property.Key, property.Value.FloatValue); break; case PropertyType.TexEnv: break; } } propertiesIsDirty = false; return material; } } /// /// Checks if the pass has the property. /// /// The property name to check /// Returns true if it has the property. public bool HasProperty(string name) { return propertiesByName.ContainsKey(name); } /// /// Checks if the pass has the property. /// /// The property hash to check /// Returns true if it has the property. public bool HasProperty(int hash) { return propertiesById.ContainsKey(hash); } /// /// Returns a vector from the pass. /// /// The name of the vector. /// The vector result. public Vector4 GetVector(string name) { SerializedPassProperty result = null; if (!propertiesByName.TryGetValue(name, out result)) { Debug.LogError("The property " + name + " doesn't exist"); return Vector4.zero; } if (result.PropertyType == PropertyType.Vector) return result.VectorValue; Debug.LogError("The property " + name + " is not a vector property"); return Vector4.zero; } /// /// Returns a vector from the pass. /// /// The hash of the vector. /// The vector result. public Vector4 GetVector(int hash) { SerializedPassProperty result = null; if (!propertiesById.TryGetValue(hash, out result)) { Debug.LogError("The property " + hash + " doesn't exist"); return Vector4.zero; } if (result.PropertyType == PropertyType.Vector) return result.VectorValue; Debug.LogError("The property " + hash + " is not a vector property"); return Vector4.zero; } /// /// Sets vector to the pass. /// /// The name of the vector. /// The vector value to be set. public void SetVector(string name, Vector4 value) { propertiesIsDirty = true; SerializedPassProperty result = null; if (!propertiesByName.TryGetValue(name, out result)) { result = new SerializedPassProperty(); result.PropertyType = PropertyType.Vector; propertiesByName.Add(name, result); propertiesById.Add(Shader.PropertyToID(name), result); } if (result.PropertyType != PropertyType.Vector) { Debug.LogError("The property " + name + " is not a vector property"); return; } result.VectorValue = value; } /// /// Sets vector to the pass. /// /// The hash of the vector. /// The vector value to be set. public void SetVector(int hash, Vector4 value) { propertiesIsDirty = true; SerializedPassProperty result = null; if (!propertiesById.TryGetValue(hash, out result)) { Debug.LogWarning("The property " + hash + " doesn't exist. Use string overload to create one."); return; } if (result.PropertyType != PropertyType.Vector) { Debug.LogError("The property " + hash + " is not a vector property"); return; } result.VectorValue = value; } /// /// Returns a float from the pass. /// /// The name of the float. /// The float value from the pass. public float GetFloat(string name) { SerializedPassProperty result = null; if (!propertiesByName.TryGetValue(name, out result)) { Debug.LogError("The property " + name + " doesn't exist"); return 0.0f; } if (result.PropertyType == PropertyType.Float || result.PropertyType == PropertyType.Range) return result.FloatValue; Debug.LogError("The property " + name + " is not a float property"); return 0.0f; } /// /// Returns a float from the pass. /// /// The hash of the float. /// The float value from the pass. public float GetFloat(int hash) { SerializedPassProperty result = null; if (!propertiesById.TryGetValue(hash, out result)) { Debug.LogError("The property " + hash + " is doesn't exist"); return 0.0f; } if (result.PropertyType == PropertyType.Float || result.PropertyType == PropertyType.Range) return result.FloatValue; Debug.LogError("The property " + hash + " is not a float property"); return 0.0f; } /// /// Sets a float to the pass. /// /// The name of the float. /// The value to be set. public void SetFloat(string name, float value) { propertiesIsDirty = true; SerializedPassProperty result = null; if (!propertiesByName.TryGetValue(name, out result)) { result = new SerializedPassProperty(); result.PropertyType = PropertyType.Float; propertiesByName.Add(name, result); propertiesById.Add(Shader.PropertyToID(name), result); } if (result.PropertyType != PropertyType.Float && result.PropertyType != PropertyType.Range) { Debug.LogError("The property " + name + " is not a float property"); return; } result.FloatValue = value; } /// /// Sets a float to the pass. /// /// The hash of the float. /// The value to be set. public void SetFloat(int hash, float value) { propertiesIsDirty = true; SerializedPassProperty result = null; if (!propertiesById.TryGetValue(hash, out result)) { Debug.LogError("The property " + hash + " doesn't exist. Use string overload to create one."); return; } if (result.PropertyType != PropertyType.Float) { Debug.LogError("The property " + hash + " is not a float property"); return; } result.FloatValue = value; } /// /// Returns a color from the pass. /// /// The name of the color. /// The color value from the pass. public Color GetColor(string name) { SerializedPassProperty result = null; if (!propertiesByName.TryGetValue(name, out result)) { Debug.LogError("The property " + name + " doesn't exist"); return Color.black; } if (result.PropertyType == PropertyType.Color) return result.ColorValue; else { Debug.LogError("The property " + name + " is not a color property"); return Color.black; } } /// /// Returns a color from the pass. /// /// The hash of the color. /// The color value from the pass. public Color GetColor(int hash) { SerializedPassProperty result = null; if (!propertiesById.TryGetValue(hash, out result)) { Debug.LogError("The property " + hash + " doesn't exist"); return Color.black; } if (result.PropertyType == PropertyType.Color) return result.ColorValue; else return Color.black; } /// /// Sets a color to the pass. /// /// The name of the color /// The value to be set. public void SetColor(string name, Color value) { propertiesIsDirty = true; SerializedPassProperty result = null; if (!propertiesByName.TryGetValue(name, out result)) { result = new SerializedPassProperty(); result.PropertyType = PropertyType.Color; propertiesByName.Add(name, result); propertiesById.Add(Shader.PropertyToID(name), result); } if (result.PropertyType != PropertyType.Color) { Debug.LogError("The property " + name + " is not a color property."); return; } result.ColorValue = value; } /// /// Sets a color to the pass. /// /// The hash of the color /// The value to be set. public void SetColor(int hash, Color value) { propertiesIsDirty = true; SerializedPassProperty result = null; if (!propertiesById.TryGetValue(hash, out result)) { Debug.LogError("The property " + hash + " doesn't exist. Use string overload to create one."); return; } if (result.PropertyType != PropertyType.Color) { Debug.LogError("The property " + hash + " is not a color property"); return; } result.ColorValue = value; } public void OnBeforeSerialize() { serializedProperties.Clear(); foreach (var property in propertiesByName) { var pair = new SerializedPropertyKeyValuePair(); pair.Property = property.Value; pair.PropertyName = property.Key; serializedProperties.Add(pair); } } public void OnAfterDeserialize() { propertiesIsDirty = true; propertiesById.Clear(); propertiesByName.Clear(); foreach (var serialized in serializedProperties) { if (propertiesByName.ContainsKey(serialized.PropertyName)) continue; propertiesById.Add(Shader.PropertyToID(serialized.PropertyName), serialized.Property); propertiesByName.Add(serialized.PropertyName, serialized.Property); } } } }