Exemplo n.º 1
0
    ///
    public void OnGUI()
    {
        GUILayout.BeginArea(new Rect(0, 0, position.width, position.height));
        uiScroll = EditorGUILayout.BeginScrollView(uiScroll, false, false, GUILayout.MinWidth(300), GUILayout.MaxWidth(position.width));

        float rightPad     = 23;
        float minWidth     = 315;
        float sectionWidth = position.width - rightPad;
        float logoSize     = 128;

        Rect logoRect = EditorGUILayout.BeginVertical(); {
            GUILayout.Space(32);
            drawSkyshopLogo(sectionWidth - logoSize, logoRect.y, logoSize);
        } EditorGUILayout.EndVertical();

        uiHideDuringCompute = false;        //EditorGUILayout.Toggle("Hide UI During Compute",uiHideDuringCompute);
        if (!uiHideDuringCompute || !ps.isPlaying())
        {
            // INPUT REF
            EditorGUILayout.BeginVertical(); {
                inSKY.previewWidth = Mathf.Max(328, (int)sectionWidth - 2);
                inSKY.drawGUI();
                outSIM.inputPath = outSKY.inputPath = inSKY.fullPath;
            } EditorGUILayout.EndVertical();

            // OUTPUT REF
            EditorGUILayout.BeginVertical("HelpBox", GUILayout.Width(sectionWidth), GUILayout.MinWidth(minWidth)); {
                uiRefOptions = EditorGUILayout.Foldout(uiRefOptions, "Output Cubemaps");
                if (uiRefOptions)
                {
                    outSKY.drawGUI(); EditorGUILayout.Space();
                    outSIM.drawGUI(); EditorGUILayout.Space();

                    EditorGUILayout.BeginHorizontal(); {
                        string newTip = "Create a new cubemap assets for each output slot and adds them to the project.";
                        if (GUILayout.Button(new GUIContent("New All ", newTip), GUILayout.Width(70), GUILayout.Height(18)))
                        {
                            outSKY.newCube();
                            outSIM.newCube();
                        }
                        string findTip = "Search project for all existing output cubemaps by input panorama name.";
                        if (GUILayout.Button(new GUIContent("Find All", findTip), GUILayout.Width(70), GUILayout.Height(18)))
                        {
                            outSKY.find();
                            outSIM.find();
                        }
                        string clearTip = "Deselect all target cubemaps from output slots.";
                        if (GUILayout.Button(new GUIContent("Clear All", clearTip), GUILayout.Width(80), GUILayout.Height(18)))
                        {
                            outSKY.clear();
                            outSIM.clear();
                        }
                        string reloadTip = "Reload all input and output slot textures and generate preview images for them.";
                        EditorGUI.BeginDisabledGroup(outSKY.fullPath.Length == 0 && outSIM.fullPath.Length == 0 && inSKY.fullPath.Length == 0);
                        {
                            if (GUILayout.Button(new GUIContent("Reload All", reloadTip), GUILayout.Width(85), GUILayout.Height(18)))
                            {
                                outSKY.reloadReference();
                                outSIM.reloadReference();
                                inSKY.reloadReference();
                            }
                        }
                        EditorGUI.EndDisabledGroup();
                    } EditorGUILayout.EndHorizontal();

                    EditorGUILayout.BeginHorizontal(); {
                        string   editLabel = "";
                        string   editTip   = "";
                        mset.Sky editSky   = null;

                        if (uiSelectedSky)
                        {
                            editSky   = uiSelectedSky;
                            editLabel = "Edit Selected";
                            editTip   = "Select cubemaps from the selected Sky as output targets.";
                        }
                        else
                        {
                            mset.SkyManager mgr = mset.SkyManager.Get();
                            if (mgr)
                            {
                                editSky = mgr.GlobalSky;
                            }
                            else
                            {
                                editSky = null;
                            }
                            editLabel = "Edit Global";
                            editTip   = "Select cubemaps from the current viewport Sky as output targets.";
                        }
                        EditorGUI.BeginDisabledGroup(editSky == null);
                        if (GUILayout.Button(new GUIContent(editLabel, editTip), GUILayout.Width(95), GUILayout.Height(32)))
                        {
                            if (editSky)
                            {
                                outSKY.HDR = editSky.HDRSky;
                                outSIM.HDR = editSky.HDRSpec;

                                if (editSky.SkyboxCube)
                                {
                                    outSKY.setReference(AssetDatabase.GetAssetPath(editSky.SkyboxCube), false, true);
                                }
                                else
                                {
                                    outSKY.clear();
                                }

                                if (editSky.SpecularCube)
                                {
                                    outSIM.setReference(AssetDatabase.GetAssetPath(editSky.SpecularCube), true, true);
                                }
                                else
                                {
                                    outSIM.clear();
                                }
                            }
                        }
                        EditorGUI.EndDisabledGroup();

                        string applyTip = "Change the selected Sky object to use Skyshop's current output cubemaps.";
                        EditorGUI.BeginDisabledGroup(uiSelectedSky == null);
                        if (GUILayout.Button(new GUIContent("Apply to Selected", applyTip), GUILayout.Width(120), GUILayout.Height(32)))
                        {
                            if (uiSelectedSky)
                            {
                                mset.EditorUtil.RegisterUndo(uiSelectedSky, "Apply to Selected Sky");
                                uiSelectedSky.SpecularCube    = outSIM.cube;
                                uiSelectedSky.SkyboxCube      = outSKY.cube;
                                uiSelectedSky.MasterIntensity = 1f;
                                uiSelectedSky.SkyIntensity    = 1f;
                                uiSelectedSky.DiffIntensity   = 1f;
                                uiSelectedSky.SpecIntensity   = 1f;
                                uiSelectedSky.HDRSky          = outSKY.HDR;
                                uiSelectedSky.HDRSpec         = outSIM.HDR;

                                SceneView.RepaintAll();
                            }
                        }
                        EditorGUI.EndDisabledGroup();

                        string addTip = "Create a new Sky object in the scene and assigns Skyshop's current output cubemaps to it.";
                        if (GUILayout.Button(new GUIContent("Add to Scene", addTip), GUILayout.Width(95), GUILayout.Height(32)))
                        {
                            mset.Sky skyScript = addSky(this.inSKY.skyName);
                            if (skyScript)
                            {
                                skyScript.SpecularCube    = outSIM.cube;
                                skyScript.SkyboxCube      = outSKY.cube;
                                skyScript.MasterIntensity = 1f;
                                skyScript.SkyIntensity    = 1f;
                                skyScript.DiffIntensity   = 1f;
                                skyScript.SpecIntensity   = 1f;
                                skyScript.HDRSky          = outSKY.HDR;
                                skyScript.HDRSpec         = outSIM.HDR;
                                skyScript.Apply();                                 //Add to Scene
                                SceneView.RepaintAll();
                            }
                        }
                    } EditorGUILayout.EndHorizontal();
                    EditorGUILayout.Space();
                }                // end if uiRefOptions
            } EditorGUILayout.EndVertical();

            // BASIC
            string tipExposure = "A multiplier on all the pixels in the Input Panorama during computation. Use for uniform brightness adjustment of results.";
            string tipQuality  = "Changes some advanced options to balance between image quality and computation speed.";

            EditorGUILayout.BeginVertical("HelpBox", GUILayout.Width(sectionWidth), GUILayout.MinWidth(minWidth)); {
                uiBasicOptions = EditorGUILayout.Foldout(uiBasicOptions, "Basic Options");
                if (uiBasicOptions)
                {
                    float newExposure = EditorGUILayout.FloatField(new GUIContent("Baked Exposure", "Baked Exposure -\n" + tipExposure), uiExposure, GUILayout.Width(300));
                    newExposure = Mathf.Max(0.0f, newExposure);
                    if (newExposure != uiExposure)
                    {
                        mset.EditorUtil.RegisterUndo(this, "Change Exposure");
                        uiExposure = newExposure;
                    }

                    mset.Quality newQuality = (mset.Quality)EditorGUILayout.EnumPopup(
                        new GUIContent("Quality", "Quality -\n" + tipQuality),
                        (mset.Quality)uiConvoQuality,
                        GUILayout.Width(300)
                        );

                    if (newQuality != uiConvoQuality)
                    {
                        mset.EditorUtil.RegisterUndo(this, "Change Quality");
                        uiConvoQuality = newQuality;
                        switch (uiConvoQuality)
                        {
                        case mset.Quality.ultra:        uiConvoSize = 64; break;

                        case mset.Quality.high:         uiConvoSize = 32; break;

                        case mset.Quality.medium:       uiConvoSize = 16; break;

                        case mset.Quality.low:          uiConvoSize = 8; break;
                        }
                    }

                    /*
                     * uiCubeSize = (TexSize)EditorGUILayout.EnumPopup(
                     *      new GUIContent("Output Size (cube)","Output Size -\n"+tipCubeSize),
                     *      (CubeSize)uiCubeSize,
                     *      GUILayout.Width(300)
                     * );*/

                    EditorGUILayout.Space();
                }                // end if uiBasicOptions
            } EditorGUILayout.EndVertical();

            // PRO MOVES
            string tipConvoSize    = "Resolution the input panorama is downsampled to for convolution, must be power of 2.\n\nWarning: High resolutions can lead to VERY long computation times!";
            string tipMipChain     = "If enabled, different specular gloss exponents are computed and stored in each mipmap level of the Specular Output cube.\n\nThis must be enabled for Gloss Maps to function in Marmoset Shaders.";
            string tipExponent     = "Gloss exponent used in computing the Specular Output cubemap. Value must be a power of 2, lower values result in a blurrier cubemap. Only available when \"Build Mip Chains\" is disabled.";
            string tipMaxExponent  = "Highest gloss exponent use in the specular mip chain. Other exponents in the chain are generated from this value.";
            string tipExponents    = "Displays a list of the specular gloss exponents used in the various mip levels of the Specular Output cube.";
            string tipResponsiveUI = "Enable if Unity is too unresponsive during computation. Will slow overall computation time.";
            string tipReflection   = "Highest gloss level in the specular mip chain is a polished mirror reflection pulled from the input panorama itself.";

            EditorGUILayout.BeginVertical("HelpBox", GUILayout.Width(sectionWidth), GUILayout.MinWidth(minWidth));
            {
                uiAdvancedOptions = EditorGUILayout.Foldout(uiAdvancedOptions, "Advanced Options");
                if (uiAdvancedOptions)
                {
                    int newConvoSize = EditorGUILayout.IntField(
                        new GUIContent("Convolution Size", "Convolution Size -\n" + tipConvoSize),
                        uiConvoSize,
                        GUILayout.Width(300)
                        );

                    if (newConvoSize < 2)
                    {
                        newConvoSize = 2;
                    }
                    newConvoSize += newConvoSize % 2;

                    if (newConvoSize != uiConvoSize)
                    {
                        mset.EditorUtil.RegisterUndo(this, "Change Convolution Size");
                        uiConvoSize    = newConvoSize;
                        uiConvoQuality = mset.Quality.custom;
                        switch (uiConvoSize)
                        {
                        case 8:  uiConvoQuality = mset.Quality.low; break;

                        case 16: uiConvoQuality = mset.Quality.medium; break;

                        case 32: uiConvoQuality = mset.Quality.high; break;

                        case 64: uiConvoQuality = mset.Quality.ultra; break;
                        }
                        ;
                    }
                    EditorGUILayout.Space();
                    mset.CubemapGUI.drawStaticGUI();

                    bool newMipChain = EditorGUILayout.Toggle(new GUIContent("Build Specular Mip Chain", "Specular Mip Chains -\n" + tipMipChain), uiMipChain);
                    if (newMipChain != uiMipChain)
                    {
                        mset.EditorUtil.RegisterUndo(this, "Toggle Specular Mip Chain");
                        uiMipChain = newMipChain;
                    }
                    if (uiMipChain)
                    {
                        bool newRefInSIM = EditorGUILayout.Toggle(new GUIContent("Highest Mip is Reflection", "Highest Mip is Reflection -\n" + tipReflection), uiReflectionInSIM);
                        if (newRefInSIM != uiReflectionInSIM)
                        {
                            mset.EditorUtil.RegisterUndo(this, "Toggle Mip Chain Reflection");
                            uiReflectionInSIM = newRefInSIM;
                        }
                        int newExponent = EditorGUILayout.IntField(
                            new GUIContent("Max Specular Exponent", "Specular Exponent -\n" + tipMaxExponent),
                            uiExponent,
                            GUILayout.Width(300)
                            );
                        newExponent = Mathf.Max(1, newExponent);
                        if (newExponent != uiExponent)
                        {
                            mset.EditorUtil.RegisterUndo(this, "Change Specular Exponent");
                            uiExponent = newExponent;
                        }

                        EditorGUI.BeginDisabledGroup(true);
                        string mipString;
                        if (uiReflectionInSIM)
                        {
                            mipString = "mirror";
                        }
                        else
                        {
                            mipString = uiExponent.ToString();
                        }
                        for (int i = 1; i < 4; ++i)
                        {
                            if ((1 << i) < uiExponent)
                            {
                                mipString += ", ";
                                mipString += (uiExponent >> i);
                                if (i == 3)
                                {
                                    mipString += "...";
                                }
                            }
                        }
                        EditorGUILayout.TextField(new GUIContent("Specular Exponents", "Specular Exponents -\n" + tipExponents), mipString, GUILayout.Width(300));
                        EditorGUI.EndDisabledGroup();
                    }
                    else
                    {
                        EditorGUI.BeginDisabledGroup(true);
                        EditorGUILayout.Toggle(new GUIContent("Highest Mip is Reflection", "Highest Mip is Reflection -\n" + tipReflection), false);
                        EditorGUI.EndDisabledGroup();
                        int newExponent = EditorGUILayout.IntField(
                            new GUIContent("Specular Exponent", "Specular Exponent -\n" + tipExponent),
                            uiExponent,
                            GUILayout.Width(300)
                            );
                        newExponent = Mathf.Max(1, newExponent);
                        if (newExponent != uiExponent)
                        {
                            mset.EditorUtil.RegisterUndo(this, "Change Specular Exponent");
                            uiExponent = newExponent;
                        }
                    }
                    EditorGUILayout.Space();

                    //TODO: Will anyone ever want this? Marmoset shaders need gamma compression as does sRGB sampling.
                    uiGammaCompress = true;

                    /*
                     * uiGammaCompress = EditorGUILayout.Toggle(new GUIContent(
                     *      "Gamma-Compress RGBM",
                     *      "Gamma-Compress RGBM -\nIf enabled, a gamma of 1/2.2 is applied to HDR data before it is encoded as RGBM. This adds dynamic range but also shader complexity. Leave enabled for Marmoset shaders."),
                     *      uiGammaCompress);
                     */

                    uiResponsiveUI = stepsPerFrame <= 1024 * 16;
                    uiResponsiveUI = EditorGUILayout.Toggle(new GUIContent("Keep UI Responsive", "Keep UI Responsive -\n" + tipResponsiveUI), uiResponsiveUI);
                    ulong newStepsPerFrame = stepsPerFrame;
                    if (uiResponsiveUI)
                    {
                        newStepsPerFrame = 1024 * 16;
                    }
                    else
                    {
                        newStepsPerFrame = 1024 * 256;
                    }

                    if (newStepsPerFrame != stepsPerFrame)
                    {
                        mset.EditorUtil.RegisterUndo(this, "Toggle Responsive UI");
                        stepsPerFrame = newStepsPerFrame;
                    }
                    EditorGUILayout.Space();


                    if (GUILayout.Button("Reset to Default", GUILayout.Width(120)))
                    {
                        uiConvoSize       = Mathf.Min(uiConvoSize, 16);
                        uiMipChain        = true;
                        uiReflectionInSIM = true;
                        uiResponsiveUI    = false;
                        uiGammaCompress   = true;
                        uiExponent        = 512;
                    }
                    EditorGUILayout.Space();
                }
            } EditorGUILayout.EndVertical();

            EditorGUILayout.Space();
            EditorGUILayout.Space();
        }

        //GENERATE
        bool generateGPU = false;
        bool generate    = false;
        bool cancel      = false;

        EditorGUILayout.BeginHorizontal(); {
            bool   hasPro        = UnityEditorInternal.InternalEditorUtility.HasPro();
            string tipGPUCompute = "Generates skybox and specular cubemaps. Specular convolution is performed on the GPU for greater speed and quality.\n\nNote: a different convolution equation is used, results may vary from CPU compute.";
            if (hasPro == false)
            {
                tipGPUCompute = "Requires Unity Pro :-(\n\n" + tipGPUCompute;
            }

            bool playing = ps.isPlaying();
            //if( ps.isPlaying() ) {
            //	cancel = GUILayout.Button("Abort", GUILayout.Width(130), GUILayout.Height(50));
            //} else
            {
                bool valid = true;
                if (inSKY.input == null)
                {
                    valid = false;
                }
                if (outSKY.cube == null && outSIM.cube == null)
                {
                    valid = false;
                }
                EditorGUILayout.BeginVertical();
                EditorGUI.BeginDisabledGroup(!valid);
                generate = GUILayout.Button(playing ? "Cancel" : "Compute", GUILayout.Width(130), GUILayout.Height(50));
                if (playing)
                {
                    cancel = generate; generate = false;
                }
                EditorGUI.EndDisabledGroup();

                EditorGUI.BeginDisabledGroup(!valid || !hasPro || playing);
                generateGPU = GUILayout.Button(new GUIContent("GPU Compute", "GPU Compute -\n" + tipGPUCompute), GUILayout.Width(130), GUILayout.Height(50));
                EditorGUI.EndDisabledGroup();
                EditorGUILayout.EndVertical();

                if (!valid)
                {
                    EditorGUILayout.BeginVertical();
                    if (inSKY.input == null)
                    {
                        EditorGUILayout.HelpBox("Input Panorama is missing.", MessageType.Error);
                    }
                    if (outSKY.cube == null && outSIM.cube == null)
                    {
                        EditorGUILayout.HelpBox("An Output Cubemap is needed.", MessageType.Error);
                    }
                    EditorGUILayout.EndVertical();
                }
            }
        } EditorGUILayout.EndHorizontal();
        if (cancel)
        {
            ps.pause();
            Repaint();

            inSKY.locked          =
                outSKY.locked     =
                    outSIM.locked = false;
            inSKY.updateBuffers();
        }

        progressRect       = GUILayoutUtility.GetRect(sectionWidth - 4, 16);
        progressRect.width = sectionWidth;
        progressRect.x     = 4;
        progressRect.y    += 2;

        //uiShowPreview = true;
        if (uiShowPreview)
        {
            EditorGUILayout.LabelField("Convolution Preview");
            float previewWidth  = position.width - rightPad;
            float previewHeight = previewWidth * 0.5f;
            mset.EditorUtil.GUILayout.drawTexture(4, 0, previewWidth, previewHeight, "", uiConvoPreview, false);
        }

        if (generate)
        {
            startConvo();
            ps.repaintMetric.begin();
        }

        if (generateGPU)
        {
            this.startConvoGPU();
            this.finishSKY();

            if (outSIM.cube)
            {
                Cubemap tempCube = this.outSKY.cube;
                if (tempCube == null)
                {
                    tempCube = new Cubemap(outSIM.cube.width, TextureFormat.ARGB32, false);
                    ps.IN.resampleToCube(ref tempCube, 0, outSIM.colorMode, true, uiExposure);
                    tempCube.Apply(false);
                    mset.AssetUtil.setLinear(new SerializedObject(tempCube), false);
                }

                mset.SkyProbe p = new mset.SkyProbe();
                p.maxExponent        = this.uiExponent;
                p.highestMipIsMirror = this.uiReflectionInSIM;
                p.generateMipChain   = this.uiMipChain;
                bool linear = UnityEditor.PlayerSettings.colorSpace == ColorSpace.Linear;
                p.convolve(this.outSIM.cube, tempCube, this.outSIM.HDR, this.outSKY.HDR, linear);
                outSIM.reloadReference();

                if (ps.buildMipChain)
                {
                    finishSIM();
                }
            }
            this.finishConvoGPU();
        }

        if (ps.isPlaying())
        {
            if (ps.curr == 0)
            {
                finishSKY();
            }
            if (ps.done())
            {
                ps.repaintMetric.end();
                finishConvo();
                Repaint();
                ps.pause();
            }
            else
            {
                ps.repaintMetric.end();
                //execute a subset of convolution steps, take a break to repaint the gui, then continue convolution
                stepConvo();
                EditorGUI.ProgressBar(progressRect, ps.progress(), "Convolution Progress " + Mathf.Floor(100f * ps.progress()) + "%");
                Repaint();
                ps.pendingRepaint = false;
                ps.repaintMetric.begin();
            }
        }

        if (ps.isPlaying() && !ps.done())
        {
            EditorGUI.ProgressBar(progressRect, ps.progress(), "Convolution Progress " + Mathf.Floor(100f * ps.progress()) + "%");
        }

        //DEBUG OPTIONS

        /*
         * EditorGUILayout.BeginVertical("HelpBox", GUILayout.Width(sectionWidth), GUILayout.MinWidth(minWidth)); {
         *      uiPerfReport = EditorGUILayout.Foldout(uiPerfReport,"Debug");
         *      if( uiPerfReport ) {
         *              uiShowPreview = EditorGUILayout.Toggle("Show Preview", uiShowPreview, GUILayout.Height(16));
         *              EditorGUILayout.Space();
         *
         *              string report = "Performance Report\n";
         *              report += ps.totalMetric.getString("Total",0);
         *              report += ps.initMetric.getString("Init",1);
         *              report += ps.blockMetric.getString("Coroutine Step",1);
         *              report += ps.passWriteMetric.getString("Cube Write",2);
         *              report += ps.repaintMetric.getString("Repaint", 1);
         *              report += ps.finishMetric.getString("Finalize", 1);
         *              EditorGUILayout.SelectableLabel(report, "HelpBox", GUILayout.Height(360));
         *              EditorGUILayout.Space();
         *              selectTest();
         *      }
         * }EditorGUILayout.EndVertical();
         */

        EditorGUILayout.BeginVertical("HelpBox", GUILayout.Width(sectionWidth), GUILayout.MinWidth(minWidth));
        {
            uiGIOptions = EditorGUILayout.Foldout(uiGIOptions, "Beast Global Illum Options");
            if (uiGIOptions)
            {
                mset.BeastConfig.DrawGUI();
                EditorGUILayout.Space();
            }
        } EditorGUILayout.EndVertical();


        EditorGUILayout.EndScrollView();
        GUILayout.EndArea();

        //GUIUtility.ExitGUI();
    }
