You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

193 lines
5.8 KiB

using UnityEditor;
using UnityEngine;
namespace Klak.Chromatics
{
// Custom editor for cosine gradient object
[CustomEditor(typeof(CosineGradient))]
public class CosineGradientEditor : Editor
{
GraphDrawer _graph;
PreviewDrawer _preview;
SerializedProperty _redCoeffs;
SerializedProperty _greenCoeffs;
SerializedProperty _blueCoeffs;
[SerializeField] Shader _previewShader;
void OnEnable()
{
_graph = new GraphDrawer();
_preview = new PreviewDrawer(_previewShader);
_redCoeffs = serializedObject.FindProperty("_redCoeffs");
_greenCoeffs = serializedObject.FindProperty("_greenCoeffs");
_blueCoeffs = serializedObject.FindProperty("_blueCoeffs");
}
void OnDisable()
{
_preview.Cleanup();
}
public override void OnInspectorGUI()
{
serializedObject.Update();
_graph.DrawGraph((CosineGradient)target);
EditorGUILayout.Space();
_preview.DrawPreview((CosineGradient)target);
EditorGUILayout.Space();
ShowSliders("Red", _redCoeffs);
ShowSliders("Green", _greenCoeffs);
ShowSliders("Blue", _blueCoeffs);
serializedObject.ApplyModifiedProperties();
}
void ShowSliders(string label, SerializedProperty prop)
{
var v = prop.vector4Value;
EditorGUILayout.LabelField(label);
EditorGUI.BeginChangeCheck();
EditorGUI.indentLevel++;
v.x = EditorGUILayout.Slider("Bias", v.x, 0, 1);
v.y = EditorGUILayout.Slider("Amplitude", v.y, 0, 1);
v.z = EditorGUILayout.Slider("Frequency", v.z, 0, 3);
v.w = EditorGUILayout.Slider("Phase", v.w, 0, 1);
EditorGUI.indentLevel--;
if (EditorGUI.EndChangeCheck())
prop.vector4Value = new Vector4(v.x, v.y, v.z, v.w);
}
}
// A utility class for drawing component curves.
public class GraphDrawer
{
#region Public Methods
public void DrawGraph(CosineGradient grad)
{
_rectGraph = GUILayoutUtility.GetRect(128, 80);
// Background
DrawRect(0, 0, 1, 1, 0.1f, 0.4f);
// Horizontal line
var lineColor = Color.white * 0.4f;
DrawLine(0, 0.5f, 1, 0.5f, lineColor);
// Vertical lines
DrawLine(0.25f, 0, 0.25f, 1, lineColor);
DrawLine(0.50f, 0, 0.50f, 1, lineColor);
DrawLine(0.75f, 0, 0.75f, 1, lineColor);
// R/G/B curves
DrawGradientCurve(grad.redCoeffs, Color.red);
DrawGradientCurve(grad.greenCoeffs, Color.green);
DrawGradientCurve(grad.blueCoeffs, Color.blue);
}
void DrawGradientCurve(Vector4 coeffs, Color color)
{
for (var i = 0; i < _curveResolution; i++)
{
var x = (float)i / (_curveResolution - 1);
var theta = (coeffs.z * x + coeffs.w) * Mathf.PI * 2;
var y = coeffs.x + coeffs.y * Mathf.Cos(theta);
_curveVertices[i] = PointInRect(x, Mathf.Clamp01(y));
}
Handles.color = color;
Handles.DrawAAPolyLine(2.0f, _curveResolution, _curveVertices);
}
#endregion
#region Graph Functions
// Number of vertices in curve
const int _curveResolution = 96;
// Vertex buffers
Vector3[] _rectVertices = new Vector3[4];
Vector3[] _lineVertices = new Vector3[2];
Vector3[] _curveVertices = new Vector3[_curveResolution];
Rect _rectGraph;
// Transform a point into the graph rect.
Vector3 PointInRect(float x, float y)
{
x = Mathf.Lerp(_rectGraph.x, _rectGraph.xMax, x);
y = Mathf.Lerp(_rectGraph.yMax, _rectGraph.y, y);
return new Vector3(x, y, 0);
}
// Draw a line in the graph rect.
void DrawLine(float x1, float y1, float x2, float y2, Color color)
{
_lineVertices[0] = PointInRect(x1, y1);
_lineVertices[1] = PointInRect(x2, y2);
Handles.color = color;
Handles.DrawAAPolyLine(2.0f, _lineVertices);
}
// Draw a rect in the graph rect.
void DrawRect(float x1, float y1, float x2, float y2, float fill, float line)
{
_rectVertices[0] = PointInRect(x1, y1);
_rectVertices[1] = PointInRect(x2, y1);
_rectVertices[2] = PointInRect(x2, y2);
_rectVertices[3] = PointInRect(x1, y2);
Handles.DrawSolidRectangleWithOutline(
_rectVertices,
fill < 0 ? Color.clear : Color.white * fill,
line < 0 ? Color.clear : Color.white * line
);
}
#endregion
}
// A utility class for drawing a gradient preview area.
public class PreviewDrawer
{
Material _material;
public PreviewDrawer(Shader shader)
{
_material = new Material(Shader.Find("Hidden/Klak/Chromatics/CosineGradient/Preview"));
_material.hideFlags = HideFlags.DontSave;
}
public void Cleanup()
{
if (_material != null) Object.DestroyImmediate(_material);
_material = null;
}
public void DrawPreview(CosineGradient grad)
{
_material.SetVector("_CoeffsA", grad.coeffsA);
_material.SetVector("_CoeffsB", grad.coeffsB);
_material.SetVector("_CoeffsC", grad.coeffsC2);
_material.SetVector("_CoeffsD", grad.coeffsD2);
EditorGUI.DrawPreviewTexture(
GUILayoutUtility.GetRect(128, 32),
EditorGUIUtility.whiteTexture, _material
);
}
}
}