/* Copyright (C) 2022 igoz <igoz@igoz.net>
 * See end of file for extended copyright and license notice. */
using UnityEngine;
using ColorTup = System.Tuple<UnityEngine.Color, UnityEngine.Color, UnityEngine.Color>;

[ExecuteInEditMode]
[RequireComponent(typeof(Camera))]
public class ColorBlindViewer : MonoBehaviour
{
    public enum ColorBlindness
    {
        None,
        Protanopia,
        Deuteranopia,
        Protanomaly,
        Deuteranomaly,
        Tritanopia,
        Tritanomaly,
        Achromatopsia,
        Achromatomaly
    }

    // Values obtained from: https://web.archive.org/web/20081014161121/http://www.colorjack.com/labs/colormatrix/
    public static readonly ColorTup ChannelsNone            = new ColorTup(new Color(1.00000f, 0.00000f, 0.00000f), new Color(0.00000f, 1.00000f, 0.00000f), new Color(0.00000f, 0.00000f, 1.00000f));
    public static readonly ColorTup ChannelsProtanopia      = new ColorTup(new Color(0.56667f, 0.43333f, 0.00000f), new Color(0.55833f, 0.44167f, 0.00000f), new Color(0.00000f, 0.24167f, 0.75833f));
    public static readonly ColorTup ChannelsDeuteranopia    = new ColorTup(new Color(0.62500f, 0.37500f, 0.00000f), new Color(0.70000f, 0.30000f, 0.00000f), new Color(0.00000f, 0.30000f, 0.70000f));
    public static readonly ColorTup ChannelsProtanomaly     = new ColorTup(new Color(0.81667f, 0.18333f, 0.00000f), new Color(0.33333f, 0.66667f, 0.00000f), new Color(0.00000f, 0.12500f, 0.87500f));
    public static readonly ColorTup ChannelsDeuteranomaly   = new ColorTup(new Color(0.80000f, 0.20000f, 0.00000f), new Color(0.25833f, 0.74167f, 0.00000f), new Color(0.00000f, 0.14167f, 0.85833f));
    public static readonly ColorTup ChannelsTritanopia      = new ColorTup(new Color(0.95000f, 0.05000f, 0.00000f), new Color(0.00000f, 0.43333f, 0.56667f), new Color(0.00000f, 0.47500f, 0.52500f));
    public static readonly ColorTup ChannelsTritanomaly     = new ColorTup(new Color(0.96667f, 0.03333f, 0.00000f), new Color(0.00000f, 0.73333f, 0.26667f), new Color(0.00000f, 0.18333f, 0.81667f));
    public static readonly ColorTup ChannelsAchromatopsia   = new ColorTup(new Color(0.29900f, 0.58700f, 0.11400f), new Color(0.29900f, 0.58700f, 0.11400f), new Color(0.29900f, 0.58700f, 0.11400f));
    public static readonly ColorTup ChannelsAchromatomaly   = new ColorTup(new Color(0.61800f, 0.32000f, 0.06200f), new Color(0.16300f, 0.77500f, 0.06200f), new Color(0.16300f, 0.32000f, 0.51600f));

    private Material _renderMaterial;
    public ColorBlindness ColorBlindnessMode = ColorBlindness.None;
    private ColorBlindness _lastColorBlindnessMode = ColorBlindness.None;

    private void UpdateMaterial()
    {
        switch (ColorBlindnessMode)
        {
            case ColorBlindness.None:
                _renderMaterial.SetColor("_Red", ChannelsNone.Item1);
                _renderMaterial.SetColor("_Green", ChannelsNone.Item2);
                _renderMaterial.SetColor("_Blue", ChannelsNone.Item3);
                return;
            case ColorBlindness.Protanopia:
                _renderMaterial.SetColor("_Red", ChannelsProtanopia.Item1);
                _renderMaterial.SetColor("_Green", ChannelsProtanopia.Item2);
                _renderMaterial.SetColor("_Blue", ChannelsProtanopia.Item3);
                break;
            case ColorBlindness.Deuteranopia:
                _renderMaterial.SetColor("_Red", ChannelsDeuteranopia.Item1);
                _renderMaterial.SetColor("_Green", ChannelsDeuteranopia.Item2);
                _renderMaterial.SetColor("_Blue", ChannelsDeuteranopia.Item3);
                break;
            case ColorBlindness.Protanomaly:
                _renderMaterial.SetColor("_Red", ChannelsProtanomaly.Item1);
                _renderMaterial.SetColor("_Green", ChannelsProtanomaly.Item2);
                _renderMaterial.SetColor("_Blue", ChannelsProtanomaly.Item3);
                break;
            case ColorBlindness.Deuteranomaly:
                _renderMaterial.SetColor("_Red", ChannelsDeuteranomaly.Item1);
                _renderMaterial.SetColor("_Green", ChannelsDeuteranomaly.Item2);
                _renderMaterial.SetColor("_Blue", ChannelsDeuteranomaly.Item3);
                break;
            case ColorBlindness.Tritanopia:
                _renderMaterial.SetColor("_Red", ChannelsTritanopia.Item1);
                _renderMaterial.SetColor("_Green", ChannelsTritanopia.Item2);
                _renderMaterial.SetColor("_Blue", ChannelsTritanopia.Item3);
                break;
            case ColorBlindness.Tritanomaly:
                _renderMaterial.SetColor("_Red", ChannelsTritanomaly.Item1);
                _renderMaterial.SetColor("_Green", ChannelsTritanomaly.Item2);
                _renderMaterial.SetColor("_Blue", ChannelsTritanomaly.Item3);
                break;
            case ColorBlindness.Achromatopsia:
                _renderMaterial.SetColor("_Red", ChannelsAchromatopsia.Item1);
                _renderMaterial.SetColor("_Green", ChannelsAchromatopsia.Item2);
                _renderMaterial.SetColor("_Blue", ChannelsAchromatopsia.Item3);
                break;
            case ColorBlindness.Achromatomaly:
                _renderMaterial.SetColor("_Red", ChannelsAchromatomaly.Item1);
                _renderMaterial.SetColor("_Green", ChannelsAchromatomaly.Item2);
                _renderMaterial.SetColor("_Blue", ChannelsAchromatomaly.Item3);
                break;
        }
    }

    private void Awake()
    {
        _renderMaterial = new Material(Shader.Find("Hidden/ColorBlindFiltering"));
        UpdateMaterial();
    }

    private void OnRenderImage(RenderTexture source, RenderTexture destination)
    {
        if (ColorBlindnessMode == _lastColorBlindnessMode)
            Graphics.Blit(source, destination, _renderMaterial);
        else
        {
            UpdateMaterial();
            _lastColorBlindnessMode = ColorBlindnessMode;
            Graphics.Blit(source, destination, _renderMaterial);
        }
    }
}

/* Copyright (C) 2022 igoz <igoz@igoz.net>
 *
 * This file is part of ColorBlindViewer.
 *
 * ColorBlindViewer is free software: you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your option) any
 * later version.
 *
 * ColorBlindViewer is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * ColorBlindViewer. If not, see <https://www.gnu.org/licenses/>. 
 */