using System; using System.Collections; using System.Collections.Generic; using UnityEngine; namespace EPOOutline { public class SerializedPassInfoAttribute : Attribute { public readonly string Title; public readonly string ShadersFolder; public SerializedPassInfoAttribute(string title, string shadersFolder) { Title = title; ShadersFolder = shadersFolder; } } [System.Serializable] public class SerializedPass : ISerializationCallbackReceiver { public enum PropertyType { Color = 0, Vector = 1, Float = 2, Range = 3, 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; public Shader Shader { get { return 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; public 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; } } public bool HasProperty(string name) { return propertiesByName.ContainsKey(name); } public bool HasProperty(int hash) { return propertiesById.ContainsKey(hash); } 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; else { Debug.LogError("The property " + name + " is not a vector property"); return Vector4.zero; } } 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; else { Debug.LogError("The property " + hash + " is not a vector property"); return Vector4.zero; } } 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; } 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; } 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; else { Debug.LogError("The property " + name + " is not a float property"); return 0.0f; } } 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; else { Debug.LogError("The property " + hash + " is not a float property"); return 0.0f; } } 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; } 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; } 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; } } 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; } 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; } 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); } } } }