Custom plugins
Introduction
You can override... everything. Enjoy and good luck.
Create a plugin
The MonoBehaviour
namespace MyProject {
    [AddComponentMenu("")]
    public class ColorMatrixMyTestPlugin : ColorMatrixPlugin {
        #region editor
        public override string EditorTitle => "My Test";
        public override string EditorDescription => "This plugin is a test !";
        #endregion
    }
}
EditorTitleis the label in the editorEditorDescriptionis the description at bottom of content
Editor basics
namespace MyProject {
    [AddComponentMenu("")]
    public class ColorMatrixMyTestPlugin : ColorMatrixPlugin {
        #region editor
        public override string EditorTitle => "My Test";
        public override string EditorDescription => "This plugin is a test !";
        public override Texture2D EditorIcon => null;
        public override string IconPath => "ColorMatrix_pluginTheme";
        public override bool ActiveCustomEditor() { return true; }
        public override bool Multiple() { return true; }
        #endregion
    }
}
EditorIcon=> Create a texture. It is the module icon. default(null);IconPath=> Get a texture using TextureUtility (from Resources folder or dll);ActiveCustomEditor(): The plugin have a custom editor. default(false)Multiple(): Single or multiple ? default(false)
Editor functions
public override void OnEditorEnable() { }
public override void OnEditorUpdate() { }
OnEditorEnable: On the first editor draw.OnEditorUpdate: On Update (only in editor mode and not playing)
Runtime functions
public override void BeforeUpdate(ColorMatrixElement element, int index) { }
public override void AfterLocalUpdate(ColorMatrixElement element, int index, Mat4x4 merged = null) { }
public override void AfterUpdate(Mat4x4 merged, bool fromParent = false) { }
public override void BeforeUpdate() { }
public override void AfterLocalUpdate() { }
public void BeforeInherit() { AfterLocalUpdate(); } // alias
public override void AfterUpdate() { }
public override ColorMatrix FindParent() { return null; }
public override void OnAwake(ref int maxMatrices) { }
public override void OnDestroyParentColorMatrix() { }
public override void OnRender(PropertiesController.PropertiesSetter ps) { }
public override bool RemoveDefaultRendering() { return false; }
BeforeUpdate(ColorMatrixElement element, int index): Before applying matrix. But element was updated.AfterLocalUpdate(ColorMatrixElement element, int index, Mat4x4 merged = null): After element merged to the ColorMatrix. merged is the result if element matrix has merged with another local matrix.AfterUpdate(Mat4x4 merged, bool fromParent = false): After a merge with parent. fromParent = true if parent matrix was not modified.BeforeUpdate(): On update, before matrix updating. this.Matrices are equal to the preview frameAfterLocalUpdate(): After all local matrix mergeAfterUpdate(): After all matrix merge (local and parents). Just before rendering.FindParent(): With this method you can override the inherit system.OnAwake(ref int maxMatrices): On ColorMatrix Awake. maxMatrices can be changed here if you want up or down the max ranges number. You can't change the max number at runtime.OnDestroyParentColorMatrix(): The parent component was removed.OnRender(PropertiesController.PropertiesSetter ps): Here you can add your own properties.RemoveDefaultRendering(): If true, default rendering is removed. Manage all the rendering in your OnRender method. default(false)
ColorMatrix methods preview
Update
==> plugins.BeforeUpdate();
Matrices = new List<Mat4x4>();
// local update
var cmes = GetComponents<ColorMatrixElement>().OrderBy(c => c.Index);
int index = 0;
foreach (var cme in cmes) {
    cme.UpdateMatrix();
    ==> plugins.BeforeUpdate(cme, index);
    // select a mergable matrix
    var select = Matrices.FirstOrDefault(mat => Mergable(mat, cme.Matrix));
    // merge matrices
    if (select != null) {
        select.Mult(cme.Matrix);
        ==> plugins.AfterLocalUpdate(cme, index, select);
    }
    // add a new range
    else {
        Matrices.Add(cme.Matrix.Clone());
        ==> plugins.AfterLocalUpdate(cme, index);
    }
    ++index;
}
==> plugins.AfterLocalUpdate();
// inherit
if (_parent != null && _parent.Matrices != null) {
    foreach (var pmat in _parent.Matrices) {
        // select a mergeable matrix
        var select = Matrices.FirstOrDefault(mat => Mergable(mat, pmat));
        // apply ratio
        var prat = pmat.Clone();
        prat.Ratio(InheritRatio);
        // merge matrices
        if (select != null) {
            select.Mult(prat);
            ==> plugins.AfterUpdate(select);
        }
        // add a new range
        else {
            Matrices.Add(prat);
            ==> plugins.AfterUpdate(prat, true);
        }
    }
}
==> plugins.AfterUpdate();
// render
RenderColorMatrix();
RenderColorMatrix
if (==> plugins.RemoveDefaultRendering()) {
    ==> plugins.OnRender(ref _renderer, ref _props);
    return;
}
if (_props != null) {
    _props.SetMatrixArray("_ColorMatrices", GenerateMatrixArray());
    if (Matrices.Count > 0) {
        _props.SetFloat("_MatrixCount", (float) Mathf.Min(Matrices.Count, _maxMatrices));
        _props.SetFloat("_DebugCM", Debug == EDebug.Ranges ? 1f : 0f);
    } else {
        _props.SetFloat("_MatrixCount", 0f);
    }
    ==> plugins.OnRender(ref _renderer, ref _props);
    _renderer.SetPropertyBlock(_props);
}
GenerateMatrixArray
public Matrix4x4[] GenerateMatrixArray() {
    List<Matrix4x4> response = new List<Matrix4x4>();
    for (int i = 0; i < _maxMatrices; ++i) {
        if (i < Matrices.Count) {
            response.Add(Matrices[i].Matrix);
        } else {
            response.Add(CreateIdentityMatrix());
        }
    }
    return response.ToArray();
}
Examples
ColorToColor
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace EODE.Wonderland {
    [AddComponentMenu("")]
    public class ColorMatrixColorToColorPlugin : ColorMatrixPlugin {
        #region editor
        public override string EditorTitle => "ColorToColor";
        public override string EditorDescription {
            get {
                return "Apply a hue rotation to transform the first color to the second" +
                    "\nActual rotation : " + ActualRotation;
            }
        }
        public override string IconPath => "ColorMatrix_pluginColor2Color";
        public override bool Multiple() { return true; }
        #endregion
        public Color Origin;
        public Color Destination;
        [SerializeField][HideInInspector] Mat4x4 _rotation = new Mat4x4();
        public float ActualRotation => (Destination.GetHue() - Origin.GetHue()) * 360f;
        // update mat4x4 rotation
        public override void OnEditorUpdate() {
            UpdateRotation();
        }
        public void UpdateRotation() {
            _rotation = new Mat4x4();
            _rotation.HueRotate(ActualRotation);
        }
        // add the rotation before rendering
        public override void AfterUpdate() {
            var select = ColorMatrix.Matrices.FirstOrDefault(mat => ColorMatrix.Mergable(mat, _rotation));
            if (select == null) {
                select = new Mat4x4();
                ColorMatrix.Matrices.Add(select);
            }
            select.Mult(_rotation.Matrix);
        }
    }
}
ColorMatrixThemeConditionPlugin
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace EODE.Wonderland {
    [AddComponentMenu("")]
    public class ColorMatrixThemeConditionPlugin : ColorMatrixPlugin {
        #region editor
        public override string EditorTitle => "Theme Condition";
        public override string EditorDescription => "This plugin allow to enable a matrix according to the parent theme";
        public override string IconPath => "ColorMatrix_pluginThemeCondition";
        public override bool ActiveCustomEditor() { return true; }
        public override bool Multiple() { return true; }
        #endregion
        [SerializeField][HideInInspector] int[] _activeConditions = new int[0];
        [SerializeField][HideInInspector] int _selectedMatrix = -1;
        protected ColorMatrixElement _target;
        protected ColorMatrixThemePlugin _theme;
        public virtual void Start() {
            Init();
        }
        public virtual void Init() {
            _target = FindColorMatrix(_selectedMatrix);
            _theme = ParentColorMatrix != null ? ParentColorMatrix.GetComponent<ColorMatrixThemePlugin>() : null;
        }
        public override void BeforeUpdate() {
            if (_target == null || _theme == null) return;
            _target.LocalRatio = _theme.GetActualValue(_activeConditions);
        }
        ColorMatrix FindInheritColorMatrix(Transform tr) {
            if (tr.parent == null) return null;
            var parent = tr.parent.GetComponent<ColorMatrix>();
            if (parent != null && parent.HasPlugin(typeof(ColorMatrixThemePlugin))) {
                return parent;
            }
            return FindInheritColorMatrix(tr.parent.transform);
        }
        public override ColorMatrix FindInheritColorMatrix() {
            return FindInheritColorMatrix(transform);
        }
    }
}
