using System; using System.Collections; using System.Collections.Generic; using System.Reflection; using UnityEditor; using UnityEngine; namespace EPOOutline { public static class SerializedPropertyExtentions { private static MethodInfo getFieldInfoAndStaticTypeFromProperty; public static Attribute[] GetFieldAttributes(this SerializedProperty prop) { if (getFieldInfoAndStaticTypeFromProperty == null) { foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) { foreach (var t in assembly.GetTypes()) { if (t.Name != "ScriptAttributeUtility") continue; getFieldInfoAndStaticTypeFromProperty = t.GetMethod("GetFieldAttributes", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); foreach (var info in getFieldInfoAndStaticTypeFromProperty.GetParameters()) Debug.Log(info.ParameterType + " " + info.Name); break; } if (getFieldInfoAndStaticTypeFromProperty != null) break; } } var p = new object[] { prop, null }; var fieldInfo = getFieldInfoAndStaticTypeFromProperty.Invoke(null, p) as Attribute[]; return fieldInfo; } public static T GetCustomAttributeFromProperty(this SerializedProperty prop) where T : System.Attribute { return Array.Find(GetFieldAttributes(prop), x => x is T) as T; } } [CustomPropertyDrawer(typeof(SerializedPass))] public class SerializedPassPropertyDrawer : PropertyDrawer { public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) { var drawingPosition = position; drawingPosition.height = EditorGUIUtility.singleLineHeight; var shaderProperty = property.FindPropertyRelative("shader"); var currentShaderReference = shaderProperty.objectReferenceValue as Shader; var attribute = (SerializedPassInfoAttribute)null;// property.GetCustomAttributeFromProperty(); var prefix = attribute == null ? "Hidden/EPO/Fill/" : attribute.ShadersFolder; var fillLabel = currentShaderReference == null ? "none" : currentShaderReference.name.Substring(prefix.Length); if (shaderProperty.hasMultipleDifferentValues) fillLabel = "-"; if (EditorGUI.DropdownButton(position, new GUIContent(label.text + " : " + fillLabel), FocusType.Passive)) { var menu = new GenericMenu(); menu.AddItem(new GUIContent("none"), currentShaderReference == null && !shaderProperty.hasMultipleDifferentValues, () => { shaderProperty.objectReferenceValue = null; shaderProperty.serializedObject.ApplyModifiedProperties(); }); var shaders = AssetDatabase.FindAssets("t:Shader"); foreach (var shader in shaders) { var loadedShader = AssetDatabase.LoadAssetAtPath(AssetDatabase.GUIDToAssetPath(shader), typeof(Shader)) as Shader; if (!loadedShader.name.StartsWith(prefix)) continue; menu.AddItem(new GUIContent(loadedShader.name.Substring(prefix.Length)), loadedShader == shaderProperty.objectReferenceValue && !shaderProperty.hasMultipleDifferentValues, () => { shaderProperty.objectReferenceValue = loadedShader; shaderProperty.serializedObject.ApplyModifiedProperties(); }); } menu.ShowAsContext(); } if (shaderProperty.hasMultipleDifferentValues) return; if (currentShaderReference != null) { position.x += EditorGUIUtility.singleLineHeight; position.width -= EditorGUIUtility.singleLineHeight; var properties = new Dictionary(); var serializedProperties = property.FindPropertyRelative("serializedProperties"); for (var index = 0; index < serializedProperties.arraySize; index++) { var subProperty = serializedProperties.GetArrayElementAtIndex(index); var propertyName = subProperty.FindPropertyRelative("PropertyName"); var propertyValue = subProperty.FindPropertyRelative("Property"); if (propertyName == null || propertyValue == null) break; properties.Add(propertyName.stringValue, propertyValue); } var fillParametersPosition = position; fillParametersPosition.height = EditorGUIUtility.singleLineHeight; for (var index = 0; index < ShaderUtil.GetPropertyCount(currentShaderReference); index++) { var propertyName = ShaderUtil.GetPropertyName(currentShaderReference, index); if (!propertyName.StartsWith("_Public")) continue; fillParametersPosition.y += EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; SerializedProperty currentProperty; if (!properties.TryGetValue(propertyName, out currentProperty)) { serializedProperties.InsertArrayElementAtIndex(serializedProperties.arraySize); currentProperty = serializedProperties.GetArrayElementAtIndex(serializedProperties.arraySize - 1); currentProperty.FindPropertyRelative("PropertyName").stringValue = propertyName; currentProperty = currentProperty.FindPropertyRelative("Property"); var tempMaterial = new Material(currentShaderReference); switch (ShaderUtil.GetPropertyType(currentShaderReference, index)) { case ShaderUtil.ShaderPropertyType.Color: currentProperty.FindPropertyRelative("ColorValue").colorValue = tempMaterial.GetColor(propertyName); break; case ShaderUtil.ShaderPropertyType.Vector: currentProperty.FindPropertyRelative("VectorValue").vector4Value = tempMaterial.GetVector(propertyName); break; case ShaderUtil.ShaderPropertyType.Float: currentProperty.FindPropertyRelative("FloatValue").floatValue = tempMaterial.GetFloat(propertyName); break; case ShaderUtil.ShaderPropertyType.Range: currentProperty.FindPropertyRelative("FloatValue").floatValue = tempMaterial.GetFloat(propertyName); break; case ShaderUtil.ShaderPropertyType.TexEnv: currentProperty.FindPropertyRelative("TextureValue").objectReferenceValue = tempMaterial.GetTexture(propertyName); break; } GameObject.DestroyImmediate(tempMaterial); properties.Add(propertyName, currentProperty); } if (currentProperty == null) continue; var content = new GUIContent(ShaderUtil.GetPropertyDescription(currentShaderReference, index)); switch (ShaderUtil.GetPropertyType(currentShaderReference, index)) { case ShaderUtil.ShaderPropertyType.Color: var colorProperty = currentProperty.FindPropertyRelative("ColorValue"); colorProperty.colorValue = EditorGUI.ColorField(fillParametersPosition, content, colorProperty.colorValue, true, true, true); break; case ShaderUtil.ShaderPropertyType.Vector: var vectorProperty = currentProperty.FindPropertyRelative("VectorValue"); vectorProperty.vector4Value = EditorGUI.Vector4Field(fillParametersPosition, content, vectorProperty.vector4Value); break; case ShaderUtil.ShaderPropertyType.Float: EditorGUI.PropertyField(fillParametersPosition, currentProperty.FindPropertyRelative("FloatValue"), content); break; case ShaderUtil.ShaderPropertyType.Range: var floatProperty = currentProperty.FindPropertyRelative("FloatValue"); floatProperty.floatValue = EditorGUI.Slider(fillParametersPosition, content, floatProperty.floatValue, ShaderUtil.GetRangeLimits(currentShaderReference, index, 1), ShaderUtil.GetRangeLimits(currentShaderReference, index, 2)); break; case ShaderUtil.ShaderPropertyType.TexEnv: EditorGUI.PropertyField(fillParametersPosition, currentProperty.FindPropertyRelative("TextureValue"), content); break; } currentProperty.FindPropertyRelative("PropertyType").intValue = (int)ShaderUtil.GetPropertyType(currentShaderReference, index); } } } public override float GetPropertyHeight(SerializedProperty property, GUIContent label) { if (property.FindPropertyRelative("shader").hasMultipleDifferentValues) return EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing; var shaderProperty = property.FindPropertyRelative("shader"); var currentShaderReference = shaderProperty.objectReferenceValue as Shader; var additionalCount = 0; if (currentShaderReference != null) { for (var index = 0; index < ShaderUtil.GetPropertyCount(currentShaderReference); index++) { var propertyName = ShaderUtil.GetPropertyName(currentShaderReference, index); if (!propertyName.StartsWith("_Public")) continue; additionalCount++; } } return (EditorGUIUtility.singleLineHeight + EditorGUIUtility.standardVerticalSpacing) * (additionalCount + 1); } } }