private void Update()
    {
        DFTMat.EnableKeyword("DFT_FORWARD");
        DFTMat.DisableKeyword("DFT_INVERSE");

        DFTMat.EnableKeyword("DFT_HORZ");
        DFTMat.DisableKeyword("DFT_VERT");

        DFTMat.SetInt("u_SamplesSizeX", SourceTex.width);
        DFTMat.SetInt("u_SamplesSizeY", SourceTex.height);
        DFTMat.SetVector("_MainTex_TexelSize", SourceTex.texelSize);
        DFTMat.SetTexture("_MainTex", SourceTex);

        Graphics.Blit(SourceTex, destTex, DFTMat);
        DFT_GPU.CopyTo(destTex, intermediateTex);

        //DFTMat.EnableKeyword("DFT_VERT");
        //DFTMat.DisableKeyword("DFT_HORZ");
        //DFTMat.SetTexture("_MainTex", destTex);

        //Graphics.Blit(intermediateTex, destTex, DFTMat);
    }
        private void OnGUI()
        {
            ScrollPos = GUILayout.BeginScrollView(ScrollPos);

            ShowSection_Forward = EditorGUILayout.Foldout(ShowSection_Forward, "Forward DFT");
            if (ShowSection_Forward)
            {
                if (GUILayout.Button("Load Source Image"))
                {
                    string path = EditorUtility.OpenFilePanelWithFilters(
                        "Choose the image file", Application.dataPath,
                        new string[] { "PNG", "png", "JPEG", "jpg", "JPEG", "jpeg" });
                    if (path.Length > 0)
                    {
                        InitDisplayTex(ref ForwardDFT_Src);

                        ForwardDFT_Src.LoadImage(File.ReadAllBytes(path));
                        ForwardDFT_Src.Apply(false, false);
                    }
                }
                if (ForwardDFT_Src != null)
                {
                    var texPos = GUILayoutUtility.GetRect(Math.Min(512, ForwardDFT_Src.width),
                                                          Math.Min(512, ForwardDFT_Src.height));
                    GUI.DrawTexture(texPos, ForwardDFT_Src, ScaleMode.ScaleToFit);

                    GUILayout.Space(15.0f);

                    if (GUILayout.Button("Run Forward DFT"))
                    {
                        var samples = Algo2D.ToSamples(ForwardDFT_Src);
                        //var dftResults = Algo2D.Forward(samples);

                        var dftResults = new Complex[samples.GetLength(0), samples.GetLength(1)];
                        DFT_GPU.Forward((uint)samples.GetLength(0), (uint)samples.GetLength(1),
                                        (x, y) => samples[x, y],
                                        (x, y, c) => dftResults[x, y] = c);

                        InitDisplayTex(ref ForwardDFT_Dest);
                        Algo2D.ToTex(dftResults, ForwardDFT_Dest);
                    }
                    if (ForwardDFT_Dest != null)
                    {
                        texPos = GUILayoutUtility.GetRect(Math.Min(256, ForwardDFT_Dest.width),
                                                          Math.Min(256, ForwardDFT_Dest.height));
                        GUI.DrawTexture(texPos, ForwardDFT_Dest, ScaleMode.ScaleToFit);

                        GUILayout.BeginHorizontal();
                        if (GUILayout.Button("Shift"))
                        {
                            ForwardDFT_Dest.Filter(
                                (x, y, c, pixels) =>
                            {
                                x = (x + (ForwardDFT_Dest.width / 2)) % ForwardDFT_Dest.width;
                                y = (y + (ForwardDFT_Dest.height / 2)) % ForwardDFT_Dest.height;
                                return(pixels[x + (y * ForwardDFT_Dest.width)]);
                            });
                        }
                        if (GUILayout.Button("Map to [0, 1]"))
                        {
                            //A continuous 1:1 mapping from (-inf, +inf) to (0, 1) is:
                            //    1/(1+e^(-x))
                            ForwardDFT_Dest.Filter(f => (1.0f / (1.0f + Mathf.Exp(-f))));
                        }
                        if (GUILayout.Button("Map to [-inf, +inf]"))
                        {
                            //The inverse of the above mapping is:
                            //    ln(-x/(x-1))
                            ForwardDFT_Dest.Filter(f => Mathf.Log(-f / (f - 1)));
                        }
                        GUILayout.EndHorizontal();

                        GUILayout.BeginHorizontal();
                        ScaleVal = EditorGUILayout.FloatField("Log Scale: ", ScaleVal);
                        if (GUILayout.Button("Forward"))
                        {
                            ForwardDFT_Dest.Filter(f => (ScaleVal * Mathf.Log(f + 1)));
                        }
                        if (GUILayout.Button("Invert"))
                        {
                            //Use the inverse of the "forward" scale.
                            ForwardDFT_Dest.Filter(f => (Mathf.Exp(f / ScaleVal) - 1.0f));
                        }
                        GUILayout.EndHorizontal();
                    }

                    GUILayout.Space(15.0f);

                    if (ForwardDFT_Dest != null)
                    {
                        if (GUILayout.Button("Save Forward DFT"))
                        {
                            string path = EditorUtility.SaveFilePanel("Choose the location",
                                                                      Application.dataPath,
                                                                      "DFT", "png");
                            if (path.Length > 0)
                            {
                                File.WriteAllBytes(path, ForwardDFT_Dest.EncodeToPNG());
                            }
                        }
                    }
                }
            }

            GUILayout.Space(30.0f);

            ShowSection_Inverse = EditorGUILayout.Foldout(ShowSection_Inverse, "Inverse DFT");
            if (ShowSection_Inverse)
            {
                GUILayout.BeginHorizontal();
                if (GUILayout.Button("Load DFT Img"))
                {
                    string path = EditorUtility.OpenFilePanelWithFilters(
                        "Choose the DFT image file", Application.dataPath,
                        new string[] { "JPEG", "jpeg", "JPEG", "jpg", "PNG", "png" });
                    if (path.Length > 0)
                    {
                        InitDisplayTex(ref InverseDFT_Src);

                        InverseDFT_Src.LoadImage(File.ReadAllBytes(path));
                        InverseDFT_Src.Apply(false, false);
                    }
                }
                if (ForwardDFT_Dest != null && GUILayout.Button("Copy DFT Img"))
                {
                    InitDisplayTex(ref InverseDFT_Src);
                    ForwardDFT_Dest.CopyTo(InverseDFT_Src);
                }
                GUILayout.EndHorizontal();

                if (InverseDFT_Src != null)
                {
                    var texPos = GUILayoutUtility.GetRect(Math.Min(256, InverseDFT_Src.width),
                                                          Math.Min(256, InverseDFT_Src.height));
                    GUI.DrawTexture(texPos, InverseDFT_Src, ScaleMode.ScaleToFit);

                    GUILayout.BeginHorizontal();
                    if (GUILayout.Button("Map to [0, 1]"))
                    {
                        //A continuous 1:1 mapping from (-inf, +inf) to (0, 1) is:
                        //    1/(1+e^(-x))
                        InverseDFT_Src.Filter(f => (1.0f / (1.0f + Mathf.Exp(-f))));
                    }
                    if (GUILayout.Button("Map to [-inf, +inf]"))
                    {
                        //The inverse of the above mapping is:
                        //    ln(-x/(x-1))
                        InverseDFT_Src.Filter(f => Mathf.Log(-f / (f - 1)));
                    }
                    GUILayout.EndHorizontal();


                    GUILayout.Space(15.0f);

                    if (GUILayout.Button("Run Inverse DFT"))
                    {
                        var samples = Algo2D.ToSamples(InverseDFT_Src);
                        var results = Algo2D.Inverse(samples);

                        InitDisplayTex(ref InverseDFT_Dest);
                        Algo2D.ToTex(results, InverseDFT_Dest);
                    }
                    if (InverseDFT_Dest != null)
                    {
                        texPos = GUILayoutUtility.GetRect(Math.Min(512, InverseDFT_Dest.width),
                                                          Math.Min(512, InverseDFT_Dest.height));
                        GUI.DrawTexture(texPos, InverseDFT_Dest, ScaleMode.ScaleToFit);
                    }

                    GUILayout.Space(15.0f);

                    if (InverseDFT_Dest != null)
                    {
                        if (GUILayout.Button("Save Inverse DFT"))
                        {
                            string path = EditorUtility.SaveFilePanel("Choose the location",
                                                                      Application.dataPath,
                                                                      "DFT", "png");
                            if (path.Length > 0)
                            {
                                File.WriteAllBytes(path, InverseDFT_Dest.EncodeToPNG());
                            }
                        }
                    }
                }
            }

            GUILayout.EndScrollView();
        }
        public override void OnInspectorGUI()
        {
            base.OnInspectorGUI();

            var script = (DFTTestScript)target;

            GUILayout.Space(20.0f);

            //Button to sample from time signal.
            GUILayout.BeginHorizontal();
            NSamples = EditorGUILayout.IntField(NSamples);
            if (NSamples < 2)
            {
                NSamples = 2;
            }
            if (GUILayout.Button("Sample " + NSamples.ToString() + " points"))
            {
                timeSamples = DFTTestScript.GetDiscreteTimeSignal(script.TimeSignal, NSamples);
                var newKeys = new Keyframe[timeSamples.Length];

                float timeIncrement = 1.0f / (timeSamples.Length - 1);
                for (int sampleI = 0; sampleI < timeSamples.Length; ++sampleI)
                {
                    newKeys[sampleI] = new Keyframe(sampleI * timeIncrement, timeSamples[sampleI]);
                }

                script.SampledTimeSignal.keys = newKeys;
                script.CloneCurve(ref script.SampledTimeSignal);
                Repaint();
            }
            GUILayout.EndHorizontal();

            useGPU = GUILayout.Toggle(useGPU, "Use GPU");

            //Button to perform forward DFT.
            if (GUILayout.Button("Perform Forward DFT"))
            {
                if (useGPU)
                {
                    dftResults = new Complex[timeSamples.Length];
                    string errMsg = DFT_GPU.Forward((uint)timeSamples.Length, 1,
                                                    (x, y) => timeSamples[x],
                                                    (x, y, c) => dftResults[x] = c);
                    if (errMsg.Length > 0)
                    {
                        Debug.LogError(errMsg);
                    }
                }
                else
                {
                    Complex[,] _timeSamples = new Complex[timeSamples.Length, 1];
                    for (int i = 0; i < timeSamples.Length; ++i)
                    {
                        _timeSamples[i, 0] = new Complex(timeSamples[i], 0.0f);
                    }

                    var _dftResults = Algo2D.Forward(_timeSamples);

                    dftResults = new Complex[timeSamples.Length];
                    for (int i = 0; i < timeSamples.Length; ++i)
                    {
                        dftResults[i] = _dftResults[i, 0];
                    }

                    //dftResults = Algo1D.Forward(timeSamples.Select(f => new Complex(f, 0.0f)).ToArray());
                }

                var newKeys_Cosine = new Keyframe[dftResults.Length];
                var newKeys_Sine   = new Keyframe[dftResults.Length];

                for (int sampleI = 0; sampleI < dftResults.Length; ++sampleI)
                {
                    newKeys_Cosine[sampleI] = new Keyframe(sampleI, dftResults[sampleI].R);
                    newKeys_Sine[sampleI]   = new Keyframe(sampleI, dftResults[sampleI].I);
                }

                script.CosFrequencySignal.keys = newKeys_Cosine;
                script.SinFrequencySignal.keys = newKeys_Sine;
                script.CloneCurve(ref script.CosFrequencySignal);
                script.CloneCurve(ref script.SinFrequencySignal);
            }

            //Button to perform inverse DFT.
            if (GUILayout.Button("Perform inverse DFT"))
            {
                float[] results = null;
                if (useGPU)
                {
                    results = new float[dftResults.Length];
                    string errMsg = DFT_GPU.Inverse((uint)results.Length, 1,
                                                    (x, y) => dftResults[x],
                                                    (x, y, c) => results[x] = c);
                    if (errMsg.Length > 0)
                    {
                        Debug.LogError(errMsg);
                    }
                }
                else
                {
                    Complex[,] _dftResults = new Complex[dftResults.Length, 1];
                    for (int i = 0; i < dftResults.Length; ++i)
                    {
                        _dftResults[i, 0] = dftResults[i];
                    }

                    var _results = Algo2D.Inverse(_dftResults);

                    results = new float[dftResults.Length];
                    for (int i = 0; i < results.Length; ++i)
                    {
                        results[i] = _results[i, 0].R;
                    }

                    //results = Algo1D.Inverse(dftResults).Select(c => c.R).ToArray();
                }

                var   newKeys       = new Keyframe[results.Length];
                float timeIncrement = 1.0f / (results.Length - 1);
                for (int sampleI = 0; sampleI < results.Length; ++sampleI)
                {
                    newKeys[sampleI] = new Keyframe(sampleI * timeIncrement, results[sampleI]);
                }

                script.ReconstructedTimeSignal.keys = newKeys;
                script.CloneCurve(ref script.ReconstructedTimeSignal);
            }
        }