using System; using System.Linq; using UnityEngine; using UnityEngine.Rendering.HighDefinition; using UnityEditor.Rendering; namespace UnityEditor.Rendering.HighDefinition { /// /// Base implementation of a material GUI block to be disabled in the material inspector. /// public abstract class MaterialUIBlock { /// The current material editor. protected MaterialEditor materialEditor; /// The list of selected materials to edit. protected Material[] materials; /// The list of available properties in the selected materials. protected MaterialProperty[] properties; /// Parent of the UI block. protected MaterialUIBlockList parent; /// Bit index used to store a foldout state in the editor preferences. [Flags] public enum ExpandableBit : uint { // Standard ///Reserved Base Bit Base = 1 << 0, ///Reserved Input Bit Input = 1 << 1, ///Reserved Tessellation Bit Tessellation = 1 << 2, ///Reserved Transparency Bit Transparency = 1 << 3, // Free slot 4 ///Reserved Detail Bit Detail = 1 << 5, ///Reserved Emissive Bit Emissive = 1 << 6, ///Reserved Advanced Bit Advance = 1 << 7, ///Reserved Other Bit Other = 1 << 8, ///Reserved ShaderGraph Bit ShaderGraph = 1 << 9, // Free slot 10 // Layered ///Reserved MainLayer Bit MainLayer = 1 << 11, ///Reserved Layer1 Bit Layer1 = 1 << 12, ///Reserved Layer2 Bit Layer2 = 1 << 13, ///Reserved Layer3 Bit Layer3 = 1 << 14, ///Reserved LayeringOptionMain Bit LayeringOptionMain = 1 << 15, ///Reserved ShowLayer1 Bit ShowLayer1 = 1 << 16, ///Reserved ShowLayer2 Bit ShowLayer2 = 1 << 17, ///Reserved ShowLayer3 Bit ShowLayer3 = 1 << 18, ///Reserved MaterialReferences Bit MaterialReferences = 1 << 19, ///Reserved MainInput Bit MainInput = 1 << 20, ///Reserved Layer1Input Bit Layer1Input = 1 << 21, ///Reserved Layer2Input Bit Layer2Input = 1 << 22, ///Reserved Layer3Input Bit Layer3Input = 1 << 23, ///Reserved MainDetail Bit MainDetail = 1 << 24, ///Reserved Layer1Detail Bit Layer1Detail = 1 << 25, ///Reserved Layer2Detail Bit Layer2Detail = 1 << 26, ///Reserved Layer3Detail Bit Layer3Detail = 1 << 27, ///Reserved LayeringOption1 Bit LayeringOption1 = 1 << 28, ///Reserved LayeringOption2 Bit LayeringOption2 = 1 << 29, ///Reserved LayeringOption3 Bit LayeringOption3 = 1 << 30, // Note that we use the bit reserved for layered material UI in this enum, we can do this // because this enum will be used for ShaderGraph custom UI and we can't author layered // shader in shadergraph. ///User Bit 0 User0 = 1 << 11, ///User Bit 1 User1 = 1 << 12, ///User Bit 2 User2 = 1 << 13, ///User Bit 3 User3 = 1 << 14, ///User Bit 4 User4 = 1 << 15, ///User Bit 5 User5 = 1 << 16, ///User Bit 6 User6 = 1 << 17, ///User Bit 7 User7 = 1 << 18, ///User Bit 8 User8 = 1 << 19, ///User Bit 9 User9 = 1 << 20, ///User Bit 10 User10 = 1 << 21, ///User Bit 11 User11 = 1 << 22, ///User Bit 12 User12 = 1 << 23, ///User Bit 13 User13 = 1 << 24, ///User Bit 14 User14 = 1 << 25, ///User Bit 15 User15 = 1 << 26, ///User Bit 16 User16 = 1 << 27, ///User Bit 17 User17 = 1 << 28, ///User Bit 18 User18 = 1 << 29, ///User Bit 19 User19 = 1 << 30, } internal void Initialize(MaterialEditor materialEditor, MaterialProperty[] properties, MaterialUIBlockList parent) { this.materialEditor = materialEditor; this.parent = parent; materials = materialEditor.targets.Select(target => target as Material).ToArray(); // We should always register the key used to keep collapsable state materialEditor.InitExpandableState(); } internal void UpdateMaterialProperties(MaterialProperty[] properties) { this.properties = properties; LoadMaterialProperties(); } /// /// Find a material property in the list of available properties. /// /// Name of the property. /// Specifies whether the property is mandatory for your Inspector. /// Returns the material property if it exists. Returns null otherwise. protected MaterialProperty FindProperty(string propertyName, bool isMandatory = false) { // ShaderGUI.FindProperty is a protected member of ShaderGUI so we can't call it here: // return ShaderGUI.FindProperty(propertyName, properties, isMandatory); // TODO: move this to a map since this is done at every editor frame foreach (var prop in properties) if (prop.name == propertyName) return prop; if (isMandatory) throw new ArgumentException("Could not find MaterialProperty: '" + propertyName + "', Num properties: " + properties.Length); return null; } /// /// Find a material property with layering option /// /// Name of the property. /// Number of layers of the shader. /// Specifies whether the property is mandatory for your Inspector. /// Returns the material property if it exists. Returns null otherwise. protected MaterialProperty[] FindPropertyLayered(string propertyName, int layerCount, bool isMandatory = false) { MaterialProperty[] properties = new MaterialProperty[layerCount]; // If the layerCount is 1, then it means that the property we're fetching is not from a layered material // thus it doesn't have a prefix string[] prefixes = (layerCount > 1) ? new[] {"0", "1", "2", "3"} : new[] {""}; for (int i = 0; i < layerCount; i++) { properties[i] = FindProperty(string.Format("{0}{1}", propertyName, prefixes[i]), isMandatory); } return properties; } /// /// Loads the material properties for the block. /// public abstract void LoadMaterialProperties(); /// /// Renders the properties in the block. /// public abstract void OnGUI(); } }