少年修仙传客户端基础资源
hzr
2018-08-11 709d24f9c2070e9118ff298ff74e66fd38fae27d
Assets/Plugins/PostProcessing/Editor/Models/ColorGradingModelEditor.cs
@@ -1,672 +1,672 @@
using UnityEngine;
using UnityEngine.PostProcessing;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
namespace UnityEditor.PostProcessing
{
    using Settings = ColorGradingModel.Settings;
    using Tonemapper = ColorGradingModel.Tonemapper;
   using ColorWheelMode = ColorGradingModel.ColorWheelMode;
    [PostProcessingModelEditor(typeof(ColorGradingModel))]
    public class ColorGradingModelEditor : PostProcessingModelEditor
    {
        static GUIContent[] s_Tonemappers =
        {
            new GUIContent("None"),
            new GUIContent("Filmic (ACES)"),
            new GUIContent("Neutral")
        };
        struct TonemappingSettings
        {
            public SerializedProperty tonemapper;
            public SerializedProperty neutralBlackIn;
            public SerializedProperty neutralWhiteIn;
            public SerializedProperty neutralBlackOut;
            public SerializedProperty neutralWhiteOut;
            public SerializedProperty neutralWhiteLevel;
            public SerializedProperty neutralWhiteClip;
        }
        struct BasicSettings
        {
            public SerializedProperty exposure;
            public SerializedProperty temperature;
            public SerializedProperty tint;
            public SerializedProperty hueShift;
            public SerializedProperty saturation;
            public SerializedProperty contrast;
        }
        struct ChannelMixerSettings
        {
            public SerializedProperty[] channels;
            public SerializedProperty currentEditingChannel;
        }
        struct ColorWheelsSettings
        {
           public SerializedProperty mode;
            public SerializedProperty log;
            public SerializedProperty linear;
        }
        static GUIContent[] s_Curves =
        {
            new GUIContent("YRGB"),
            new GUIContent("Hue VS Hue"),
            new GUIContent("Hue VS Sat"),
            new GUIContent("Sat VS Sat"),
            new GUIContent("Lum VS Sat")
        };
        struct CurvesSettings
        {
            public SerializedProperty master;
            public SerializedProperty red;
            public SerializedProperty green;
            public SerializedProperty blue;
            public SerializedProperty hueVShue;
            public SerializedProperty hueVSsat;
            public SerializedProperty satVSsat;
            public SerializedProperty lumVSsat;
            public SerializedProperty currentEditingCurve;
            public SerializedProperty curveY;
            public SerializedProperty curveR;
            public SerializedProperty curveG;
            public SerializedProperty curveB;
        }
        TonemappingSettings m_Tonemapping;
        BasicSettings m_Basic;
        ChannelMixerSettings m_ChannelMixer;
        ColorWheelsSettings m_ColorWheels;
        CurvesSettings m_Curves;
        CurveEditor m_CurveEditor;
        Dictionary<SerializedProperty, Color> m_CurveDict;
      // Neutral tonemapping curve helper
        const int k_CurveResolution = 24;
        const float k_NeutralRangeX = 2f;
        const float k_NeutralRangeY = 1f;
        Vector3[] m_RectVertices = new Vector3[4];
        Vector3[] m_LineVertices = new Vector3[2];
        Vector3[] m_CurveVertices = new Vector3[k_CurveResolution];
       Rect m_NeutralCurveRect;
        public override void OnEnable()
        {
            // Tonemapping settings
            m_Tonemapping = new TonemappingSettings
            {
                tonemapper = FindSetting((Settings x) => x.tonemapping.tonemapper),
                neutralBlackIn = FindSetting((Settings x) => x.tonemapping.neutralBlackIn),
                neutralWhiteIn = FindSetting((Settings x) => x.tonemapping.neutralWhiteIn),
                neutralBlackOut = FindSetting((Settings x) => x.tonemapping.neutralBlackOut),
                neutralWhiteOut = FindSetting((Settings x) => x.tonemapping.neutralWhiteOut),
                neutralWhiteLevel = FindSetting((Settings x) => x.tonemapping.neutralWhiteLevel),
                neutralWhiteClip = FindSetting((Settings x) => x.tonemapping.neutralWhiteClip)
            };
            // Basic settings
            m_Basic = new BasicSettings
            {
                exposure = FindSetting((Settings x) => x.basic.postExposure),
                temperature = FindSetting((Settings x) => x.basic.temperature),
                tint = FindSetting((Settings x) => x.basic.tint),
                hueShift = FindSetting((Settings x) => x.basic.hueShift),
                saturation = FindSetting((Settings x) => x.basic.saturation),
                contrast = FindSetting((Settings x) => x.basic.contrast)
            };
            // Channel mixer
            m_ChannelMixer = new ChannelMixerSettings
            {
                channels = new[]
                {
                    FindSetting((Settings x) => x.channelMixer.red),
                    FindSetting((Settings x) => x.channelMixer.green),
                    FindSetting((Settings x) => x.channelMixer.blue)
                },
                currentEditingChannel = FindSetting((Settings x) => x.channelMixer.currentEditingChannel)
            };
            // Color wheels
            m_ColorWheels = new ColorWheelsSettings
            {
            mode = FindSetting((Settings x) => x.colorWheels.mode),
                log = FindSetting((Settings x) => x.colorWheels.log),
                linear = FindSetting((Settings x) => x.colorWheels.linear)
            };
            // Curves
            m_Curves = new CurvesSettings
            {
                master = FindSetting((Settings x) => x.curves.master.curve),
                red = FindSetting((Settings x) => x.curves.red.curve),
                green = FindSetting((Settings x) => x.curves.green.curve),
                blue = FindSetting((Settings x) => x.curves.blue.curve),
                hueVShue = FindSetting((Settings x) => x.curves.hueVShue.curve),
                hueVSsat = FindSetting((Settings x) => x.curves.hueVSsat.curve),
                satVSsat = FindSetting((Settings x) => x.curves.satVSsat.curve),
                lumVSsat = FindSetting((Settings x) => x.curves.lumVSsat.curve),
                currentEditingCurve = FindSetting((Settings x) => x.curves.e_CurrentEditingCurve),
                curveY = FindSetting((Settings x) => x.curves.e_CurveY),
                curveR = FindSetting((Settings x) => x.curves.e_CurveR),
                curveG = FindSetting((Settings x) => x.curves.e_CurveG),
                curveB = FindSetting((Settings x) => x.curves.e_CurveB)
            };
            // Prepare the curve editor and extract curve display settings
            m_CurveDict = new Dictionary<SerializedProperty, Color>();
            var settings = CurveEditor.Settings.defaultSettings;
            m_CurveEditor = new CurveEditor(settings);
            AddCurve(m_Curves.master,   new Color(1f, 1f, 1f), 2, false);
            AddCurve(m_Curves.red,      new Color(1f, 0f, 0f), 2, false);
            AddCurve(m_Curves.green,    new Color(0f, 1f, 0f), 2, false);
            AddCurve(m_Curves.blue,     new Color(0f, 0.5f, 1f), 2, false);
            AddCurve(m_Curves.hueVShue, new Color(1f, 1f, 1f), 0, true);
            AddCurve(m_Curves.hueVSsat, new Color(1f, 1f, 1f), 0, true);
            AddCurve(m_Curves.satVSsat, new Color(1f, 1f, 1f), 0, false);
            AddCurve(m_Curves.lumVSsat, new Color(1f, 1f, 1f), 0, false);
        }
        void AddCurve(SerializedProperty prop, Color color, uint minPointCount, bool loop)
        {
            var state = CurveEditor.CurveState.defaultState;
            state.color = color;
            state.visible = false;
            state.minPointCount = minPointCount;
            state.onlyShowHandlesOnSelection = true;
            state.zeroKeyConstantValue = 0.5f;
            state.loopInBounds = loop;
            m_CurveEditor.Add(prop, state);
            m_CurveDict.Add(prop, color);
        }
        public override void OnDisable()
        {
            m_CurveEditor.RemoveAll();
        }
        public override void OnInspectorGUI()
        {
            DoGUIFor("Tonemapping", DoTonemappingGUI);
            EditorGUILayout.Space();
            DoGUIFor("Basic", DoBasicGUI);
            EditorGUILayout.Space();
            DoGUIFor("Channel Mixer", DoChannelMixerGUI);
            EditorGUILayout.Space();
            DoGUIFor("Trackballs", DoColorWheelsGUI);
            EditorGUILayout.Space();
            DoGUIFor("Grading Curves", DoCurvesGUI);
        }
        void DoGUIFor(string title, Action func)
        {
            EditorGUILayout.LabelField(title, EditorStyles.boldLabel);
            EditorGUI.indentLevel++;
            func();
            EditorGUI.indentLevel--;
        }
        void DoTonemappingGUI()
        {
            int tid = EditorGUILayout.Popup(EditorGUIHelper.GetContent("Tonemapper"), m_Tonemapping.tonemapper.intValue, s_Tonemappers);
            if (tid == (int)Tonemapper.Neutral)
            {
               DrawNeutralTonemappingCurve();
                EditorGUILayout.PropertyField(m_Tonemapping.neutralBlackIn, EditorGUIHelper.GetContent("Black In"));
                EditorGUILayout.PropertyField(m_Tonemapping.neutralWhiteIn, EditorGUIHelper.GetContent("White In"));
                EditorGUILayout.PropertyField(m_Tonemapping.neutralBlackOut, EditorGUIHelper.GetContent("Black Out"));
                EditorGUILayout.PropertyField(m_Tonemapping.neutralWhiteOut, EditorGUIHelper.GetContent("White Out"));
                EditorGUILayout.PropertyField(m_Tonemapping.neutralWhiteLevel, EditorGUIHelper.GetContent("White Level"));
                EditorGUILayout.PropertyField(m_Tonemapping.neutralWhiteClip, EditorGUIHelper.GetContent("White Clip"));
            }
            m_Tonemapping.tonemapper.intValue = tid;
        }
       void DrawNeutralTonemappingCurve()
       {
            using (new GUILayout.HorizontalScope())
            {
                GUILayout.Space(EditorGUI.indentLevel * 15f);
                m_NeutralCurveRect = GUILayoutUtility.GetRect(128, 80);
            }
         // Background
         m_RectVertices[0] = PointInRect(             0f,              0f);
            m_RectVertices[1] = PointInRect(k_NeutralRangeX,              0f);
            m_RectVertices[2] = PointInRect(k_NeutralRangeX, k_NeutralRangeY);
            m_RectVertices[3] = PointInRect(             0f, k_NeutralRangeY);
            Handles.DrawSolidRectangleWithOutline(
                m_RectVertices,
                Color.white * 0.1f,
                Color.white * 0.4f
                );
            // Horizontal lines
            for (var i = 1; i < k_NeutralRangeY; i++)
                DrawLine(0, i, k_NeutralRangeX, i, 0.4f);
            // Vertical lines
            for (var i = 1; i < k_NeutralRangeX; i++)
                DrawLine(i, 0, i, k_NeutralRangeY, 0.4f);
         // Label
            Handles.Label(
                PointInRect(0, k_NeutralRangeY) + Vector3.right,
                "Neutral Tonemapper", EditorStyles.miniLabel
                );
         // Precompute some values
            var tonemap = ((ColorGradingModel)target).settings.tonemapping;
          const float scaleFactor = 20f;
            const float scaleFactorHalf = scaleFactor * 0.5f;
            float inBlack = tonemap.neutralBlackIn * scaleFactor + 1f;
            float outBlack = tonemap.neutralBlackOut * scaleFactorHalf + 1f;
            float inWhite = tonemap.neutralWhiteIn / scaleFactor;
            float outWhite = 1f - tonemap.neutralWhiteOut / scaleFactor;
            float blackRatio = inBlack / outBlack;
            float whiteRatio = inWhite / outWhite;
            const float a = 0.2f;
            float b = Mathf.Max(0f, Mathf.LerpUnclamped(0.57f, 0.37f, blackRatio));
            float c = Mathf.LerpUnclamped(0.01f, 0.24f, whiteRatio);
            float d = Mathf.Max(0f, Mathf.LerpUnclamped(0.02f, 0.20f, blackRatio));
            const float e = 0.02f;
            const float f = 0.30f;
          float whiteLevel = tonemap.neutralWhiteLevel;
          float whiteClip = tonemap.neutralWhiteClip / scaleFactorHalf;
         // Tonemapping curve
            var vcount = 0;
            while (vcount < k_CurveResolution)
            {
                float x = k_NeutralRangeX * vcount / (k_CurveResolution - 1);
                float y = NeutralTonemap(x, a, b, c, d, e, f, whiteLevel, whiteClip);
                if (y < k_NeutralRangeY)
                {
                    m_CurveVertices[vcount++] = PointInRect(x, y);
                }
                else
                {
                    if (vcount > 1)
                    {
                        // Extend the last segment to the top edge of the rect.
                        var v1 = m_CurveVertices[vcount - 2];
                        var v2 = m_CurveVertices[vcount - 1];
                        var clip = (m_NeutralCurveRect.y - v1.y) / (v2.y - v1.y);
                        m_CurveVertices[vcount - 1] = v1 + (v2 - v1) * clip;
                    }
                    break;
                }
            }
            if (vcount > 1)
            {
                Handles.color = Color.white * 0.9f;
                Handles.DrawAAPolyLine(2.0f, vcount, m_CurveVertices);
            }
       }
      void DrawLine(float x1, float y1, float x2, float y2, float grayscale)
        {
            m_LineVertices[0] = PointInRect(x1, y1);
            m_LineVertices[1] = PointInRect(x2, y2);
            Handles.color = Color.white * grayscale;
            Handles.DrawAAPolyLine(2f, m_LineVertices);
        }
      Vector3 PointInRect(float x, float y)
        {
            x = Mathf.Lerp(m_NeutralCurveRect.x, m_NeutralCurveRect.xMax, x / k_NeutralRangeX);
            y = Mathf.Lerp(m_NeutralCurveRect.yMax, m_NeutralCurveRect.y, y / k_NeutralRangeY);
            return new Vector3(x, y, 0);
        }
      float NeutralCurve(float x, float a, float b, float c, float d, float e, float f)
      {
         return ((x * (a * x + c * b) + d * e) / (x * (a * x + b) + d * f)) - e / f;
      }
       float NeutralTonemap(float x, float a, float b, float c, float d, float e, float f, float whiteLevel, float whiteClip)
       {
         x = Mathf.Max(0f, x);
         // Tonemap
         float whiteScale = 1f / NeutralCurve(whiteLevel, a, b, c, d, e, f);
         x = NeutralCurve(x * whiteScale, a, b, c, d, e, f);
         x *= whiteScale;
         // Post-curve white point adjustment
         x /= whiteClip;
         return x;
       }
        void DoBasicGUI()
        {
            EditorGUILayout.PropertyField(m_Basic.exposure, EditorGUIHelper.GetContent("Post Exposure (EV)"));
            EditorGUILayout.PropertyField(m_Basic.temperature);
            EditorGUILayout.PropertyField(m_Basic.tint);
            EditorGUILayout.PropertyField(m_Basic.hueShift);
            EditorGUILayout.PropertyField(m_Basic.saturation);
            EditorGUILayout.PropertyField(m_Basic.contrast);
        }
        void DoChannelMixerGUI()
        {
            int currentChannel = m_ChannelMixer.currentEditingChannel.intValue;
            EditorGUI.BeginChangeCheck();
            {
                using (new EditorGUILayout.HorizontalScope())
                {
                    EditorGUILayout.PrefixLabel("Channel");
                    if (GUILayout.Toggle(currentChannel == 0, EditorGUIHelper.GetContent("Red|Red output channel."), EditorStyles.miniButtonLeft)) currentChannel = 0;
                    if (GUILayout.Toggle(currentChannel == 1, EditorGUIHelper.GetContent("Green|Green output channel."), EditorStyles.miniButtonMid)) currentChannel = 1;
                    if (GUILayout.Toggle(currentChannel == 2, EditorGUIHelper.GetContent("Blue|Blue output channel."), EditorStyles.miniButtonRight)) currentChannel = 2;
                }
            }
            if (EditorGUI.EndChangeCheck())
            {
                GUI.FocusControl(null);
            }
            var serializedChannel = m_ChannelMixer.channels[currentChannel];
            m_ChannelMixer.currentEditingChannel.intValue = currentChannel;
            var v = serializedChannel.vector3Value;
            v.x = EditorGUILayout.Slider(EditorGUIHelper.GetContent("Red|Modify influence of the red channel within the overall mix."), v.x, -2f, 2f);
            v.y = EditorGUILayout.Slider(EditorGUIHelper.GetContent("Green|Modify influence of the green channel within the overall mix."), v.y, -2f, 2f);
            v.z = EditorGUILayout.Slider(EditorGUIHelper.GetContent("Blue|Modify influence of the blue channel within the overall mix."), v.z, -2f, 2f);
            serializedChannel.vector3Value = v;
        }
        void DoColorWheelsGUI()
        {
           int wheelMode = m_ColorWheels.mode.intValue;
           using (new EditorGUILayout.HorizontalScope())
           {
              GUILayout.Space(15);
              if (GUILayout.Toggle(wheelMode == (int)ColorWheelMode.Linear, "Linear", EditorStyles.miniButtonLeft)) wheelMode = (int)ColorWheelMode.Linear;
              if (GUILayout.Toggle(wheelMode == (int)ColorWheelMode.Log, "Log", EditorStyles.miniButtonRight)) wheelMode = (int)ColorWheelMode.Log;
           }
           m_ColorWheels.mode.intValue = wheelMode;
           EditorGUILayout.Space();
           if (wheelMode == (int)ColorWheelMode.Linear)
           {
              EditorGUILayout.PropertyField(m_ColorWheels.linear);
              WheelSetTitle(GUILayoutUtility.GetLastRect(), "Linear Controls");
           }
         else if (wheelMode == (int)ColorWheelMode.Log)
         {
            EditorGUILayout.PropertyField(m_ColorWheels.log);
            WheelSetTitle(GUILayoutUtility.GetLastRect(), "Log Controls");
         }
        }
        static void WheelSetTitle(Rect position, string label)
        {
            var matrix = GUI.matrix;
            var rect = new Rect(position.x - 10f, position.y, TrackballGroupDrawer.m_Size, TrackballGroupDrawer.m_Size);
            GUIUtility.RotateAroundPivot(-90f, rect.center);
            GUI.Label(rect, label, FxStyles.centeredMiniLabel);
            GUI.matrix = matrix;
        }
        void ResetVisibleCurves()
        {
            foreach (var curve in m_CurveDict)
            {
                var state = m_CurveEditor.GetCurveState(curve.Key);
                state.visible = false;
                m_CurveEditor.SetCurveState(curve.Key, state);
            }
        }
        void SetCurveVisible(SerializedProperty prop)
        {
            var state = m_CurveEditor.GetCurveState(prop);
            state.visible = true;
            m_CurveEditor.SetCurveState(prop, state);
        }
        bool SpecialToggle(bool value, string name, out bool rightClicked)
        {
            var rect = GUILayoutUtility.GetRect(EditorGUIHelper.GetContent(name), EditorStyles.toolbarButton);
            var e = Event.current;
            rightClicked = (e.type == EventType.MouseUp && rect.Contains(e.mousePosition) && e.button == 1);
            return GUI.Toggle(rect, value, name, EditorStyles.toolbarButton);
        }
        static Material s_MaterialSpline;
        void DoCurvesGUI()
        {
            EditorGUILayout.Space();
            EditorGUI.indentLevel -= 2;
            ResetVisibleCurves();
            using (new EditorGUI.DisabledGroupScope(serializedProperty.serializedObject.isEditingMultipleObjects))
            {
                int curveEditingId = 0;
                // Top toolbar
                using (new GUILayout.HorizontalScope(EditorStyles.toolbar))
                {
                    curveEditingId = EditorGUILayout.Popup(m_Curves.currentEditingCurve.intValue, s_Curves, EditorStyles.toolbarPopup, GUILayout.MaxWidth(150f));
                    bool y = false, r = false, g = false, b = false;
                    if (curveEditingId == 0)
                    {
                        EditorGUILayout.Space();
                        bool rightClickedY, rightClickedR, rightClickedG, rightClickedB;
                        y = SpecialToggle(m_Curves.curveY.boolValue, "Y", out rightClickedY);
                        r = SpecialToggle(m_Curves.curveR.boolValue, "R", out rightClickedR);
                        g = SpecialToggle(m_Curves.curveG.boolValue, "G", out rightClickedG);
                        b = SpecialToggle(m_Curves.curveB.boolValue, "B", out rightClickedB);
                        if (!y && !r && !g && !b)
                        {
                            r = g = b = false;
                            y = true;
                        }
                        if (rightClickedY || rightClickedR || rightClickedG || rightClickedB)
                        {
                            y = rightClickedY;
                            r = rightClickedR;
                            g = rightClickedG;
                            b = rightClickedB;
                        }
                        if (y) SetCurveVisible(m_Curves.master);
                        if (r) SetCurveVisible(m_Curves.red);
                        if (g) SetCurveVisible(m_Curves.green);
                        if (b) SetCurveVisible(m_Curves.blue);
                        m_Curves.curveY.boolValue = y;
                        m_Curves.curveR.boolValue = r;
                        m_Curves.curveG.boolValue = g;
                        m_Curves.curveB.boolValue = b;
                    }
                    else
                    {
                        switch (curveEditingId)
                        {
                            case 1: SetCurveVisible(m_Curves.hueVShue);
                                break;
                            case 2: SetCurveVisible(m_Curves.hueVSsat);
                                break;
                            case 3: SetCurveVisible(m_Curves.satVSsat);
                                break;
                            case 4: SetCurveVisible(m_Curves.lumVSsat);
                                break;
                        }
                    }
                    GUILayout.FlexibleSpace();
                    if (GUILayout.Button("Reset", EditorStyles.toolbarButton))
                    {
                        switch (curveEditingId)
                        {
                            case 0:
                                if (y) m_Curves.master.animationCurveValue = AnimationCurve.Linear(0f, 0f, 1f, 1f);
                                if (r) m_Curves.red.animationCurveValue    = AnimationCurve.Linear(0f, 0f, 1f, 1f);
                                if (g) m_Curves.green.animationCurveValue  = AnimationCurve.Linear(0f, 0f, 1f, 1f);
                                if (b) m_Curves.blue.animationCurveValue   = AnimationCurve.Linear(0f, 0f, 1f, 1f);
                                break;
                            case 1: m_Curves.hueVShue.animationCurveValue = new AnimationCurve();
                                break;
                            case 2: m_Curves.hueVSsat.animationCurveValue = new AnimationCurve();
                                break;
                            case 3: m_Curves.satVSsat.animationCurveValue = new AnimationCurve();
                                break;
                            case 4: m_Curves.lumVSsat.animationCurveValue = new AnimationCurve();
                                break;
                        }
                    }
                    m_Curves.currentEditingCurve.intValue = curveEditingId;
                }
                // Curve area
                var settings = m_CurveEditor.settings;
                var rect = GUILayoutUtility.GetAspectRect(2f);
                var innerRect = settings.padding.Remove(rect);
                if (Event.current.type == EventType.Repaint)
                {
                    // Background
                    EditorGUI.DrawRect(rect, new Color(0.15f, 0.15f, 0.15f, 1f));
                    if (s_MaterialSpline == null)
                        s_MaterialSpline = new Material(Shader.Find("Hidden/Post FX/UI/Curve Background")) { hideFlags = HideFlags.HideAndDontSave };
                    if (curveEditingId == 1 || curveEditingId == 2)
                        DrawBackgroundTexture(innerRect, 0);
                    else if (curveEditingId == 3 || curveEditingId == 4)
                        DrawBackgroundTexture(innerRect, 1);
                    // Bounds
                    Handles.color = Color.white;
                    Handles.DrawSolidRectangleWithOutline(innerRect, Color.clear, new Color(0.8f, 0.8f, 0.8f, 0.5f));
                    // Grid setup
                    Handles.color = new Color(1f, 1f, 1f, 0.05f);
                    int hLines = (int)Mathf.Sqrt(innerRect.width);
                    int vLines = (int)(hLines / (innerRect.width / innerRect.height));
                    // Vertical grid
                    int gridOffset = Mathf.FloorToInt(innerRect.width / hLines);
                    int gridPadding = ((int)(innerRect.width) % hLines) / 2;
                    for (int i = 1; i < hLines; i++)
                    {
                        var offset = i * Vector2.right * gridOffset;
                        offset.x += gridPadding;
                        Handles.DrawLine(innerRect.position + offset, new Vector2(innerRect.x, innerRect.yMax - 1) + offset);
                    }
                    // Horizontal grid
                    gridOffset = Mathf.FloorToInt(innerRect.height / vLines);
                    gridPadding = ((int)(innerRect.height) % vLines) / 2;
                    for (int i = 1; i < vLines; i++)
                    {
                        var offset = i * Vector2.up * gridOffset;
                        offset.y += gridPadding;
                        Handles.DrawLine(innerRect.position + offset, new Vector2(innerRect.xMax - 1, innerRect.y) + offset);
                    }
                }
                // Curve editor
                if (m_CurveEditor.OnGUI(rect))
                {
                    Repaint();
                    GUI.changed = true;
                }
                if (Event.current.type == EventType.Repaint)
                {
                    // Borders
                    Handles.color = Color.black;
                    Handles.DrawLine(new Vector2(rect.x, rect.y - 18f), new Vector2(rect.xMax, rect.y - 18f));
                    Handles.DrawLine(new Vector2(rect.x, rect.y - 19f), new Vector2(rect.x, rect.yMax));
                    Handles.DrawLine(new Vector2(rect.x, rect.yMax), new Vector2(rect.xMax, rect.yMax));
                    Handles.DrawLine(new Vector2(rect.xMax, rect.yMax), new Vector2(rect.xMax, rect.y - 18f));
                    // Selection info
                    var selection = m_CurveEditor.GetSelection();
                    if (selection.curve != null && selection.keyframeIndex > -1)
                    {
                        var key = selection.keyframe.Value;
                        var infoRect = innerRect;
                        infoRect.x += 5f;
                        infoRect.width = 100f;
                        infoRect.height = 30f;
                        GUI.Label(infoRect, string.Format("{0}\n{1}", key.time.ToString("F3"), key.value.ToString("F3")), FxStyles.preLabel);
                    }
                }
            }
            /*
            EditorGUILayout.HelpBox(
                @"Curve editor cheat sheet:
- [Del] or [Backspace] to remove a key
- [Ctrl] to break a tangent handle
- [Shift] to align tangent handles
- [Double click] to create a key on the curve(s) at mouse position
- [Alt] + [Double click] to create a key on the curve(s) at a given time",
                MessageType.Info);
            */
            EditorGUILayout.Space();
            EditorGUI.indentLevel += 2;
        }
        void DrawBackgroundTexture(Rect rect, int pass)
        {
            float scale = EditorGUIUtility.pixelsPerPoint;
            var oldRt = RenderTexture.active;
            var rt = RenderTexture.GetTemporary(Mathf.CeilToInt(rect.width * scale), Mathf.CeilToInt(rect.height * scale), 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
            s_MaterialSpline.SetFloat("_DisabledState", GUI.enabled ? 1f : 0.5f);
            s_MaterialSpline.SetFloat("_PixelScaling", EditorGUIUtility.pixelsPerPoint);
            Graphics.Blit(null, rt, s_MaterialSpline, pass);
            RenderTexture.active = oldRt;
            GUI.DrawTexture(rect, rt);
            RenderTexture.ReleaseTemporary(rt);
        }
    }
}
using UnityEngine;
using UnityEngine.PostProcessing;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
namespace UnityEditor.PostProcessing
{
    using Settings = ColorGradingModel.Settings;
    using Tonemapper = ColorGradingModel.Tonemapper;
   using ColorWheelMode = ColorGradingModel.ColorWheelMode;
    [PostProcessingModelEditor(typeof(ColorGradingModel))]
    public class ColorGradingModelEditor : PostProcessingModelEditor
    {
        static GUIContent[] s_Tonemappers =
        {
            new GUIContent("None"),
            new GUIContent("Filmic (ACES)"),
            new GUIContent("Neutral")
        };
        struct TonemappingSettings
        {
            public SerializedProperty tonemapper;
            public SerializedProperty neutralBlackIn;
            public SerializedProperty neutralWhiteIn;
            public SerializedProperty neutralBlackOut;
            public SerializedProperty neutralWhiteOut;
            public SerializedProperty neutralWhiteLevel;
            public SerializedProperty neutralWhiteClip;
        }
        struct BasicSettings
        {
            public SerializedProperty exposure;
            public SerializedProperty temperature;
            public SerializedProperty tint;
            public SerializedProperty hueShift;
            public SerializedProperty saturation;
            public SerializedProperty contrast;
        }
        struct ChannelMixerSettings
        {
            public SerializedProperty[] channels;
            public SerializedProperty currentEditingChannel;
        }
        struct ColorWheelsSettings
        {
           public SerializedProperty mode;
            public SerializedProperty log;
            public SerializedProperty linear;
        }
        static GUIContent[] s_Curves =
        {
            new GUIContent("YRGB"),
            new GUIContent("Hue VS Hue"),
            new GUIContent("Hue VS Sat"),
            new GUIContent("Sat VS Sat"),
            new GUIContent("Lum VS Sat")
        };
        struct CurvesSettings
        {
            public SerializedProperty master;
            public SerializedProperty red;
            public SerializedProperty green;
            public SerializedProperty blue;
            public SerializedProperty hueVShue;
            public SerializedProperty hueVSsat;
            public SerializedProperty satVSsat;
            public SerializedProperty lumVSsat;
            public SerializedProperty currentEditingCurve;
            public SerializedProperty curveY;
            public SerializedProperty curveR;
            public SerializedProperty curveG;
            public SerializedProperty curveB;
        }
        TonemappingSettings m_Tonemapping;
        BasicSettings m_Basic;
        ChannelMixerSettings m_ChannelMixer;
        ColorWheelsSettings m_ColorWheels;
        CurvesSettings m_Curves;
        CurveEditor m_CurveEditor;
        Dictionary<SerializedProperty, Color> m_CurveDict;
      // Neutral tonemapping curve helper
        const int k_CurveResolution = 24;
        const float k_NeutralRangeX = 2f;
        const float k_NeutralRangeY = 1f;
        Vector3[] m_RectVertices = new Vector3[4];
        Vector3[] m_LineVertices = new Vector3[2];
        Vector3[] m_CurveVertices = new Vector3[k_CurveResolution];
       Rect m_NeutralCurveRect;
        public override void OnEnable()
        {
            // Tonemapping settings
            m_Tonemapping = new TonemappingSettings
            {
                tonemapper = FindSetting((Settings x) => x.tonemapping.tonemapper),
                neutralBlackIn = FindSetting((Settings x) => x.tonemapping.neutralBlackIn),
                neutralWhiteIn = FindSetting((Settings x) => x.tonemapping.neutralWhiteIn),
                neutralBlackOut = FindSetting((Settings x) => x.tonemapping.neutralBlackOut),
                neutralWhiteOut = FindSetting((Settings x) => x.tonemapping.neutralWhiteOut),
                neutralWhiteLevel = FindSetting((Settings x) => x.tonemapping.neutralWhiteLevel),
                neutralWhiteClip = FindSetting((Settings x) => x.tonemapping.neutralWhiteClip)
            };
            // Basic settings
            m_Basic = new BasicSettings
            {
                exposure = FindSetting((Settings x) => x.basic.postExposure),
                temperature = FindSetting((Settings x) => x.basic.temperature),
                tint = FindSetting((Settings x) => x.basic.tint),
                hueShift = FindSetting((Settings x) => x.basic.hueShift),
                saturation = FindSetting((Settings x) => x.basic.saturation),
                contrast = FindSetting((Settings x) => x.basic.contrast)
            };
            // Channel mixer
            m_ChannelMixer = new ChannelMixerSettings
            {
                channels = new[]
                {
                    FindSetting((Settings x) => x.channelMixer.red),
                    FindSetting((Settings x) => x.channelMixer.green),
                    FindSetting((Settings x) => x.channelMixer.blue)
                },
                currentEditingChannel = FindSetting((Settings x) => x.channelMixer.currentEditingChannel)
            };
            // Color wheels
            m_ColorWheels = new ColorWheelsSettings
            {
            mode = FindSetting((Settings x) => x.colorWheels.mode),
                log = FindSetting((Settings x) => x.colorWheels.log),
                linear = FindSetting((Settings x) => x.colorWheels.linear)
            };
            // Curves
            m_Curves = new CurvesSettings
            {
                master = FindSetting((Settings x) => x.curves.master.curve),
                red = FindSetting((Settings x) => x.curves.red.curve),
                green = FindSetting((Settings x) => x.curves.green.curve),
                blue = FindSetting((Settings x) => x.curves.blue.curve),
                hueVShue = FindSetting((Settings x) => x.curves.hueVShue.curve),
                hueVSsat = FindSetting((Settings x) => x.curves.hueVSsat.curve),
                satVSsat = FindSetting((Settings x) => x.curves.satVSsat.curve),
                lumVSsat = FindSetting((Settings x) => x.curves.lumVSsat.curve),
                currentEditingCurve = FindSetting((Settings x) => x.curves.e_CurrentEditingCurve),
                curveY = FindSetting((Settings x) => x.curves.e_CurveY),
                curveR = FindSetting((Settings x) => x.curves.e_CurveR),
                curveG = FindSetting((Settings x) => x.curves.e_CurveG),
                curveB = FindSetting((Settings x) => x.curves.e_CurveB)
            };
            // Prepare the curve editor and extract curve display settings
            m_CurveDict = new Dictionary<SerializedProperty, Color>();
            var settings = CurveEditor.Settings.defaultSettings;
            m_CurveEditor = new CurveEditor(settings);
            AddCurve(m_Curves.master,   new Color(1f, 1f, 1f), 2, false);
            AddCurve(m_Curves.red,      new Color(1f, 0f, 0f), 2, false);
            AddCurve(m_Curves.green,    new Color(0f, 1f, 0f), 2, false);
            AddCurve(m_Curves.blue,     new Color(0f, 0.5f, 1f), 2, false);
            AddCurve(m_Curves.hueVShue, new Color(1f, 1f, 1f), 0, true);
            AddCurve(m_Curves.hueVSsat, new Color(1f, 1f, 1f), 0, true);
            AddCurve(m_Curves.satVSsat, new Color(1f, 1f, 1f), 0, false);
            AddCurve(m_Curves.lumVSsat, new Color(1f, 1f, 1f), 0, false);
        }
        void AddCurve(SerializedProperty prop, Color color, uint minPointCount, bool loop)
        {
            var state = CurveEditor.CurveState.defaultState;
            state.color = color;
            state.visible = false;
            state.minPointCount = minPointCount;
            state.onlyShowHandlesOnSelection = true;
            state.zeroKeyConstantValue = 0.5f;
            state.loopInBounds = loop;
            m_CurveEditor.Add(prop, state);
            m_CurveDict.Add(prop, color);
        }
        public override void OnDisable()
        {
            m_CurveEditor.RemoveAll();
        }
        public override void OnInspectorGUI()
        {
            DoGUIFor("Tonemapping", DoTonemappingGUI);
            EditorGUILayout.Space();
            DoGUIFor("Basic", DoBasicGUI);
            EditorGUILayout.Space();
            DoGUIFor("Channel Mixer", DoChannelMixerGUI);
            EditorGUILayout.Space();
            DoGUIFor("Trackballs", DoColorWheelsGUI);
            EditorGUILayout.Space();
            DoGUIFor("Grading Curves", DoCurvesGUI);
        }
        void DoGUIFor(string title, Action func)
        {
            EditorGUILayout.LabelField(title, EditorStyles.boldLabel);
            EditorGUI.indentLevel++;
            func();
            EditorGUI.indentLevel--;
        }
        void DoTonemappingGUI()
        {
            int tid = EditorGUILayout.Popup(EditorGUIHelper.GetContent("Tonemapper"), m_Tonemapping.tonemapper.intValue, s_Tonemappers);
            if (tid == (int)Tonemapper.Neutral)
            {
               DrawNeutralTonemappingCurve();
                EditorGUILayout.PropertyField(m_Tonemapping.neutralBlackIn, EditorGUIHelper.GetContent("Black In"));
                EditorGUILayout.PropertyField(m_Tonemapping.neutralWhiteIn, EditorGUIHelper.GetContent("White In"));
                EditorGUILayout.PropertyField(m_Tonemapping.neutralBlackOut, EditorGUIHelper.GetContent("Black Out"));
                EditorGUILayout.PropertyField(m_Tonemapping.neutralWhiteOut, EditorGUIHelper.GetContent("White Out"));
                EditorGUILayout.PropertyField(m_Tonemapping.neutralWhiteLevel, EditorGUIHelper.GetContent("White Level"));
                EditorGUILayout.PropertyField(m_Tonemapping.neutralWhiteClip, EditorGUIHelper.GetContent("White Clip"));
            }
            m_Tonemapping.tonemapper.intValue = tid;
        }
       void DrawNeutralTonemappingCurve()
       {
            using (new GUILayout.HorizontalScope())
            {
                GUILayout.Space(EditorGUI.indentLevel * 15f);
                m_NeutralCurveRect = GUILayoutUtility.GetRect(128, 80);
            }
         // Background
         m_RectVertices[0] = PointInRect(             0f,              0f);
            m_RectVertices[1] = PointInRect(k_NeutralRangeX,              0f);
            m_RectVertices[2] = PointInRect(k_NeutralRangeX, k_NeutralRangeY);
            m_RectVertices[3] = PointInRect(             0f, k_NeutralRangeY);
            Handles.DrawSolidRectangleWithOutline(
                m_RectVertices,
                Color.white * 0.1f,
                Color.white * 0.4f
                );
            // Horizontal lines
            for (var i = 1; i < k_NeutralRangeY; i++)
                DrawLine(0, i, k_NeutralRangeX, i, 0.4f);
            // Vertical lines
            for (var i = 1; i < k_NeutralRangeX; i++)
                DrawLine(i, 0, i, k_NeutralRangeY, 0.4f);
         // Label
            Handles.Label(
                PointInRect(0, k_NeutralRangeY) + Vector3.right,
                "Neutral Tonemapper", EditorStyles.miniLabel
                );
         // Precompute some values
            var tonemap = ((ColorGradingModel)target).settings.tonemapping;
          const float scaleFactor = 20f;
            const float scaleFactorHalf = scaleFactor * 0.5f;
            float inBlack = tonemap.neutralBlackIn * scaleFactor + 1f;
            float outBlack = tonemap.neutralBlackOut * scaleFactorHalf + 1f;
            float inWhite = tonemap.neutralWhiteIn / scaleFactor;
            float outWhite = 1f - tonemap.neutralWhiteOut / scaleFactor;
            float blackRatio = inBlack / outBlack;
            float whiteRatio = inWhite / outWhite;
            const float a = 0.2f;
            float b = Mathf.Max(0f, Mathf.LerpUnclamped(0.57f, 0.37f, blackRatio));
            float c = Mathf.LerpUnclamped(0.01f, 0.24f, whiteRatio);
            float d = Mathf.Max(0f, Mathf.LerpUnclamped(0.02f, 0.20f, blackRatio));
            const float e = 0.02f;
            const float f = 0.30f;
          float whiteLevel = tonemap.neutralWhiteLevel;
          float whiteClip = tonemap.neutralWhiteClip / scaleFactorHalf;
         // Tonemapping curve
            var vcount = 0;
            while (vcount < k_CurveResolution)
            {
                float x = k_NeutralRangeX * vcount / (k_CurveResolution - 1);
                float y = NeutralTonemap(x, a, b, c, d, e, f, whiteLevel, whiteClip);
                if (y < k_NeutralRangeY)
                {
                    m_CurveVertices[vcount++] = PointInRect(x, y);
                }
                else
                {
                    if (vcount > 1)
                    {
                        // Extend the last segment to the top edge of the rect.
                        var v1 = m_CurveVertices[vcount - 2];
                        var v2 = m_CurveVertices[vcount - 1];
                        var clip = (m_NeutralCurveRect.y - v1.y) / (v2.y - v1.y);
                        m_CurveVertices[vcount - 1] = v1 + (v2 - v1) * clip;
                    }
                    break;
                }
            }
            if (vcount > 1)
            {
                Handles.color = Color.white * 0.9f;
                Handles.DrawAAPolyLine(2.0f, vcount, m_CurveVertices);
            }
       }
      void DrawLine(float x1, float y1, float x2, float y2, float grayscale)
        {
            m_LineVertices[0] = PointInRect(x1, y1);
            m_LineVertices[1] = PointInRect(x2, y2);
            Handles.color = Color.white * grayscale;
            Handles.DrawAAPolyLine(2f, m_LineVertices);
        }
      Vector3 PointInRect(float x, float y)
        {
            x = Mathf.Lerp(m_NeutralCurveRect.x, m_NeutralCurveRect.xMax, x / k_NeutralRangeX);
            y = Mathf.Lerp(m_NeutralCurveRect.yMax, m_NeutralCurveRect.y, y / k_NeutralRangeY);
            return new Vector3(x, y, 0);
        }
      float NeutralCurve(float x, float a, float b, float c, float d, float e, float f)
      {
         return ((x * (a * x + c * b) + d * e) / (x * (a * x + b) + d * f)) - e / f;
      }
       float NeutralTonemap(float x, float a, float b, float c, float d, float e, float f, float whiteLevel, float whiteClip)
       {
         x = Mathf.Max(0f, x);
         // Tonemap
         float whiteScale = 1f / NeutralCurve(whiteLevel, a, b, c, d, e, f);
         x = NeutralCurve(x * whiteScale, a, b, c, d, e, f);
         x *= whiteScale;
         // Post-curve white point adjustment
         x /= whiteClip;
         return x;
       }
        void DoBasicGUI()
        {
            EditorGUILayout.PropertyField(m_Basic.exposure, EditorGUIHelper.GetContent("Post Exposure (EV)"));
            EditorGUILayout.PropertyField(m_Basic.temperature);
            EditorGUILayout.PropertyField(m_Basic.tint);
            EditorGUILayout.PropertyField(m_Basic.hueShift);
            EditorGUILayout.PropertyField(m_Basic.saturation);
            EditorGUILayout.PropertyField(m_Basic.contrast);
        }
        void DoChannelMixerGUI()
        {
            int currentChannel = m_ChannelMixer.currentEditingChannel.intValue;
            EditorGUI.BeginChangeCheck();
            {
                using (new EditorGUILayout.HorizontalScope())
                {
                    EditorGUILayout.PrefixLabel("Channel");
                    if (GUILayout.Toggle(currentChannel == 0, EditorGUIHelper.GetContent("Red|Red output channel."), EditorStyles.miniButtonLeft)) currentChannel = 0;
                    if (GUILayout.Toggle(currentChannel == 1, EditorGUIHelper.GetContent("Green|Green output channel."), EditorStyles.miniButtonMid)) currentChannel = 1;
                    if (GUILayout.Toggle(currentChannel == 2, EditorGUIHelper.GetContent("Blue|Blue output channel."), EditorStyles.miniButtonRight)) currentChannel = 2;
                }
            }
            if (EditorGUI.EndChangeCheck())
            {
                GUI.FocusControl(null);
            }
            var serializedChannel = m_ChannelMixer.channels[currentChannel];
            m_ChannelMixer.currentEditingChannel.intValue = currentChannel;
            var v = serializedChannel.vector3Value;
            v.x = EditorGUILayout.Slider(EditorGUIHelper.GetContent("Red|Modify influence of the red channel within the overall mix."), v.x, -2f, 2f);
            v.y = EditorGUILayout.Slider(EditorGUIHelper.GetContent("Green|Modify influence of the green channel within the overall mix."), v.y, -2f, 2f);
            v.z = EditorGUILayout.Slider(EditorGUIHelper.GetContent("Blue|Modify influence of the blue channel within the overall mix."), v.z, -2f, 2f);
            serializedChannel.vector3Value = v;
        }
        void DoColorWheelsGUI()
        {
           int wheelMode = m_ColorWheels.mode.intValue;
           using (new EditorGUILayout.HorizontalScope())
           {
              GUILayout.Space(15);
              if (GUILayout.Toggle(wheelMode == (int)ColorWheelMode.Linear, "Linear", EditorStyles.miniButtonLeft)) wheelMode = (int)ColorWheelMode.Linear;
              if (GUILayout.Toggle(wheelMode == (int)ColorWheelMode.Log, "Log", EditorStyles.miniButtonRight)) wheelMode = (int)ColorWheelMode.Log;
           }
           m_ColorWheels.mode.intValue = wheelMode;
           EditorGUILayout.Space();
           if (wheelMode == (int)ColorWheelMode.Linear)
           {
              EditorGUILayout.PropertyField(m_ColorWheels.linear);
              WheelSetTitle(GUILayoutUtility.GetLastRect(), "Linear Controls");
           }
         else if (wheelMode == (int)ColorWheelMode.Log)
         {
            EditorGUILayout.PropertyField(m_ColorWheels.log);
            WheelSetTitle(GUILayoutUtility.GetLastRect(), "Log Controls");
         }
        }
        static void WheelSetTitle(Rect position, string label)
        {
            var matrix = GUI.matrix;
            var rect = new Rect(position.x - 10f, position.y, TrackballGroupDrawer.m_Size, TrackballGroupDrawer.m_Size);
            GUIUtility.RotateAroundPivot(-90f, rect.center);
            GUI.Label(rect, label, FxStyles.centeredMiniLabel);
            GUI.matrix = matrix;
        }
        void ResetVisibleCurves()
        {
            foreach (var curve in m_CurveDict)
            {
                var state = m_CurveEditor.GetCurveState(curve.Key);
                state.visible = false;
                m_CurveEditor.SetCurveState(curve.Key, state);
            }
        }
        void SetCurveVisible(SerializedProperty prop)
        {
            var state = m_CurveEditor.GetCurveState(prop);
            state.visible = true;
            m_CurveEditor.SetCurveState(prop, state);
        }
        bool SpecialToggle(bool value, string name, out bool rightClicked)
        {
            var rect = GUILayoutUtility.GetRect(EditorGUIHelper.GetContent(name), EditorStyles.toolbarButton);
            var e = Event.current;
            rightClicked = (e.type == EventType.MouseUp && rect.Contains(e.mousePosition) && e.button == 1);
            return GUI.Toggle(rect, value, name, EditorStyles.toolbarButton);
        }
        static Material s_MaterialSpline;
        void DoCurvesGUI()
        {
            EditorGUILayout.Space();
            EditorGUI.indentLevel -= 2;
            ResetVisibleCurves();
            using (new EditorGUI.DisabledGroupScope(serializedProperty.serializedObject.isEditingMultipleObjects))
            {
                int curveEditingId = 0;
                // Top toolbar
                using (new GUILayout.HorizontalScope(EditorStyles.toolbar))
                {
                    curveEditingId = EditorGUILayout.Popup(m_Curves.currentEditingCurve.intValue, s_Curves, EditorStyles.toolbarPopup, GUILayout.MaxWidth(150f));
                    bool y = false, r = false, g = false, b = false;
                    if (curveEditingId == 0)
                    {
                        EditorGUILayout.Space();
                        bool rightClickedY, rightClickedR, rightClickedG, rightClickedB;
                        y = SpecialToggle(m_Curves.curveY.boolValue, "Y", out rightClickedY);
                        r = SpecialToggle(m_Curves.curveR.boolValue, "R", out rightClickedR);
                        g = SpecialToggle(m_Curves.curveG.boolValue, "G", out rightClickedG);
                        b = SpecialToggle(m_Curves.curveB.boolValue, "B", out rightClickedB);
                        if (!y && !r && !g && !b)
                        {
                            r = g = b = false;
                            y = true;
                        }
                        if (rightClickedY || rightClickedR || rightClickedG || rightClickedB)
                        {
                            y = rightClickedY;
                            r = rightClickedR;
                            g = rightClickedG;
                            b = rightClickedB;
                        }
                        if (y) SetCurveVisible(m_Curves.master);
                        if (r) SetCurveVisible(m_Curves.red);
                        if (g) SetCurveVisible(m_Curves.green);
                        if (b) SetCurveVisible(m_Curves.blue);
                        m_Curves.curveY.boolValue = y;
                        m_Curves.curveR.boolValue = r;
                        m_Curves.curveG.boolValue = g;
                        m_Curves.curveB.boolValue = b;
                    }
                    else
                    {
                        switch (curveEditingId)
                        {
                            case 1: SetCurveVisible(m_Curves.hueVShue);
                                break;
                            case 2: SetCurveVisible(m_Curves.hueVSsat);
                                break;
                            case 3: SetCurveVisible(m_Curves.satVSsat);
                                break;
                            case 4: SetCurveVisible(m_Curves.lumVSsat);
                                break;
                        }
                    }
                    GUILayout.FlexibleSpace();
                    if (GUILayout.Button("Reset", EditorStyles.toolbarButton))
                    {
                        switch (curveEditingId)
                        {
                            case 0:
                                if (y) m_Curves.master.animationCurveValue = AnimationCurve.Linear(0f, 0f, 1f, 1f);
                                if (r) m_Curves.red.animationCurveValue    = AnimationCurve.Linear(0f, 0f, 1f, 1f);
                                if (g) m_Curves.green.animationCurveValue  = AnimationCurve.Linear(0f, 0f, 1f, 1f);
                                if (b) m_Curves.blue.animationCurveValue   = AnimationCurve.Linear(0f, 0f, 1f, 1f);
                                break;
                            case 1: m_Curves.hueVShue.animationCurveValue = new AnimationCurve();
                                break;
                            case 2: m_Curves.hueVSsat.animationCurveValue = new AnimationCurve();
                                break;
                            case 3: m_Curves.satVSsat.animationCurveValue = new AnimationCurve();
                                break;
                            case 4: m_Curves.lumVSsat.animationCurveValue = new AnimationCurve();
                                break;
                        }
                    }
                    m_Curves.currentEditingCurve.intValue = curveEditingId;
                }
                // Curve area
                var settings = m_CurveEditor.settings;
                var rect = GUILayoutUtility.GetAspectRect(2f);
                var innerRect = settings.padding.Remove(rect);
                if (Event.current.type == EventType.Repaint)
                {
                    // Background
                    EditorGUI.DrawRect(rect, new Color(0.15f, 0.15f, 0.15f, 1f));
                    if (s_MaterialSpline == null)
                        s_MaterialSpline = new Material(Shader.Find("Hidden/Post FX/UI/Curve Background")) { hideFlags = HideFlags.HideAndDontSave };
                    if (curveEditingId == 1 || curveEditingId == 2)
                        DrawBackgroundTexture(innerRect, 0);
                    else if (curveEditingId == 3 || curveEditingId == 4)
                        DrawBackgroundTexture(innerRect, 1);
                    // Bounds
                    Handles.color = Color.white;
                    Handles.DrawSolidRectangleWithOutline(innerRect, Color.clear, new Color(0.8f, 0.8f, 0.8f, 0.5f));
                    // Grid setup
                    Handles.color = new Color(1f, 1f, 1f, 0.05f);
                    int hLines = (int)Mathf.Sqrt(innerRect.width);
                    int vLines = (int)(hLines / (innerRect.width / innerRect.height));
                    // Vertical grid
                    int gridOffset = Mathf.FloorToInt(innerRect.width / hLines);
                    int gridPadding = ((int)(innerRect.width) % hLines) / 2;
                    for (int i = 1; i < hLines; i++)
                    {
                        var offset = i * Vector2.right * gridOffset;
                        offset.x += gridPadding;
                        Handles.DrawLine(innerRect.position + offset, new Vector2(innerRect.x, innerRect.yMax - 1) + offset);
                    }
                    // Horizontal grid
                    gridOffset = Mathf.FloorToInt(innerRect.height / vLines);
                    gridPadding = ((int)(innerRect.height) % vLines) / 2;
                    for (int i = 1; i < vLines; i++)
                    {
                        var offset = i * Vector2.up * gridOffset;
                        offset.y += gridPadding;
                        Handles.DrawLine(innerRect.position + offset, new Vector2(innerRect.xMax - 1, innerRect.y) + offset);
                    }
                }
                // Curve editor
                if (m_CurveEditor.OnGUI(rect))
                {
                    Repaint();
                    GUI.changed = true;
                }
                if (Event.current.type == EventType.Repaint)
                {
                    // Borders
                    Handles.color = Color.black;
                    Handles.DrawLine(new Vector2(rect.x, rect.y - 18f), new Vector2(rect.xMax, rect.y - 18f));
                    Handles.DrawLine(new Vector2(rect.x, rect.y - 19f), new Vector2(rect.x, rect.yMax));
                    Handles.DrawLine(new Vector2(rect.x, rect.yMax), new Vector2(rect.xMax, rect.yMax));
                    Handles.DrawLine(new Vector2(rect.xMax, rect.yMax), new Vector2(rect.xMax, rect.y - 18f));
                    // Selection info
                    var selection = m_CurveEditor.GetSelection();
                    if (selection.curve != null && selection.keyframeIndex > -1)
                    {
                        var key = selection.keyframe.Value;
                        var infoRect = innerRect;
                        infoRect.x += 5f;
                        infoRect.width = 100f;
                        infoRect.height = 30f;
                        GUI.Label(infoRect, string.Format("{0}\n{1}", key.time.ToString("F3"), key.value.ToString("F3")), FxStyles.preLabel);
                    }
                }
            }
            /*
            EditorGUILayout.HelpBox(
                @"Curve editor cheat sheet:
- [Del] or [Backspace] to remove a key
- [Ctrl] to break a tangent handle
- [Shift] to align tangent handles
- [Double click] to create a key on the curve(s) at mouse position
- [Alt] + [Double click] to create a key on the curve(s) at a given time",
                MessageType.Info);
            */
            EditorGUILayout.Space();
            EditorGUI.indentLevel += 2;
        }
        void DrawBackgroundTexture(Rect rect, int pass)
        {
            float scale = EditorGUIUtility.pixelsPerPoint;
            var oldRt = RenderTexture.active;
            var rt = RenderTexture.GetTemporary(Mathf.CeilToInt(rect.width * scale), Mathf.CeilToInt(rect.height * scale), 0, RenderTextureFormat.ARGB32, RenderTextureReadWrite.Linear);
            s_MaterialSpline.SetFloat("_DisabledState", GUI.enabled ? 1f : 0.5f);
            s_MaterialSpline.SetFloat("_PixelScaling", EditorGUIUtility.pixelsPerPoint);
            Graphics.Blit(null, rt, s_MaterialSpline, pass);
            RenderTexture.active = oldRt;
            GUI.DrawTexture(rect, rt);
            RenderTexture.ReleaseTemporary(rt);
        }
    }
}