using System;
using System.Collections;
using System.Drawing;
using System.Windows.Forms;
using PaintDotNet;
using PaintDotNet.Effects;

namespace BlendModesPlus
{
    public class EffectPlugin
        : PaintDotNet.Effects.Effect
    {
        public static string StaticName
        {
            get
            {
                return "BlendModes Plus";
            }
        }

        public static Bitmap StaticIcon
        {
            get
            {
                return new Bitmap(typeof(EffectPlugin), "EffectPluginIcon.png");
            }
        }

        public static string StaticSubMenuName
        {
            get
            {
                return "Tools";
            }
        }

        public EffectPlugin()
            : base(EffectPlugin.StaticName, EffectPlugin.StaticIcon, EffectPlugin.StaticSubMenuName, true)
        {

        }

        public override EffectConfigDialog CreateConfigDialog()
        {
            return new EffectPluginConfigDialog();
        }

        public override void Render(EffectConfigToken parameters, RenderArgs dstArgs, RenderArgs srcArgs, Rectangle[] rois, int startIndex, int length)
        {
            PdnRegion selectionRegion = EnvironmentParameters.GetSelection(srcArgs.Bounds);
            EffectPluginConfigToken token = (EffectPluginConfigToken)parameters;
            if (token.LoadedImage == null) return;

            ColorBgra CP;
            ColorBgra LCP;
            HsvColor CPHSV;
            HsvColor LCPHSV;

            for (int i = startIndex; i < startIndex + length; ++i)
            {
                Rectangle rect = rois[i];

                for (int y = rect.Top; y < rect.Bottom; ++y)
                {
                    for (int x = rect.Left; x < rect.Right; ++x)
                    {
                        if ((token.FromClipboard == false && token.LoadedImage != null) || (token.FromClipboard == true && token.ClipboardImage != null))
                        {
                        CP = new ColorBgra();
                        LCP = new ColorBgra();
                        CPHSV = new HsvColor();
                        LCPHSV = new HsvColor();
                        
                        if (token.FromClipboard == false && token.SwapLayers == false)
                        {
                            CP = srcArgs.Surface[x, y];
                            LCP = token.LoadedImage[x, y];
                            CPHSV = HsvColor.FromColor(Color.FromArgb(CP.A, CP.R, CP.G, CP.B));
                            LCPHSV = HsvColor.FromColor(Color.FromArgb(LCP.A, LCP.R, LCP.G, LCP.B));
                        }

                        if (token.FromClipboard == false && token.SwapLayers == true)
                        {
                            CP = token.LoadedImage[x, y];
                            LCP = srcArgs.Surface[x, y];
                            CPHSV = HsvColor.FromColor(Color.FromArgb(CP.A, CP.R, CP.G, CP.B));
                            LCPHSV = HsvColor.FromColor(Color.FromArgb(LCP.A, LCP.R, LCP.G, LCP.B));
                        }

                        if (token.FromClipboard == true && token.SwapLayers == false)
                        {
                            CP = srcArgs.Surface[x, y];
                            LCP = token.ClipboardImage[x, y];
                            CPHSV = HsvColor.FromColor(Color.FromArgb(CP.A, CP.R, CP.G, CP.B));
                            LCPHSV = HsvColor.FromColor(Color.FromArgb(LCP.A, LCP.R, LCP.G, LCP.B));
                        }

                        if (token.FromClipboard == true && token.SwapLayers == true)
                        {
                            CP = token.ClipboardImage[x, y];
                            LCP = srcArgs.Surface[x, y];
                            CPHSV = HsvColor.FromColor(Color.FromArgb(CP.A, CP.R, CP.G, CP.B));
                            LCPHSV = HsvColor.FromColor(Color.FromArgb(LCP.A, LCP.R, LCP.G, LCP.B));
                        }
                            switch (token.BlendMode)
                            {
                                #region Normal
                                case "Normal":
                                    dstArgs.Surface[x, y] = LCP;
                                    break;
                                #endregion

                                #region Additive
                                case "Additive":
                                    byte AdR = Utility.ClampToByte(CP.R + LCP.R);
                                    byte AdG = Utility.ClampToByte(CP.G + LCP.G);
                                    byte AdB = Utility.ClampToByte(CP.B + LCP.B);
                                    byte AdA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(AdB, AdG, AdR, AdA);
                                    break;
                                #endregion

                                #region Average
                                case "Average":
                                    byte AR = Utility.ClampToByte((CP.R + LCP.R) / 2);
                                    byte AG = Utility.ClampToByte((CP.G + LCP.G) / 2);
                                    byte AB = Utility.ClampToByte((CP.B + LCP.B) / 2);
                                    byte AA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(AB, AG, AR, AA);
                                    break;
                                #endregion

                                #region Blue
                                case "Blue":
                                    byte BA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(LCP.B, CP.G, CP.R, BA);
                                    break;
                                #endregion

                                #region Clone
                                case "Clone":
                                    byte CR = 0;
                                    byte CG = 0;
                                    byte CB = 0;
                                    byte CA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(CB, CG, CR, CA);
                                    break;
                                #endregion

                                #region Color
                                case "Color":
                                    HsvColor CHSV = new HsvColor();
                                    CHSV.Hue = LCPHSV.Hue;
                                    CHSV.Saturation = LCPHSV.Saturation;
                                    CHSV.Value = CPHSV.Value;
                                    Color CCol = CHSV.ToColor();
                                    byte ColA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(CCol.B, CCol.G, CCol.R, ColA);
                                    break;
                                #endregion

                                #region Color Burn
                                case "Color Burn":
                                    byte CBR = ((LCP.R == 0) ? (byte)0 : Utility.ClampToByte((255 - ((255 - CP.R) << 8 ) / LCP.R)));
                                    byte CBG = ((LCP.G == 0) ? (byte)0 : Utility.ClampToByte((255 - ((255 - CP.G) << 8 ) / LCP.G)));
                                    byte CBB = ((LCP.B == 0) ? (byte)0 : Utility.ClampToByte((255 - ((255 - CP.B) << 8 ) / LCP.B)));
                                    byte CBA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(CBB, CBG, CBR, CBA);
                                    break;
                                #endregion

                                #region Color Dodge
                                case "Color Dodge":
                                    byte CDR = ((LCP.R == 255) ? (byte)255 : Utility.ClampToByte(((CP.R << 8) / (255 - LCP.R))));
                                    byte CDG = ((LCP.G == 255) ? (byte)255 : Utility.ClampToByte(((CP.G << 8) / (255 - LCP.G))));
                                    byte CDB = ((LCP.B == 255) ? (byte)255 : Utility.ClampToByte(((CP.B << 8) / (255 - LCP.B))));
                                    byte CDA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(CDB, CDG, CDR, CDA);
                                    break;
                                #endregion

                                #region Cyan
                                case "Cyan":
                                    byte CyA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(LCP.B, LCP.G, CP.R, CyA);
                                    break;
                                #endregion

                                #region Darken
                                case "Darken":
                                    byte DaR = Utility.ClampToByte(Math.Min(CP.R, LCP.R));
                                    byte DaG = Utility.ClampToByte(Math.Min(CP.G, LCP.G));
                                    byte DaB = Utility.ClampToByte(Math.Min(CP.B, LCP.B));
                                    byte DaA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(DaB, DaG, DaR, DaA);
                                    break;
                                #endregion

                                #region Difference
                                case "Difference":
                                    byte DiR = Utility.ClampToByte(Math.Abs(CP.R - LCP.R));
                                    byte DiG = Utility.ClampToByte(Math.Abs(CP.G - LCP.G));
                                    byte DiB = Utility.ClampToByte(Math.Abs(CP.B - LCP.B));
                                    byte DiA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(DiB, DiG, DiR, DiA);
                                    break;
                                #endregion

                                #region Divide
                                case "Divide":
                                    byte DR = Utility.ClampToByte((CP.R * 255) / (LCP.R + 1));
                                    byte DG = Utility.ClampToByte((CP.G * 255) / (LCP.G + 1));
                                    byte DB = Utility.ClampToByte((CP.B * 255) / (LCP.B + 1));
                                    byte DA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(DB, DG, DR, DA);
                                    break;
                                #endregion

                                #region Exclusion
                                case "Exclusion":
                                    byte ER = Utility.ClampToByte(CP.R + LCP.R - 2 * CP.R * LCP.R / 255);
                                    byte EG = Utility.ClampToByte(CP.G + LCP.G - 2 * CP.G * LCP.G / 255);
                                    byte EB = Utility.ClampToByte(CP.B + LCP.B - 2 * CP.B * LCP.B / 255);
                                    byte EA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(EB, EG, ER, EA);
                                    break;
                                #endregion

                                #region Freeze
                                case "Freeze":
                                    byte FR = 0;
                                    byte FG = 0;
                                    byte FB = 0;

                                    if (LCP.R == 0)
                                    {
                                        FR = 0;
                                    }
                                    else
                                    {
                                        FR = Utility.ClampToByte((255 - Math.Pow((255 - CP.R), 2)) / (LCP.R));
                                    }

                                    if (LCP.G == 0)
                                    {
                                        FG = 0;
                                    }
                                    else
                                    {
                                        FG = Utility.ClampToByte((255 - Math.Pow((255 - CP.G), 2)) / (LCP.G));
                                    }

                                    if (LCP.B == 0)
                                    {
                                        FB = 0;
                                    }
                                    else
                                    {
                                        FB = Utility.ClampToByte((255 - Math.Pow((255 - CP.B), 2)) / (LCP.B));
                                    }

                                    byte FA = Utility.ClampToByte((CP.A + LCP.A) / 2);

                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(FB, FG, FR, FA);
                                    break;
                                #endregion

                                #region Glow
                                case "Glow":
                                    byte GlR = Utility.ClampToByte((CP.R == 255) ? 255 : (LCP.R * LCP.R / (255 - CP.R)));
                                    byte GlG = Utility.ClampToByte((CP.G == 255) ? 255 : (LCP.G * LCP.G / (255 - CP.G)));
                                    byte GlB = Utility.ClampToByte((CP.B == 255) ? 255 : (LCP.B * LCP.B / (255 - CP.B)));
                                    byte GlA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(GlB, GlG, GlR, GlA);
                                    break;
                                #endregion

                                #region Green
                                case "Green":
                                    byte GA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(CP.B, LCP.G, CP.R, GA);
                                    break;
                                #endregion

                                #region Grain Extract
                                case "Grain Extract":
                                    byte GER = Utility.ClampToByte(CP.R - LCP.R + 128);
                                    byte GEG = Utility.ClampToByte(CP.G - LCP.G + 128);
                                    byte GEB = Utility.ClampToByte(CP.B - LCP.B + 128);
                                    byte GEA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(GEB, GEG, GER, GEA);
                                    break;
                                #endregion

                                #region Grain Merge
                                case "Grain Merge":
                                    byte GMR = Utility.ClampToByte(CP.R + LCP.R - 128);
                                    byte GMG = Utility.ClampToByte(CP.G + LCP.G - 128);
                                    byte GMB = Utility.ClampToByte(CP.B + LCP.B - 128);
                                    byte GMA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(GMB, GMG, GMR, GMA);
                                    break;
                                #endregion

                                #region Hard Light
                                case "Hard Light":
                                    byte HLR = 0;
                                    byte HLG = 0;
                                    byte HLB = 0;
                                    byte HLA = Utility.ClampToByte((CP.A + LCP.A) / 2);

                                    if (LCP.R <= 128)
                                    {
                                        HLR = Utility.ClampToByte((2 * CP.R * LCP.R) / 255);
                                    }
                                    else
                                    {
                                        HLR = Utility.ClampToByte(255 - (((255 - CP.R) * (255 - (2 * (LCP.R - 128)))) / 255));
                                    }

                                    if (LCP.G <= 128)
                                    {
                                        HLG = Utility.ClampToByte((2 * CP.G * LCP.G) / 255);
                                    }
                                    else
                                    {
                                        HLG = Utility.ClampToByte(255 - ((((255 - CP.G) * (255 - (2 * (LCP.G - 128))))) / 255));
                                    }

                                    if (LCP.B <= 128)
                                    {
                                        HLB = Utility.ClampToByte((2 * CP.B * LCP.B) / 255);
                                    }
                                    else
                                    {
                                        HLB = Utility.ClampToByte(255 - ((((255 - CP.B) * (255 - (2 * (LCP.G - 128))))) / 255));
                                    }
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(HLB, HLG, HLR, HLA);
                                    break;
                                #endregion

                                #region Hard Mix
                                case "Hard Mix":
                                    byte HMR = 0;
                                    byte HMG = 0;
                                    byte HMB = 0;
                                    byte HMA = Utility.ClampToByte((CP.A + LCP.A) / 2);

                                    if (LCP.R < 255 - CP.R)
                                    {
                                        HMR = 0;
                                    }
                                    else
                                    {
                                        HMR = 255;
                                    }

                                    if (LCP.G < 255 - CP.G)
                                    {
                                        HMG = 0;
                                    }
                                    else
                                    {
                                        HMG = 255;
                                    }

                                    if (LCP.B < 255 - CP.B)
                                    {
                                        HMB = 0;
                                    }
                                    else
                                    {
                                        HMB = 255;
                                    }

                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(HMB, HMG, HMR, HMA);
                                    break;
                                #endregion

                                #region Heat
                                case "Heat":
                                    byte HR = 0;
                                    byte HG = 0;
                                    byte HB = 0;

                                    if (CP.R == 0)
                                    {
                                        HR = 0;
                                    }
                                    else
                                    {
                                        HR = Utility.ClampToByte((255 - Math.Pow((255 - LCP.R), 2)) / (CP.R));
                                    }

                                    if (CP.G == 0)
                                    {
                                        HG = 0;
                                    }
                                    else
                                    {
                                        HG = Utility.ClampToByte((255 - Math.Pow((255 - LCP.G), 2)) / (CP.G));
                                    }

                                    if (CP.B == 0)
                                    {
                                        HB = 0;
                                    }
                                    else
                                    {
                                        HB = Utility.ClampToByte((255 - Math.Pow((255 - LCP.B), 2)) / (CP.B));
                                    }

                                    byte HA = Utility.ClampToByte((CP.A + LCP.A) / 2);

                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(HB, HG, HR, HA);
                                    break;
                                #endregion

                                #region Hue
                                case "Hue":
                                    HsvColor HHSV = new HsvColor();
                                    HHSV.Hue = LCPHSV.Hue;
                                    HHSV.Saturation = CPHSV.Saturation;
                                    HHSV.Value = CPHSV.Value;
                                    Color HueCol = HHSV.ToColor();
                                    byte HueA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(HueCol.B, HueCol.G, HueCol.R, HueA);
                                    break;
                                #endregion

                                #region Interpolation
                                case "Interpolation":
                                    byte IR = Utility.ClampToByte(128 - (64 * Math.Cos(Math.PI * CP.R)) - (64 * Math.Cos(Math.PI * LCP.R)));
                                    byte IG = Utility.ClampToByte(128 - (64 * Math.Cos(Math.PI * CP.G)) - (64 * Math.Cos(Math.PI * LCP.G)));
                                    byte IB = Utility.ClampToByte(128 - (64 * Math.Cos(Math.PI * CP.B)) - (64 * Math.Cos(Math.PI * LCP.B)));
                                    byte IA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(IB, IG, IR, IA);
                                    break;
                                #endregion

                                #region Lighten
                                case "Lighten":
                                    byte LiR = Utility.ClampToByte(Math.Max(CP.R, LCP.R));
                                    byte LiG = Utility.ClampToByte(Math.Max(CP.G, LCP.G));
                                    byte LiB = Utility.ClampToByte(Math.Max(CP.B, LCP.B));
                                    byte LiA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(LiB, LiG, LiR, LiA);
                                    break;
                                #endregion

                                #region Linear Burn
                                case "Linear Burn":
                                    byte LBR = Utility.ClampToByte((CP.R + LCP.R) - 255);
                                    byte LBG = Utility.ClampToByte((CP.G + LCP.G) - 255);
                                    byte LBB = Utility.ClampToByte((CP.B + LCP.B) - 255);
                                    byte LBA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(LBB, LBG, LBR, LBA);
                                    break;
                                #endregion

                                #region Linear Dodge
                                case "Linear Dodge":
                                    byte LDR = Utility.ClampToByte(CP.R + LCP.R);
                                    byte LDG = Utility.ClampToByte(CP.G + LCP.G);
                                    byte LDB = Utility.ClampToByte(CP.B + LCP.B);
                                    byte LDA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(LDB, LDG, LDR, LDA);
                                    break;
                                #endregion

                                #region Linear Light
                                case "Linear Light":
                                    byte LLR = Utility.ClampToByte(CP.R + (2 * LCP.R) - 255);
                                    byte LLG = Utility.ClampToByte(CP.G + (2 * LCP.G) - 255);
                                    byte LLB = Utility.ClampToByte(CP.B + (2 * LCP.B) - 255);
                                    byte LLA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(LLB, LLG, LLR, LLA);
                                    break;
                                #endregion

                                #region Luminosity
                                case "Luminosity":
                                    HsvColor LHSV = new HsvColor();
                                    LHSV.Hue = CPHSV.Hue;
                                    LHSV.Saturation = CPHSV.Saturation;
                                    LHSV.Value = LCPHSV.Value;
                                    Color LCol = LHSV.ToColor();
                                    byte LA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(LCol.B, LCol.G, LCol.R, LA);
                                    break;
                                #endregion

                                #region Magenta
                                case "Magenta":
                                    byte MA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(LCP.B, CP.G, LCP.R, MA);
                                    break;
                                #endregion

                                #region Multiply
                                case "Multiply":
                                    byte MuR = Utility.ClampToByte(CP.R * LCP.R / 255);
                                    byte MuG = Utility.ClampToByte(CP.G * LCP.G / 255);
                                    byte MuB = Utility.ClampToByte(CP.B * LCP.B / 255);
                                    byte MuA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(MuB, MuG, MuR, MuA);
                                    break;
                                #endregion

                                #region Negation
                                case "Negation":
                                    byte NR = Utility.ClampToByte(255 - Math.Abs(255 - CP.R - LCP.R));
                                    byte NG = Utility.ClampToByte(255 - Math.Abs(255 - CP.G - LCP.G));
                                    byte NB = Utility.ClampToByte(255 - Math.Abs(255 - CP.B - LCP.B));
                                    byte NA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(NB, NG, NR, NA);
                                    break;
                                #endregion

                                #region Overlay
                                case "Overlay":
                                    byte OR = (CP.R < 128) ? Utility.ClampToByte(2 * LCP.R * CP.R / 255) : Utility.ClampToByte(255 - 2 * (255 - LCP.R) * (255 - CP.R) / 255);
                                    byte OG = (CP.G < 128) ? Utility.ClampToByte(2 * LCP.G * CP.G / 255) : Utility.ClampToByte(255 - 2 * (255 - LCP.G) * (255 - CP.G) / 255); 
                                    byte OB = (CP.B < 128) ? Utility.ClampToByte(2 * LCP.B * CP.B / 255) : Utility.ClampToByte(255 - 2 * (255 - LCP.B) * (255 - CP.B) / 255);
                                    byte OA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(OB, OG, OR, OA);
                                    break;
                                #endregion

                                #region Phoenix
                                case "Phoenix":
                                    byte PR = Utility.ClampToByte(Math.Min(CP.R, LCP.R) - Math.Max(CP.R, LCP.R) + 255);
                                    byte PG = Utility.ClampToByte(Math.Min(CP.G, LCP.G) - Math.Max(CP.G, LCP.G) + 255);
                                    byte PB = Utility.ClampToByte(Math.Min(CP.B, LCP.B) - Math.Max(CP.B, LCP.B) + 255);
                                    byte PA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(PB, PG, PR, PA);
                                    break;
                                #endregion

                                #region Pin Light
                                case "Pin Light":
                                    byte PLR = 0;
                                    byte PLG = 0;
                                    byte PLB = 0;

                                    if (CP.R < (2 * LCP.R) - 255)
                                    {
                                        PLR = Utility.ClampToByte((2 * LCP.R) - 255);
                                    }

                                    if (CP.G < (2 * LCP.G) - 255)
                                    {
                                        PLG = Utility.ClampToByte((2 * LCP.G) - 255);
                                    }

                                    if (CP.B < (2 * LCP.B) - 255)
                                    {
                                        PLB = Utility.ClampToByte((2 * LCP.B) - 255);
                                    }

                                    if (CP.R > (2 * LCP.R) - 255 && CP.R < 2 * LCP.R)
                                    {
                                        PLR = CP.R;
                                    }

                                    if (CP.G > (2 * LCP.G) - 255 && CP.G < 2 * LCP.G)
                                    {
                                        PLG = CP.G;
                                    }

                                    if (CP.B > (2 * LCP.B) - 255 && CP.B < 2 * LCP.B)
                                    {
                                        PLB = CP.B;
                                    }

                                    if (CP.R > 2 * LCP.R)
                                    {
                                        PLR = Utility.ClampToByte(2 * LCP.R);
                                    }

                                    if (CP.G > 2 * LCP.G)
                                    {
                                        PLG = Utility.ClampToByte(2 * LCP.G);
                                    }

                                    if (CP.B > 2 * LCP.B)
                                    {
                                        PLB = Utility.ClampToByte(2 * LCP.B);
                                    }

                                    byte PLA = Utility.ClampToByte((CP.A + LCP.A) / 2);

                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(PLB, PLG, PLR, PLA);
                                    break;
                                #endregion

                                #region Red
                                case "Red":
                                    byte RA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(CP.B, CP.G, LCP.R, RA);
                                    break;
                                #endregion

                                #region Reflect
                                case "Reflect":
                                    byte ReR = (LCP.R == 255) ? (byte)255 : Utility.ClampToByte((CP.R * CP.R / (255 - LCP.R)));
                                    byte ReG = (LCP.G == 255) ? (byte)255 : Utility.ClampToByte((CP.G * CP.G / (255 - LCP.G)));
                                    byte ReB = (LCP.B == 255) ? (byte)255 : Utility.ClampToByte((CP.B * CP.B / (255 - LCP.B)));
                                    byte ReA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(ReB, ReG, ReR, ReA);
                                    break;
                                #endregion

                                #region Saturation
                                case "Saturation":
                                    HsvColor SHSV = new HsvColor();
                                    SHSV.Hue = CPHSV.Hue;
                                    SHSV.Saturation = LCPHSV.Saturation;
                                    SHSV.Value = CPHSV.Value;
                                    Color SCol = SHSV.ToColor();
                                    byte SA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(SCol.B, SCol.G, SCol.R, SA);
                                    break;
                                #endregion

                                #region Screen
                                case "Screen":
                                    byte ScR = Utility.ClampToByte(255 - (((255 - CP.R) * (255 - LCP.R)) >> 8));
                                    byte ScG = Utility.ClampToByte(255 - (((255 - CP.G) * (255 - LCP.G)) >> 8));
                                    byte ScB = Utility.ClampToByte(255 - (((255 - CP.B) * (255 - LCP.B)) >> 8));
                                    byte ScA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(ScB, ScG, ScR, ScA);
                                    break;
                                #endregion

                                #region Signed Difference
                                case "Signed Difference":
                                    byte SdR = Utility.ClampToByte(((CP.R - LCP.R) / 2) + 128);
                                    byte SdG = Utility.ClampToByte(((CP.G - LCP.G) / 2) + 128);
                                    byte SdB = Utility.ClampToByte(((CP.B - LCP.B) / 2) + 128);
                                    byte SdA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(SdB, SdG, SdR, SdA);
                                    break;
                                #endregion

                                #region Soft Burn
                                case "Soft Burn":
                                    byte SBR = 0;
                                    byte SBG = 0;
                                    byte SBB = 0;
                                    byte SBA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    if (CP.R + LCP.R < 255)
                                    {
                                        if (CP.R == 255)
                                        {
                                            SBR = 0;
                                        }
                                        else
                                        {
                                            SBR = Utility.ClampToByte((128 * LCP.R) / (255 - CP.R));
                                        }
                                    }
                                    else
                                    {
                                        if (LCP.R == 0)
                                        {
                                            SBR = 0;
                                        }
                                        else
                                        {
                                            SBR = Utility.ClampToByte((1 - (128 * (255 - CP.R))) / LCP.R);
                                        }
                                    }

                                    if (CP.G + LCP.G < 255)
                                    {
                                        if (CP.G == 255)
                                        {
                                            SBG = 0;
                                        }
                                        else
                                        {
                                            SBG = Utility.ClampToByte((128 * LCP.G) / (255 - CP.G));
                                        }
                                    }
                                    else
                                    {
                                        if (LCP.G == 0)
                                        {
                                            SBG = 0;
                                        }
                                        else
                                        {
                                            SBG = Utility.ClampToByte((1 - (128 * (255 - CP.G))) / LCP.G);
                                        }
                                    }

                                    if (CP.B + LCP.B < 255)
                                    {
                                        if (CP.B == 255)
                                        {
                                            SBB = 0;
                                        }
                                        else
                                        {
                                            SBB = Utility.ClampToByte((128 * LCP.B) / (255 - CP.B));
                                        }
                                    }
                                    else
                                    {
                                        if (LCP.B == 0)
                                        {
                                            SBB = 0;
                                        }
                                        else
                                        {
                                            SBB = Utility.ClampToByte((1 - (128 * (255 - CP.B))) / LCP.B);
                                        }
                                    }
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(SBB, SBG, SBR, SBA);
                                    break;
                                #endregion

                                #region Soft Dodge
                                case "Soft Dodge":
                                    byte SDR = 0;
                                    byte SDG = 0;
                                    byte SDB = 0;
                                    byte SDA = Utility.ClampToByte((CP.A + LCP.A) / 2);

                                    if (CP.R + LCP.R < 255)
                                    {
                                        if (LCP.R == 255)
                                        {
                                            SDR = 255;
                                        }
                                        else
                                        {
                                            SDR = Utility.ClampToByte((128 * CP.R) / (255 - LCP.R));
                                        }
                                    }
                                    else
                                    {
                                        if (CP.R == 0)
                                        {
                                            SDR = 0;
                                        }
                                        else
                                        {
                                            SDR = Utility.ClampToByte((255 - (128 * (255 - LCP.R))) / CP.R);
                                        }
                                    }

                                    if (CP.G + LCP.G < 255)
                                    {
                                        if (LCP.G == 255)
                                        {
                                            SDG = 255;
                                        }
                                        else
                                        {
                                            SDG = Utility.ClampToByte((128 * CP.G) / (255 - LCP.G));
                                        }
                                    }
                                    else
                                    {
                                        if (CP.G == 0)
                                        {
                                            SDG = 0;
                                        }
                                        else
                                        {
                                            SDG = Utility.ClampToByte((255 - (128 * (255 - LCP.G))) / CP.G);
                                        }
                                    }

                                    if (CP.B + LCP.B < 255)
                                    {
                                        if (LCP.B == 255)
                                        {
                                            SDB = 255;
                                        }
                                        else
                                        {
                                            SDB = Utility.ClampToByte((128 * CP.B) / (255 - LCP.B));
                                        }
                                    }
                                    else
                                    {
                                        if (CP.B == 0)
                                        {
                                            SDB = 0;
                                        }
                                        else
                                        {
                                            SDB = Utility.ClampToByte((255 - (128 * (255 - LCP.B))) / CP.B);
                                        }
                                    }
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(SDB, SDG, SDR, SDA);
                                    break;
                                #endregion

                                #region Soft Light
                                case "Soft Light":
                                    byte SLR = Utility.ClampToByte((LCP.R < 128) ? (2 * ((CP.R >> 1) + 64)) * ((float)LCP.R / 255) : (255 - (2 * (255 - ((CP.R >> 1) + 64)) * (float)(255 - LCP.R) / 255)));
                                    byte SLG = Utility.ClampToByte((LCP.G < 128) ? (2 * ((CP.G >> 1) + 64)) * ((float)LCP.G / 255) : (255 - (2 * (255 - ((CP.G >> 1) + 64)) * (float)(255 - LCP.G) / 255)));
                                    byte SLB = Utility.ClampToByte((LCP.B < 128) ? (2 * ((CP.B >> 1) + 64)) * ((float)LCP.B / 255) : (255 - (2 * (255 - ((CP.B >> 1) + 64)) * (float)(255 - LCP.B) / 255)));
                                    byte SLA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(SLB, SLG, SLR, SLA);
                                    break;
                                #endregion

                                #region Stamp
                                case "Stamp":
                                    byte StR = Utility.ClampToByte(CP.R + (2 * LCP.R) - 255);
                                    byte StG = Utility.ClampToByte(CP.G + (2 * LCP.G) - 255);
                                    byte StB = Utility.ClampToByte(CP.B + (2 * LCP.B) - 255);
                                    byte StA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(StB, StG, StR, StA);
                                    break;
                                #endregion

                                #region Vivid Light
                                case "Vivid Light":
                                    byte VLR = 0;
                                    byte VLG = 0;
                                    byte VLB = 0;
                                    byte VLA = Utility.ClampToByte((CP.A + LCP.A) / 2);

                                    if (LCP.R > 128)
                                    {
                                        VLR = Utility.ClampToByte(CP.R + 2 * (LCP.R - 128));
                                    }
                                    else
                                    {
                                        VLR = Utility.ClampToByte(CP.R + 2 * LCP.R - 255);
                                    }

                                    if (LCP.G > 128)
                                    {
                                        VLG = Utility.ClampToByte(CP.G + 2 * (LCP.G - 128));
                                    }
                                    else
                                    {
                                        VLG = Utility.ClampToByte(CP.G + 2 * LCP.G - 255);
                                    }

                                    if (LCP.B > 128)
                                    {
                                        VLB = Utility.ClampToByte(CP.B + 2 * (LCP.B - 128));
                                    }
                                    else
                                    {
                                        VLB = Utility.ClampToByte(CP.B + 2 * LCP.B - 255);
                                    }
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(VLB, VLG, VLR, VLA);
                                    break;
                                #endregion

                                #region Yellow
                                case "Yellow":
                                    byte YA = Utility.ClampToByte((CP.A + LCP.A) / 2);
                                    dstArgs.Surface[x, y] = ColorBgra.FromBgra(CP.B, LCP.G, LCP.R, YA);
                                    break;
                                #endregion
                            }
                        }
                    }
                }
            }
        }
    }
}