Exemplo n.º 2
0
    ///
    public void OnGUI()
    {
        GUILayout.BeginArea(new Rect(0,0,position.width,position.height));
        uiScroll = EditorGUILayout.BeginScrollView(uiScroll, false, false,GUILayout.MinWidth(300),GUILayout.MaxWidth(position.width) );

        float rightPad = 23;
        float minWidth = 315;
        float sectionWidth = position.width - rightPad;
        float logoSize = 128;

        Rect logoRect = EditorGUILayout.BeginVertical(); {
            GUILayout.Space(32);
            drawSkyshopLogo(sectionWidth - logoSize, logoRect.y, logoSize);
        } EditorGUILayout.EndVertical();

        uiHideDuringCompute = false;//EditorGUILayout.Toggle("Hide UI During Compute",uiHideDuringCompute);
        if( !uiHideDuringCompute || !ps.isPlaying() ) {
            // INPUT REF
            EditorGUILayout.BeginVertical(); {
                inSKY.previewWidth = Mathf.Max(328,(int)sectionWidth-2);
                inSKY.drawGUI();
                outDIM.inputPath = outSIM.inputPath = outSKY.inputPath = inSKY.fullPath;
            } EditorGUILayout.EndVertical();

            // OUTPUT REF
            EditorGUILayout.BeginVertical("HelpBox",GUILayout.Width(sectionWidth), GUILayout.MinWidth(minWidth)); {
                uiRefOptions = EditorGUILayout.Foldout(uiRefOptions,"Output Cubemaps");
                if( uiRefOptions ) {
                    outSKY.drawGUI(); EditorGUILayout.Space();
                    outDIM.drawGUI(); EditorGUILayout.Space();
                    outSIM.drawGUI(); EditorGUILayout.Space();

                    EditorGUILayout.BeginHorizontal();{
                        string newTip = "Create a new cubemap assets for each output slot and adds them to the project.";
                        if (GUILayout.Button(new GUIContent("New All ", newTip), GUILayout.Width(70), GUILayout.Height(18))) {
                            outSKY.newCube();
                            outDIM.newCube();
                            outSIM.newCube();
                        }
                        string findTip = "Search project for all existing output cubemaps by input panorama name.";
                        if (GUILayout.Button(new GUIContent("Find All", findTip), GUILayout.Width(70), GUILayout.Height(18))) {
                            outSKY.find();
                            outDIM.find();
                            outSIM.find();
                        }
                        string clearTip = "Deselect all target cubemaps from output slots.";
                        if (GUILayout.Button(new GUIContent("Clear All", clearTip), GUILayout.Width(80), GUILayout.Height(18))) {
                            outSKY.clear();
                            outDIM.clear();
                            outSIM.clear();
                        }
                        string reloadTip = "Reload all input and output slot textures and generate preview images for them.";
                        EditorGUI.BeginDisabledGroup(outSKY.fullPath.Length == 0 && outDIM.fullPath.Length == 0 && outSIM.fullPath.Length == 0 && inSKY.fullPath.Length == 0);
                        {
                            if (GUILayout.Button(new GUIContent("Reload All", reloadTip), GUILayout.Width(85), GUILayout.Height(18))) {
                                outSKY.reloadReference();
                                outDIM.reloadReference();
                                outSIM.reloadReference();
                                inSKY.reloadReference();
                            }
                        }
                        EditorGUI.EndDisabledGroup();
                    } EditorGUILayout.EndHorizontal();

                    EditorGUILayout.BeginHorizontal();{

                        string editLabel = "";
                        string editTip = "";
                        mset.Sky editSky = null;

                        if( uiSelectedSky ) {
                            editSky = uiSelectedSky;
                            editLabel = "Edit Selected";
                            editTip = "Select cubemaps from the selected Sky as output targets.";
                        } else {
                            editSky = mset.Sky.activeSky;
                            editLabel = "Edit Active";
                            editTip = "Select cubemaps from the current viewport Sky as output targets.";
                        }
                        EditorGUI.BeginDisabledGroup(editSky == null);
                        if( GUILayout.Button( new GUIContent(editLabel, editTip), GUILayout.Width(95), GUILayout.Height(32) ) ) {
                            if( editSky ) {
                                outSKY.HDR = editSky.hdrSky;
                                outDIM.HDR = editSky.hdrDiff;
                                outSIM.HDR = editSky.hdrSpec;
                                outSKY.setReference( AssetDatabase.GetAssetPath(editSky.skyboxCube), false, true );
                                outDIM.setReference( AssetDatabase.GetAssetPath(editSky.diffuseCube), false, true );
                                outSIM.setReference( AssetDatabase.GetAssetPath(editSky.specularCube), true, true );
                            }
                        }
                        EditorGUI.EndDisabledGroup();

                        string applyTip = "Change the selected Sky object to use Skyshop's current output cubemaps.";
                        EditorGUI.BeginDisabledGroup(uiSelectedSky == null);
                        if( GUILayout.Button( new GUIContent("Apply to Selected", applyTip), GUILayout.Width(120), GUILayout.Height(32) ) ) {
                            if( uiSelectedSky ) {
                                mset.Util.RegisterUndo(uiSelectedSky, "Apply to Selected Sky");
                                uiSelectedSky.diffuseCube =  outDIM.cube;
                                uiSelectedSky.specularCube = outSIM.cube;
                                uiSelectedSky.skyboxCube = outSKY.cube;
                                uiSelectedSky.masterIntensity = 1f;
                                uiSelectedSky.skyIntensity = 1f;
                                uiSelectedSky.diffIntensity = 1f;
                                uiSelectedSky.specIntensity = 1f;
                                uiSelectedSky.hdrSky =  outSKY.HDR;
                                uiSelectedSky.hdrSpec = outSIM.HDR;
                                uiSelectedSky.hdrDiff = outDIM.HDR;

                                mset.Sky currSky = mset.Sky.activeSky;
                                uiSelectedSky.Apply(); //needed for refreshing exposures and such
                                if( currSky ) currSky.Apply();
                                SceneView.RepaintAll();
                            }
                        }
                        EditorGUI.EndDisabledGroup();

                        string addTip = "Create a new Sky object in the scene and assigns Skyshop's current output cubemaps to it.";
                        if( GUILayout.Button( new GUIContent("Add to Scene", addTip), GUILayout.Width(95), GUILayout.Height(32) ) ){
                            mset.Sky skyScript = addSky();
                            if( skyScript ) {
                                skyScript.diffuseCube = outDIM.cube;
                                skyScript.specularCube = outSIM.cube;
                                skyScript.skyboxCube = outSKY.cube;
                                skyScript.masterIntensity = 1f;
                                skyScript.skyIntensity = 1f;
                                skyScript.diffIntensity = 1f;
                                skyScript.specIntensity = 1f;
                                skyScript.hdrSky =  outSKY.HDR;
                                skyScript.hdrSpec = outSIM.HDR;
                                skyScript.hdrDiff = outDIM.HDR;
                                skyScript.Apply(); //Add to Scene
                                SceneView.RepaintAll();
                            }
                        }
                    }EditorGUILayout.EndHorizontal();
                    EditorGUILayout.Space();
                }// end if uiRefOptions
            }EditorGUILayout.EndVertical();

            // BASIC
            string tipExposure = "A multiplier on all the pixels in the Input Panorama during computation. Use for uniform brightness adjustment of results.";
            string tipQuality =  "Changes some advanced options to balance between image quality and computation speed.";

            EditorGUILayout.BeginVertical("HelpBox",GUILayout.Width(sectionWidth), GUILayout.MinWidth(minWidth)); {
                uiBasicOptions = EditorGUILayout.Foldout(uiBasicOptions,"Basic Options");
                if( uiBasicOptions ) {
                    float newExposure = EditorGUILayout.FloatField(new GUIContent("Baked Exposure","Baked Exposure -\n"+tipExposure), uiExposure, GUILayout.Width(300));
                    newExposure = Mathf.Max(0.0f, newExposure);
                    if( newExposure != uiExposure ) {
                        mset.Util.RegisterUndo(this,"Change Exposure");
                        uiExposure = newExposure;
                    }

                    mset.Quality newQuality = (mset.Quality)EditorGUILayout.EnumPopup(
                        new GUIContent("Quality","Quality -\n"+tipQuality),
                        (mset.Quality)uiConvoQuality,
                        GUILayout.Width(300)
                    );

                    if( newQuality != uiConvoQuality ) {
                        mset.Util.RegisterUndo(this,"Change Quality");
                        uiConvoQuality = newQuality;
                        switch(uiConvoQuality) {
                            case mset.Quality.ultra: 	uiConvoSize =  64; break;
                            case mset.Quality.high: 	uiConvoSize =  32; break;
                            case mset.Quality.medium: 	uiConvoSize =  16; break;
                            case mset.Quality.low: 		uiConvoSize =  8; break;
                        }
                    }
                    /*
                    uiCubeSize = (TexSize)EditorGUILayout.EnumPopup(
                        new GUIContent("Output Size (cube)","Output Size -\n"+tipCubeSize),
                        (CubeSize)uiCubeSize,
                        GUILayout.Width(300)
                    );*/

                    EditorGUILayout.Space();
                }// end if uiBasicOptions
            }EditorGUILayout.EndVertical();

            // PRO MOVES
            string tipConvoSize = "Resolution the input panorama is downsampled to for convolution, must be power of 2.\n\nWarning: High resolutions can lead to VERY long computation times!";
            string tipMipChain = "If enabled, different specular gloss exponents are computed and stored in each mipmap level of the Specular Output cube.\n\nThis must be enabled for Gloss Maps to function in Marmoset Shaders.";
            string tipExponent = "Gloss exponent used in computing the Specular Output cubemap. Value must be a power of 2, lower values result in a blurrier cubemap. Only available when \"Build Mip Chains\" is disabled.";
            string tipExponents = "Displays a list of the specular gloss exponents used in the various mip levels of the Specular Output cube.";
            string tipResponsiveUI = "Enable if Unity is too unresponsive during computation. Will slow overall computation time.";
            string tipReflection = "Highest gloss level in the specular mip chain is a polished mirror reflection pulled from the input panorama itself.";

            EditorGUILayout.BeginVertical("HelpBox",GUILayout.Width(sectionWidth), GUILayout.MinWidth(minWidth));
            {
                uiAdvancedOptions = EditorGUILayout.Foldout(uiAdvancedOptions,"Advanced Options");
                if( uiAdvancedOptions ) {
                    int newConvoSize = EditorGUILayout.IntField(
                        new GUIContent("Convolution Size", "Convolution Size -\n" + tipConvoSize),
                        uiConvoSize,
                        GUILayout.Width(300)
                    );

                    if( newConvoSize < 2 ) newConvoSize = 2;
                    newConvoSize += newConvoSize % 2;

                    if( newConvoSize != uiConvoSize ) {
                        mset.Util.RegisterUndo(this,"Change Convolution Size");
                        uiConvoSize = newConvoSize;
                        uiConvoQuality = mset.Quality.custom;
                        switch( uiConvoSize ) {
                            case 8:  uiConvoQuality = mset.Quality.low; break;
                            case 16: uiConvoQuality = mset.Quality.medium; break;
                            case 32: uiConvoQuality = mset.Quality.high; break;
                            case 64: uiConvoQuality = mset.Quality.ultra; break;
                        };
                    }
                    EditorGUILayout.Space();
                    mset.CubemapGUI.drawStaticGUI();

                    bool newMipChain = EditorGUILayout.Toggle(new GUIContent("Build Specular Mip Chain","Specular Mip Chains -\n" + tipMipChain),uiMipChain);
                    if( newMipChain != uiMipChain ) {
                        mset.Util.RegisterUndo(this,"Toggle Specular Mip Chain");
                        uiMipChain = newMipChain;
                    }
                    if(uiMipChain) {
                        bool newRefInSIM = EditorGUILayout.Toggle(new GUIContent("Highest Mip is Reflection","Highest Mip is Reflection -\n" + tipReflection),uiReflectionInSIM);
                        if( newRefInSIM != uiReflectionInSIM ) {
                            mset.Util.RegisterUndo(this,"Toggle Mip Chain Reflection");
                            uiReflectionInSIM = newRefInSIM;
                        }
                        EditorGUI.BeginDisabledGroup(true);
                        string mipString;
                        if( uiReflectionInSIM ) mipString = "mirror, 128, 64, 32, 16...";
                        else 					mipString = "256, 128, 64, 32, 16, 8...";
                        EditorGUILayout.TextField(new GUIContent("Specular Exponents","Specular Exponents -\n"+tipExponents), mipString, GUILayout.Width(300));
                        EditorGUI.EndDisabledGroup();
                    } else {
                        EditorGUI.BeginDisabledGroup(true);
                        EditorGUILayout.Toggle(new GUIContent("Highest Mip is Reflection","Highest Mip is Reflection -\n" + tipReflection),false);
                        EditorGUI.EndDisabledGroup();
                        int newExponent = EditorGUILayout.IntField(
                            new GUIContent("Specular Exponent","Specular Exponent -\n" + tipExponent),
                            uiExponent,
                            GUILayout.Width(300)
                        );
                        newExponent = Mathf.Max(1, newExponent);
                        if( newExponent != uiExponent ) {
                            mset.Util.RegisterUndo(this, "Change Specular Exponent");
                            uiExponent = newExponent;
                        }
                    }
                    EditorGUILayout.Space();

                    //TODO: Will anyone ever want this? Marmoset shaders need gamma compression as does sRGB sampling.
                    uiGammaCompress = true;
                    /*
                    uiGammaCompress = EditorGUILayout.Toggle(new GUIContent(
                        "Gamma-Compress RGBM",
                        "Gamma-Compress RGBM -\nIf enabled, a gamma of 1/2.2 is applied to HDR data before it is encoded as RGBM. This adds dynamic range but also shader complexity. Leave enabled for Marmoset shaders."),
                        uiGammaCompress);
                    */

                    uiResponsiveUI = stepsPerFrame <= 1024*16;
                    uiResponsiveUI = EditorGUILayout.Toggle(new GUIContent("Keep UI Responsive","Keep UI Responsive -\n"+tipResponsiveUI), uiResponsiveUI);
                    ulong newStepsPerFrame = stepsPerFrame;
                    if( uiResponsiveUI ) newStepsPerFrame = 1024*16;
                    else 				 newStepsPerFrame = 1024*256;

                    if( newStepsPerFrame != stepsPerFrame ) {
                        mset.Util.RegisterUndo(this,"Toggle Responsive UI");
                        stepsPerFrame = newStepsPerFrame;
                    }
                    EditorGUILayout.Space();

                    if( GUILayout.Button("Reset to Default", GUILayout.Width(120)) ) {
                        uiConvoSize = Mathf.Min(uiConvoSize, 16);
                        uiMipChain = true;
                        uiReflectionInSIM = true;
                        uiResponsiveUI = false;
                        uiGammaCompress = true;
                    }
                    EditorGUILayout.Space();

                }
            }EditorGUILayout.EndVertical();

            EditorGUILayout.Space();
            EditorGUILayout.Space();
        }

        //GENERATE
        bool generate = false;
        bool cancel = false;
        EditorGUILayout.BeginHorizontal(); {
            if( ps.isPlaying() ) {
                cancel = GUILayout.Button("Abort", GUILayout.Width(130), GUILayout.Height(50));
            } else {
                bool valid = true;
                if( inSKY.input == null ) {
                    valid = false;
                }
                if( outSKY.cube == null && outDIM.cube == null && outSIM.cube == null ) {
                    valid = false;
                }
                EditorGUI.BeginDisabledGroup(!valid);
                    generate = GUILayout.Button("Compute", GUILayout.Width(130), GUILayout.Height(50));
                EditorGUI.EndDisabledGroup();

                if( !valid ) {
                    EditorGUILayout.BeginVertical();
                    if( inSKY.input == null ) {
                        EditorGUILayout.HelpBox("Input Panorama is missing.", MessageType.Error);
                    }
                    if( outSKY.cube == null && outDIM.cube == null && outSIM.cube == null ) {
                        EditorGUILayout.HelpBox("An Output Cubemap is needed.", MessageType.Error);
                    }
                    EditorGUILayout.EndVertical();
                }
            }
        }EditorGUILayout.EndHorizontal();
        if( cancel ) {
            ps.pause();
            Repaint();

            inSKY.locked =
            outSKY.locked =
            outDIM.locked =
            outSIM.locked = false;
            inSKY.updateBuffers();
        }

        progressRect = GUILayoutUtility.GetRect(sectionWidth - 4,16);
        progressRect.width = sectionWidth;
        progressRect.x = 4;
        progressRect.y += 2;

        //uiShowPreview = true;
        if( uiShowPreview ) {
            EditorGUILayout.LabelField("Convolution Preview");
            float previewWidth = position.width - rightPad;
            float previewHeight = previewWidth*0.5f;
            mset.Util.GUILayout.drawTexture( 4, 0, previewWidth, previewHeight, "", uiConvoPreview, false);
        }

        if( generate ) {
            startConvo();
            ps.repaintMetric.begin();
        }

        if( ps.isPlaying() ) {
            if( ps.curr == 0 ) { finishSKY(); }
            if( ps.done() ) {
                ps.repaintMetric.end();
                finishConvo();
                Repaint();
                ps.pause();
            } else {
                ps.repaintMetric.end();
                //execute a subset of convolution steps, take a break to repaint the gui, then continue convolution
                stepConvo();
                EditorGUI.ProgressBar(progressRect, ps.progress(), "Convolution Progress " + Mathf.Floor(100f * ps.progress()) + "%");
                Repaint();
                ps.pendingRepaint = false;
                ps.repaintMetric.begin();
            }
        }

        if( ps.isPlaying() && !ps.done() ) {
            EditorGUI.ProgressBar(progressRect, ps.progress(), "Convolution Progress " + Mathf.Floor(100f * ps.progress()) + "%");
        }

        //DEBUG OPTIONS
        /*
        EditorGUILayout.BeginVertical("HelpBox", GUILayout.Width(sectionWidth), GUILayout.MinWidth(minWidth)); {
            uiPerfReport = EditorGUILayout.Foldout(uiPerfReport,"Debug");
            if( uiPerfReport ) {
                uiShowPreview = EditorGUILayout.Toggle("Show Preview", uiShowPreview, GUILayout.Height(16));
                EditorGUILayout.Space();

                string report = "Performance Report\n";
                report += ps.totalMetric.getString("Total",0);
                report += ps.initMetric.getString("Init",1);
                report += ps.blockMetric.getString("Coroutine Step",1);
                report += ps.passWriteMetric.getString("Cube Write",2);
                report += ps.repaintMetric.getString("Repaint", 1);
                report += ps.finishMetric.getString("Finalize", 1);
                EditorGUILayout.SelectableLabel(report, "HelpBox", GUILayout.Height(360));
                EditorGUILayout.Space();
                selectTest();
            }
        }EditorGUILayout.EndVertical();
        */

        EditorGUILayout.BeginVertical("HelpBox",GUILayout.Width(sectionWidth), GUILayout.MinWidth(minWidth));
        {
            uiGIOptions = EditorGUILayout.Foldout(uiGIOptions,"Beast Global Illum Options");
            if( uiGIOptions ) {
                mset.BeastConfig.DrawGUI();
                EditorGUILayout.Space();
            }
        }EditorGUILayout.EndVertical();

        EditorGUILayout.EndScrollView();
        GUILayout.EndArea();

        //GUIUtility.ExitGUI();
    }