diff --git a/Editor/Helpers/MaterialEditorHelpers.cs b/Editor/Helpers/MaterialEditorHelpers.cs index cd03aa1..4b9df8d 100644 --- a/Editor/Helpers/MaterialEditorHelpers.cs +++ b/Editor/Helpers/MaterialEditorHelpers.cs @@ -81,9 +81,9 @@ namespace Misaki.ShaderGUI /// The label of the texture property. /// The texture property to draw. /// True if the texture property is not null. Otherwise, false. - public static bool KeywordTexturePropertySingleLine(this MaterialEditor editor, GUIContent label, MaterialProperty textureProperty) + public static bool KeywordTexturePropertySingleLine(this MaterialEditor editor, GUIContent label, MaterialProperty textureProperty, string keywordName = null) { - return KeywordTexturePropertySingleLine(editor, label, textureProperty, null, null); + return KeywordTexturePropertySingleLine(editor, label, textureProperty, null, null, keywordName); } /// @@ -94,9 +94,9 @@ namespace Misaki.ShaderGUI /// The texture property to draw. /// The first extra property to draw. /// True if the texture property is not null. Otherwise, false. - public static bool KeywordTexturePropertySingleLine(this MaterialEditor editor, GUIContent label, MaterialProperty textureProperty, MaterialProperty extraProperty) + public static bool KeywordTexturePropertySingleLine(this MaterialEditor editor, GUIContent label, MaterialProperty textureProperty, MaterialProperty extraProperty, string keywordName = null) { - return KeywordTexturePropertySingleLine(editor, label, textureProperty, extraProperty, null); + return KeywordTexturePropertySingleLine(editor, label, textureProperty, extraProperty, null, keywordName); } /// @@ -108,13 +108,13 @@ namespace Misaki.ShaderGUI /// The first extra property to draw. /// The second extra property to draw. /// True if the texture property is not null. Otherwise, false. - public static bool KeywordTexturePropertySingleLine(this MaterialEditor editor, GUIContent label, MaterialProperty textureProperty, MaterialProperty extraProperty1, MaterialProperty extraProperty2) + public static bool KeywordTexturePropertySingleLine(this MaterialEditor editor, GUIContent label, MaterialProperty textureProperty, MaterialProperty extraProperty1, MaterialProperty extraProperty2, string keywordName = null) { EditorGUI.BeginChangeCheck(); editor.TexturePropertySingleLine(label, textureProperty, extraProperty1, extraProperty2); if (EditorGUI.EndChangeCheck()) { - editor.SetKeyword(textureProperty.name.ToUpper(), textureProperty.textureValue != null); + editor.SetKeyword(string.IsNullOrEmpty(keywordName) ? textureProperty.name.ToUpper() : keywordName, textureProperty.textureValue != null); } return textureProperty.textureValue != null; diff --git a/Editor/Helpers/MaterialPropertyHelpers.cs b/Editor/Helpers/MaterialPropertyHelpers.cs index 6de4f81..f7c708c 100644 --- a/Editor/Helpers/MaterialPropertyHelpers.cs +++ b/Editor/Helpers/MaterialPropertyHelpers.cs @@ -28,5 +28,28 @@ namespace Misaki.ShaderGUI throw new NotSupportedException("Property type is not supported."); } + + public static T GetEnumValue(this MaterialProperty materialProperty) where T : Enum + { +#if UNITY_6000_1_OR_NEWER + if (materialProperty.propertyType == UnityEngine.Rendering.ShaderPropertyType.Float || materialProperty.propertyType == UnityEngine.Rendering.ShaderPropertyType.Range) +#else + if (materialProperty.type == MaterialProperty.PropType.Float || materialProperty.type == MaterialProperty.PropType.Range) +#endif + { + return (T)Enum.ToObject(typeof(T), (int)materialProperty.floatValue); + } + +#if UNITY_6000_1_OR_NEWER + if (materialProperty.propertyType == UnityEngine.Rendering.ShaderPropertyType.Int) +#else + if (materialProperty.type == MaterialProperty.PropType.Int) +#endif + { + return (T)Enum.ToObject(typeof(T), materialProperty.intValue); + } + + throw new NotSupportedException("Property type is not supported."); + } } } \ No newline at end of file diff --git a/Editor/MaterialUIBlock.cs b/Editor/MaterialUIBlock.cs index 92cdeeb..7d9bb1d 100644 --- a/Editor/MaterialUIBlock.cs +++ b/Editor/MaterialUIBlock.cs @@ -8,7 +8,7 @@ namespace Misaki.ShaderGUI.Packages { public abstract class MaterialUIBlock : IMaterialUIScope where TExpandableBit : Enum, IConvertible { - private readonly MaterialPropertyContainer _propertyContainer = new(); + protected readonly MaterialPropertyContainer propertyContainer = new(); protected MaterialEditor editor; protected IMaterialUIScopeContainer owner; @@ -39,13 +39,13 @@ namespace Misaki.ShaderGUI.Packages editor = materialEditor; owner = container; - LoadMaterialProperties(_propertyContainer); + LoadMaterialProperties(propertyContainer); UpdateMaterialProperties(properties); } public void UpdateMaterialProperties(IEnumerable properties) { - _propertyContainer.ReloadProperties(properties); + propertyContainer.ReloadProperties(properties); } public void Draw() diff --git a/Editor/PropertyDrawer/EnumFlagsDrawer.cs b/Editor/PropertyDrawer/EnumFlagsDrawer.cs new file mode 100644 index 0000000..0b53c49 --- /dev/null +++ b/Editor/PropertyDrawer/EnumFlagsDrawer.cs @@ -0,0 +1,76 @@ +using System; +using System.Reflection; +using UnityEditor; +using UnityEngine; +using UnityEngine.Rendering; + +namespace Misaki.ShaderGUI +{ + public class EnumFlagsUIDrawer : MaterialPropertyDrawer + { + private readonly Type enumType; + + public EnumFlagsUIDrawer(string enumTypeName, string assemblyName) + { + enumType = Type.GetType(Assembly.CreateQualifiedName(assemblyName, enumTypeName), true); + } + + private static bool IsPropertyTypeSuitable(MaterialProperty prop) + { +#if UNITY_6000_1_OR_NEWER + return prop.propertyType == ShaderPropertyType.Float || prop.propertyType == ShaderPropertyType.Range || prop.propertyType == ShaderPropertyType.Int; +#else + return prop.type == MaterialProperty.PropType.Float || prop.type == MaterialProperty.PropType.Range || prop.type == MaterialProperty.PropType.Float; +#endif + } + + public override void OnGUI(Rect position, MaterialProperty prop, GUIContent label, MaterialEditor editor) + { + if (!IsPropertyTypeSuitable(prop)) + { + var c = EditorGUIUtility.TrTempContent("Toggle used on a non-float property: " + prop.name); + EditorGUI.LabelField(position, c, EditorStyles.helpBox); + return; + } + + MaterialEditor.BeginProperty(position, prop); + +#if UNITY_6000_1_OR_NEWER + if (prop.propertyType != ShaderPropertyType.Int) +#else + if (prop.type != MaterialProperty.PropType.Int) +#endif + { + EditorGUI.BeginChangeCheck(); + + var value = (int)prop.floatValue; + EditorGUI.showMixedValue = prop.hasMixedValue; + var enumValue = EditorGUI.EnumFlagsField(position, label, (Enum)Enum.ToObject(enumType, value)); + value = Convert.ToInt32(enumValue); + EditorGUI.showMixedValue = false; + + if (EditorGUI.EndChangeCheck()) + { + prop.floatValue = value; + } + } + else + { + EditorGUI.BeginChangeCheck(); + + var value = prop.intValue; + EditorGUI.showMixedValue = prop.hasMixedValue; + var enumValue = EditorGUI.EnumFlagsField(position, label, (Enum)Enum.ToObject(enumType, value)); + value = Convert.ToInt32(enumValue); + + EditorGUI.showMixedValue = false; + if (EditorGUI.EndChangeCheck()) + { + prop.intValue = value; + } + } + + MaterialEditor.EndProperty(); + } + } +} diff --git a/Editor/PropertyDrawer/EnumFlagsDrawer.cs.meta b/Editor/PropertyDrawer/EnumFlagsDrawer.cs.meta new file mode 100644 index 0000000..4c94482 --- /dev/null +++ b/Editor/PropertyDrawer/EnumFlagsDrawer.cs.meta @@ -0,0 +1,2 @@ +fileFormatVersion: 2 +guid: 44cf7877640af1d4795a4d087824f9f5 \ No newline at end of file diff --git a/Editor/PropertyDrawer/PopupDrawer.cs b/Editor/PropertyDrawer/PopupDrawer.cs index 4df43c1..4695ada 100644 --- a/Editor/PropertyDrawer/PopupDrawer.cs +++ b/Editor/PropertyDrawer/PopupDrawer.cs @@ -9,11 +9,11 @@ namespace Misaki.ShaderGUI { private static readonly GUIContent[] _options = { new("Disabled"), new("Enabled") }; - protected virtual void SetKeyword(MaterialProperty prop, bool on) + protected virtual void OnPropertyChange(MaterialProperty prop) { } - static bool IsPropertyTypeSuitable(MaterialProperty prop) + private static bool IsPropertyTypeSuitable(MaterialProperty prop) { #if UNITY_6000_1_OR_NEWER return prop.propertyType == ShaderPropertyType.Float || prop.propertyType == ShaderPropertyType.Range || prop.propertyType == ShaderPropertyType.Int; @@ -41,14 +41,14 @@ namespace Misaki.ShaderGUI { EditorGUI.BeginChangeCheck(); - var value = (int)Math.Abs(prop.floatValue); + var value = (int)Mathf.Abs(prop.floatValue); EditorGUI.showMixedValue = prop.hasMixedValue; value = EditorGUI.Popup(position, label, value, _options); EditorGUI.showMixedValue = false; if (EditorGUI.EndChangeCheck()) { prop.floatValue = value; - SetKeyword(prop, value != 0); + OnPropertyChange(prop); } } else @@ -62,7 +62,7 @@ namespace Misaki.ShaderGUI if (EditorGUI.EndChangeCheck()) { prop.intValue = value; - SetKeyword(prop, value != 0); + OnPropertyChange(prop); } } @@ -74,7 +74,7 @@ namespace Misaki.ShaderGUI { private const string Keyword_Suffix = "_ON"; - protected override void SetKeyword(MaterialProperty prop, bool on) + protected override void OnPropertyChange(MaterialProperty prop) { var keywordName = prop.name.ToUpper() + Keyword_Suffix; foreach (var target in prop.targets) @@ -84,7 +84,52 @@ namespace Misaki.ShaderGUI continue; } - material.SetKeyword(new LocalKeyword(material.shader, keywordName), on); +#if UNITY_6000_1_OR_NEWER + if (prop.propertyType != ShaderPropertyType.Int) +#else + if (prop.type != MaterialProperty.PropType.Int) +#endif + { + material.SetKeyword(new LocalKeyword(material.shader, keywordName), prop.floatValue != 0); + } + else + { + material.SetKeyword(new LocalKeyword(material.shader, keywordName), prop.intValue != 0); + } + } + } + } + + public class PassPopupDrawer : PopupUIDrawer + { + private readonly string _passName; + + public PassPopupDrawer(string passName) + { + _passName = passName; + } + + protected override void OnPropertyChange(MaterialProperty prop) + { + foreach (var target in prop.targets) + { + if (target is not Material material) + { + continue; + } + +#if UNITY_6000_1_OR_NEWER + if (prop.propertyType != ShaderPropertyType.Int) +#else + if (prop.type != MaterialProperty.PropType.Int) +#endif + { + material.SetShaderPassEnabled(_passName, prop.floatValue != 0); + } + else + { + material.SetShaderPassEnabled(_passName, prop.intValue != 0); + } } } }