public override void OnInspectorGUI()
    {
        resourceObject.Update();

        bool enable = GUI.enabled; //Everything in external asset is disabled by default

        GUI.enabled = true;

        EditorGUI.BeginChangeCheck();
        EditorGUI.showMixedValue = resourceUpdateModeProperty.hasMultipleDifferentValues;
        VFXUpdateMode newUpdateMode = (VFXUpdateMode)EditorGUILayout.EnumPopup(EditorGUIUtility.TrTextContent("Update Mode"), (VFXUpdateMode)resourceUpdateModeProperty.intValue);

        if (EditorGUI.EndChangeCheck())
        {
            resourceUpdateModeProperty.intValue = (int)newUpdateMode;
            resourceObject.ApplyModifiedProperties();
        }

        EditorGUILayout.BeginHorizontal();
        EditorGUI.showMixedValue = cullingFlagsProperty.hasMultipleDifferentValues;
        EditorGUILayout.PrefixLabel(EditorGUIUtility.TrTextContent("Culling Flags"));
        EditorGUI.BeginChangeCheck();
        int newOption = EditorGUILayout.Popup(Array.IndexOf(k_CullingOptionsValue, (VFXCullingFlags)cullingFlagsProperty.intValue), k_CullingOptionsContents);

        if (EditorGUI.EndChangeCheck())
        {
            cullingFlagsProperty.intValue = (int)k_CullingOptionsValue[newOption];
            resourceObject.ApplyModifiedProperties();
        }
        EditorGUILayout.EndHorizontal();

        if (prewarmDeltaTime != null && prewarmStepCount != null)
        {
            if (!prewarmDeltaTime.hasMultipleDifferentValues && !prewarmStepCount.hasMultipleDifferentValues)
            {
                var currentDeltaTime = prewarmDeltaTime.floatValue;
                var currentStepCount = prewarmStepCount.intValue;
                var currentTotalTime = currentDeltaTime * currentStepCount;
                EditorGUI.BeginChangeCheck();
                currentTotalTime = EditorGUILayout.FloatField(EditorGUIUtility.TrTextContent("PreWarm Total Time"), currentTotalTime);
                if (EditorGUI.EndChangeCheck())
                {
                    if (currentStepCount <= 0)
                    {
                        prewarmStepCount.intValue = currentStepCount = 1;
                    }

                    currentDeltaTime            = currentTotalTime / currentStepCount;
                    prewarmDeltaTime.floatValue = currentDeltaTime;
                    resourceObject.ApplyModifiedProperties();
                }

                EditorGUI.BeginChangeCheck();
                currentStepCount = EditorGUILayout.IntField(EditorGUIUtility.TrTextContent("PreWarm Step Count"), currentStepCount);
                if (EditorGUI.EndChangeCheck())
                {
                    if (currentStepCount <= 0 && currentTotalTime != 0.0f)
                    {
                        prewarmStepCount.intValue = currentStepCount = 1;
                    }

                    currentDeltaTime            = currentTotalTime == 0.0f ? 0.0f : currentTotalTime / currentStepCount;
                    prewarmDeltaTime.floatValue = currentDeltaTime;
                    prewarmStepCount.intValue   = currentStepCount;
                    resourceObject.ApplyModifiedProperties();
                }

                EditorGUI.BeginChangeCheck();
                currentDeltaTime = EditorGUILayout.FloatField(EditorGUIUtility.TrTextContent("PreWarm Delta Time"), currentDeltaTime);
                if (EditorGUI.EndChangeCheck())
                {
                    if (currentDeltaTime < k_MinimalCommonDeltaTime)
                    {
                        prewarmDeltaTime.floatValue = currentDeltaTime = k_MinimalCommonDeltaTime;
                    }

                    if (currentDeltaTime > currentTotalTime)
                    {
                        currentTotalTime = currentDeltaTime;
                    }

                    if (currentTotalTime != 0.0f)
                    {
                        var candidateStepCount_A = Mathf.FloorToInt(currentTotalTime / currentDeltaTime);
                        var candidateStepCount_B = Mathf.RoundToInt(currentTotalTime / currentDeltaTime);

                        var totalTime_A = currentDeltaTime * candidateStepCount_A;
                        var totalTime_B = currentDeltaTime * candidateStepCount_B;

                        if (Mathf.Abs(totalTime_A - currentTotalTime) < Mathf.Abs(totalTime_B - currentTotalTime))
                        {
                            currentStepCount = candidateStepCount_A;
                        }
                        else
                        {
                            currentStepCount = candidateStepCount_B;
                        }

                        prewarmStepCount.intValue = currentStepCount;
                    }
                    prewarmDeltaTime.floatValue = currentDeltaTime;
                    resourceObject.ApplyModifiedProperties();
                }
            }
            else
            {
                //Multi selection case, can't resolve total time easily
                EditorGUI.BeginChangeCheck();
                EditorGUI.showMixedValue = prewarmStepCount.hasMultipleDifferentValues;
                EditorGUILayout.PropertyField(prewarmStepCount, EditorGUIUtility.TrTextContent("PreWarm Step Count"));
                EditorGUI.showMixedValue = prewarmDeltaTime.hasMultipleDifferentValues;
                EditorGUILayout.PropertyField(prewarmDeltaTime, EditorGUIUtility.TrTextContent("PreWarm Delta Time"));
                if (EditorGUI.EndChangeCheck())
                {
                    if (prewarmDeltaTime.floatValue < k_MinimalCommonDeltaTime)
                    {
                        prewarmDeltaTime.floatValue = k_MinimalCommonDeltaTime;
                    }
                    resourceObject.ApplyModifiedProperties();
                }
            }
        }

        if (initialEventName != null)
        {
            EditorGUI.BeginChangeCheck();
            EditorGUI.showMixedValue = initialEventName.hasMultipleDifferentValues;
            EditorGUILayout.PropertyField(initialEventName);
            if (EditorGUI.EndChangeCheck())
            {
                resourceObject.ApplyModifiedProperties();
            }
        }

        if (!serializedObject.isEditingMultipleObjects)
        {
            VisualEffectAsset    asset    = (VisualEffectAsset)target;
            VisualEffectResource resource = asset.GetResource();

            m_OutputContexts.Clear();
            m_OutputContexts.AddRange(resource.GetOrCreateGraph().children.OfType <IVFXSubRenderer>().OrderBy(t => t.sortPriority));

            m_ReorderableList.DoLayoutList();

            VisualEffectEditor.ShowHeader(EditorGUIUtility.TrTextContent("Shaders"), false, false);

            var shaderSources = resource.shaderSources;

            string        assetPath = AssetDatabase.GetAssetPath(asset);
            UnityObject[] objects   = AssetDatabase.LoadAllAssetsAtPath(assetPath);
            string        directory = Path.GetDirectoryName(assetPath) + "/" + VFXExternalShaderProcessor.k_ShaderDirectory + "/" + asset.name + "/";

            foreach (var shader in objects)
            {
                if (shader is Shader || shader is ComputeShader)
                {
                    GUILayout.BeginHorizontal();
                    GUILayout.Label(shader.name, GUILayout.ExpandWidth(true));
                    int index = resource.GetShaderIndex(shader);
                    if (index >= 0 && index < shaderSources.Length)
                    {
                        if (VFXExternalShaderProcessor.allowExternalization)
                        {
                            string externalPath = directory + shaderSources[index].name;
                            if (!shaderSources[index].compute)
                            {
                                externalPath = directory + shaderSources[index].name.Replace('/', '_') + VFXExternalShaderProcessor.k_ShaderExt;
                            }
                            else
                            {
                                externalPath = directory + shaderSources[index].name + VFXExternalShaderProcessor.k_ShaderExt;
                            }

                            if (System.IO.File.Exists(externalPath))
                            {
                                if (GUILayout.Button("Reveal External"))
                                {
                                    EditorUtility.RevealInFinder(externalPath);
                                }
                            }
                            else
                            {
                                if (GUILayout.Button("Externalize", GUILayout.Width(80)))
                                {
                                    Directory.CreateDirectory(directory);

                                    File.WriteAllText(externalPath, "//" + shaderSources[index].name + "," + index.ToString() + "\n//Don't delete the previous line or this one\n" + shaderSources[index].source);
                                }
                            }
                        }

                        if (GUILayout.Button("Show Generated", GUILayout.Width(110)))
                        {
                            resource.ShowGeneratedShaderFile(index);
                        }
                    }
                    if (GUILayout.Button("Select", GUILayout.Width(50)))
                    {
                        Selection.activeObject = shader;
                    }
                    GUILayout.EndHorizontal();
                }
            }
        }
        GUI.enabled = false;
    }
Beispiel #2
0
    public override void OnInspectorGUI()
    {
        resourceObject.Update();


        bool enable = GUI.enabled; //Everything in external asset is disabled by default

        GUI.enabled = true;

        EditorGUI.BeginChangeCheck();
        EditorGUI.showMixedValue = resourceUpdateModeProperty.hasMultipleDifferentValues;
        VFXUpdateMode newUpdateMode = (VFXUpdateMode)EditorGUILayout.EnumPopup(EditorGUIUtility.TrTextContent("Update Mode"), (VFXUpdateMode)resourceUpdateModeProperty.intValue);

        if (EditorGUI.EndChangeCheck())
        {
            resourceUpdateModeProperty.intValue = (int)newUpdateMode;
            resourceObject.ApplyModifiedProperties();
        }

        EditorGUILayout.BeginHorizontal();
        EditorGUI.showMixedValue = cullingFlagsProperty.hasMultipleDifferentValues;
        EditorGUILayout.PrefixLabel(EditorGUIUtility.TrTextContent("Culling Flags"));
        EditorGUI.BeginChangeCheck();
        int newOption = EditorGUILayout.Popup(Array.IndexOf(k_CullingOptionsValue, (VFXCullingFlags)cullingFlagsProperty.intValue), k_CullingOptionsContents);

        if (EditorGUI.EndChangeCheck())
        {
            cullingFlagsProperty.intValue = (int)k_CullingOptionsValue[newOption];
            resourceObject.ApplyModifiedProperties();
        }
        EditorGUILayout.EndHorizontal();

        bool needRecompile = false;

        EditorGUI.BeginChangeCheck();


        EditorGUI.showMixedValue = motionVectorRenderModeProperty.hasMultipleDifferentValues;
        EditorGUI.BeginChangeCheck();
        bool motionVector = EditorGUILayout.Toggle(EditorGUIUtility.TrTextContent("Use Motion Vectors"), motionVectorRenderModeProperty.intValue == (int)MotionVectorGenerationMode.Object);

        if (EditorGUI.EndChangeCheck())
        {
            motionVectorRenderModeProperty.intValue = motionVector ? (int)MotionVectorGenerationMode.Object : (int)MotionVectorGenerationMode.Camera;
            resourceObject.ApplyModifiedProperties();
            needRecompile = true;
        }

        if (needRecompile)
        {
            foreach (VisualEffectResource resource in resourceObject.targetObjects)
            {
                VFXGraph graph = resource.GetOrCreateGraph() as VFXGraph;
                if (graph != null)
                {
                    graph.SetExpressionGraphDirty();
                    graph.RecompileIfNeeded();
                }
            }
        }

        if (!serializedObject.isEditingMultipleObjects)
        {
            VisualEffectEditor.ShowHeader(EditorGUIUtility.TrTextContent("Shaders"), true, true, false, false);
            VisualEffectAsset    asset    = (VisualEffectAsset)target;
            VisualEffectResource resource = asset.GetResource();

            var shaderSources = resource.shaderSources;


            string        assetPath = AssetDatabase.GetAssetPath(asset);
            UnityObject[] objects   = AssetDatabase.LoadAllAssetsAtPath(assetPath);
            string        directory = Path.GetDirectoryName(assetPath) + "/" + VFXExternalShaderProcessor.k_ShaderDirectory + "/" + asset.name + "/";

            foreach (var shader in objects)
            {
                if (shader is Shader || shader is ComputeShader)
                {
                    GUILayout.BeginHorizontal();
                    GUILayout.Label(shader.name, GUILayout.ExpandWidth(true));
                    int index = resource.GetShaderIndex(shader);
                    if (index >= 0 && index < shaderSources.Length)
                    {
                        if (VFXExternalShaderProcessor.allowExternalization)
                        {
                            string externalPath = directory + shaderSources[index].name;
                            if (!shaderSources[index].compute)
                            {
                                externalPath = directory + shaderSources[index].name.Replace('/', '_') + VFXExternalShaderProcessor.k_ShaderExt;
                            }
                            else
                            {
                                externalPath = directory + shaderSources[index].name + VFXExternalShaderProcessor.k_ShaderExt;
                            }

                            if (System.IO.File.Exists(externalPath))
                            {
                                if (GUILayout.Button("Reveal External"))
                                {
                                    EditorUtility.RevealInFinder(externalPath);
                                }
                            }
                            else
                            {
                                if (GUILayout.Button("Externalize", GUILayout.Width(80)))
                                {
                                    Directory.CreateDirectory(directory);

                                    File.WriteAllText(externalPath, "//" + shaderSources[index].name + "," + index.ToString() + "\n//Don't delete the previous line or this one\n" + shaderSources[index].source);
                                }
                            }
                        }

                        if (GUILayout.Button("Show Generated", GUILayout.Width(110)))
                        {
                            resource.ShowGeneratedShaderFile(index);
                        }
                    }
                    if (GUILayout.Button("Select", GUILayout.Width(50)))
                    {
                        Selection.activeObject = shader;
                    }
                    GUILayout.EndHorizontal();
                }
            }
        }
        GUI.enabled = false;
    }
Beispiel #3
0
    public override void OnInspectorGUI()
    {
        resourceObject.Update();

        GUI.enabled = AssetDatabase.IsOpenForEdit(this.target, StatusQueryOptions.UseCachedIfPossible);

        EditorGUI.BeginChangeCheck();
        EditorGUI.showMixedValue = resourceUpdateModeProperty.hasMultipleDifferentValues;
        VFXUpdateMode newUpdateMode = (VFXUpdateMode)EditorGUILayout.EnumPopup(EditorGUIUtility.TrTextContent("Update Mode", "Specifies whether particles are updated using a fixed timestep (Fixed Delta Time), or in a frame-rate independent manner (Delta Time)."), (VFXUpdateMode)resourceUpdateModeProperty.intValue);

        if (EditorGUI.EndChangeCheck())
        {
            resourceUpdateModeProperty.intValue = (int)newUpdateMode;
            resourceObject.ApplyModifiedProperties();
        }

        EditorGUILayout.BeginHorizontal();
        EditorGUI.showMixedValue = cullingFlagsProperty.hasMultipleDifferentValues;
        EditorGUILayout.PrefixLabel(EditorGUIUtility.TrTextContent("Culling Flags", "Specifies how the system recomputes its bounds and simulates when off-screen."));
        EditorGUI.BeginChangeCheck();
        int newOption = EditorGUILayout.Popup(Array.IndexOf(k_CullingOptionsValue, (VFXCullingFlags)cullingFlagsProperty.intValue), k_CullingOptionsContents);

        if (EditorGUI.EndChangeCheck())
        {
            cullingFlagsProperty.intValue = (int)k_CullingOptionsValue[newOption];
            resourceObject.ApplyModifiedProperties();
        }
        EditorGUILayout.EndHorizontal();

        if (prewarmDeltaTime != null && prewarmStepCount != null)
        {
            if (!prewarmDeltaTime.hasMultipleDifferentValues && !prewarmStepCount.hasMultipleDifferentValues)
            {
                var currentDeltaTime = prewarmDeltaTime.floatValue;
                var currentStepCount = prewarmStepCount.intValue;
                var currentTotalTime = currentDeltaTime * currentStepCount;
                EditorGUI.BeginChangeCheck();
                currentTotalTime = EditorGUILayout.FloatField(EditorGUIUtility.TrTextContent("PreWarm Total Time", "Sets the time in seconds to advance the current effect to when it is initially played. "), currentTotalTime);
                if (EditorGUI.EndChangeCheck())
                {
                    if (currentStepCount <= 0)
                    {
                        prewarmStepCount.intValue = currentStepCount = 1;
                    }

                    currentDeltaTime            = currentTotalTime / currentStepCount;
                    prewarmDeltaTime.floatValue = currentDeltaTime;
                    resourceObject.ApplyModifiedProperties();
                }

                EditorGUI.BeginChangeCheck();
                currentStepCount = EditorGUILayout.IntField(EditorGUIUtility.TrTextContent("PreWarm Step Count", "Sets the number of simulation steps the prewarm should be broken down to. "), currentStepCount);
                if (EditorGUI.EndChangeCheck())
                {
                    if (currentStepCount <= 0 && currentTotalTime != 0.0f)
                    {
                        prewarmStepCount.intValue = currentStepCount = 1;
                    }

                    currentDeltaTime            = currentTotalTime == 0.0f ? 0.0f : currentTotalTime / currentStepCount;
                    prewarmDeltaTime.floatValue = currentDeltaTime;
                    prewarmStepCount.intValue   = currentStepCount;
                    resourceObject.ApplyModifiedProperties();
                }

                EditorGUI.BeginChangeCheck();
                currentDeltaTime = EditorGUILayout.FloatField(EditorGUIUtility.TrTextContent("PreWarm Delta Time", "Sets the time in seconds for each step to achieve the desired total prewarm time."), currentDeltaTime);
                if (EditorGUI.EndChangeCheck())
                {
                    if (currentDeltaTime < k_MinimalCommonDeltaTime)
                    {
                        prewarmDeltaTime.floatValue = currentDeltaTime = k_MinimalCommonDeltaTime;
                    }

                    if (currentDeltaTime > currentTotalTime)
                    {
                        currentTotalTime = currentDeltaTime;
                    }

                    if (currentTotalTime != 0.0f)
                    {
                        var candidateStepCount_A = Mathf.FloorToInt(currentTotalTime / currentDeltaTime);
                        var candidateStepCount_B = Mathf.RoundToInt(currentTotalTime / currentDeltaTime);

                        var totalTime_A = currentDeltaTime * candidateStepCount_A;
                        var totalTime_B = currentDeltaTime * candidateStepCount_B;

                        if (Mathf.Abs(totalTime_A - currentTotalTime) < Mathf.Abs(totalTime_B - currentTotalTime))
                        {
                            currentStepCount = candidateStepCount_A;
                        }
                        else
                        {
                            currentStepCount = candidateStepCount_B;
                        }

                        prewarmStepCount.intValue = currentStepCount;
                    }
                    prewarmDeltaTime.floatValue = currentDeltaTime;
                    resourceObject.ApplyModifiedProperties();
                }
            }
            else
            {
                //Multi selection case, can't resolve total time easily
                EditorGUI.BeginChangeCheck();
                EditorGUI.showMixedValue = prewarmStepCount.hasMultipleDifferentValues;
                EditorGUILayout.PropertyField(prewarmStepCount, EditorGUIUtility.TrTextContent("PreWarm Step Count", "Sets the number of simulation steps the prewarm should be broken down to."));
                EditorGUI.showMixedValue = prewarmDeltaTime.hasMultipleDifferentValues;
                EditorGUILayout.PropertyField(prewarmDeltaTime, EditorGUIUtility.TrTextContent("PreWarm Delta Time", "Sets the time in seconds for each step to achieve the desired total prewarm time."));
                if (EditorGUI.EndChangeCheck())
                {
                    if (prewarmDeltaTime.floatValue < k_MinimalCommonDeltaTime)
                    {
                        prewarmDeltaTime.floatValue = k_MinimalCommonDeltaTime;
                    }
                    resourceObject.ApplyModifiedProperties();
                }
            }
        }

        if (initialEventName != null)
        {
            EditorGUI.BeginChangeCheck();
            EditorGUI.showMixedValue = initialEventName.hasMultipleDifferentValues;
            EditorGUILayout.PropertyField(initialEventName, new GUIContent("Initial Event Name", "Sets the name of the event which triggers once the system is activated. Default: ‘OnPlay’."));
            if (EditorGUI.EndChangeCheck())
            {
                resourceObject.ApplyModifiedProperties();
            }
        }

        if (!serializedObject.isEditingMultipleObjects)
        {
            VisualEffectAsset    asset    = (VisualEffectAsset)target;
            VisualEffectResource resource = asset.GetResource();

            m_OutputContexts.Clear();
            m_OutputContexts.AddRange(resource.GetOrCreateGraph().children.OfType <IVFXSubRenderer>().OrderBy(t => t.sortPriority));

            m_ReorderableList.DoLayoutList();

            VisualEffectEditor.ShowHeader(EditorGUIUtility.TrTextContent("Shaders"), false, false);

            string        assetPath = AssetDatabase.GetAssetPath(asset);
            UnityObject[] objects   = AssetDatabase.LoadAllAssetsAtPath(assetPath);
            string        directory = Path.GetDirectoryName(assetPath) + "/" + VFXExternalShaderProcessor.k_ShaderDirectory + "/" + asset.name + "/";

            foreach (var shader in objects)
            {
                if (shader is Shader || shader is ComputeShader)
                {
                    GUILayout.BeginHorizontal();
                    Rect r = GUILayoutUtility.GetRect(0, 18, GUILayout.ExpandWidth(true));

                    int buttonsWidth = VFXExternalShaderProcessor.allowExternalization? 240:160;


                    Rect labelR = r;
                    labelR.width -= buttonsWidth;
                    GUI.Label(labelR, shader.name);
                    int index = resource.GetShaderIndex(shader);
                    if (index >= 0)
                    {
                        if (VFXExternalShaderProcessor.allowExternalization && index < resource.GetShaderSourceCount())
                        {
                            string shaderSourceName = resource.GetShaderSourceName(index);
                            string externalPath     = directory + shaderSourceName;

                            externalPath = directory + shaderSourceName.Replace('/', '_') + VFXExternalShaderProcessor.k_ShaderExt;

                            Rect buttonRect = r;
                            buttonRect.xMin  = labelR.xMax;
                            buttonRect.width = 80;
                            labelR.width    += 80;
                            if (System.IO.File.Exists(externalPath))
                            {
                                if (GUI.Button(buttonRect, "Reveal External"))
                                {
                                    EditorUtility.RevealInFinder(externalPath);
                                }
                            }
                            else
                            {
                                if (GUI.Button(buttonRect, "Externalize"))
                                {
                                    Directory.CreateDirectory(directory);

                                    File.WriteAllText(externalPath, "//" + shaderSourceName + "," + index.ToString() + "\n//Don't delete the previous line or this one\n" + resource.GetShaderSource(index));
                                }
                            }
                        }

                        Rect buttonR = r;
                        buttonR.xMin  = labelR.xMax;
                        buttonR.width = 110;
                        labelR.width += 110;
                        if (GUI.Button(buttonR, "Show Generated"))
                        {
                            resource.ShowGeneratedShaderFile(index);
                        }
                    }

                    Rect selectButtonR = r;
                    selectButtonR.xMin  = labelR.xMax;
                    selectButtonR.width = 50;
                    if (GUI.Button(selectButtonR, "Select"))
                    {
                        Selection.activeObject = shader;
                    }
                    GUILayout.EndHorizontal();
                }
            }
        }
        GUI.enabled = false;
    }
Beispiel #4
0
    public override void OnInspectorGUI()
    {
        resourceObject.Update();

        GUI.enabled = AssetDatabase.IsOpenForEdit(this.target, StatusQueryOptions.UseCachedIfPossible);

        VFXUpdateMode initialUpdateMode          = (VFXUpdateMode)0;
        bool?         initialFixedDeltaTime      = null;
        bool?         initialProcessEveryFrame   = null;
        bool?         initialIgnoreGameTimeScale = null;

        if (resourceUpdateModeProperty.hasMultipleDifferentValues)
        {
            var resourceUpdateModeProperties = resourceUpdateModeProperty.serializedObject.targetObjects
                                               .Select(o => new SerializedObject(o)
                                                       .FindProperty(resourceUpdateModeProperty.propertyPath))
                                               .ToArray();  //N.B.: This will create garbage
            var allDeltaTime = resourceUpdateModeProperties.Select(o => ((VFXUpdateMode)o.intValue & VFXUpdateMode.DeltaTime) == VFXUpdateMode.DeltaTime)
                               .Distinct();
            var allProcessEveryFrame = resourceUpdateModeProperties.Select(o => ((VFXUpdateMode)o.intValue & VFXUpdateMode.ExactFixedTimeStep) == VFXUpdateMode.ExactFixedTimeStep)
                                       .Distinct();
            var allIgnoreScale = resourceUpdateModeProperties.Select(o => ((VFXUpdateMode)o.intValue & VFXUpdateMode.IgnoreTimeScale) == VFXUpdateMode.IgnoreTimeScale)
                                 .Distinct();
            if (allDeltaTime.Count() == 1)
            {
                initialFixedDeltaTime = !allDeltaTime.First();
            }
            if (allProcessEveryFrame.Count() == 1)
            {
                initialProcessEveryFrame = allProcessEveryFrame.First();
            }
            if (allIgnoreScale.Count() == 1)
            {
                initialIgnoreGameTimeScale = allIgnoreScale.First();
            }
        }
        else
        {
            initialUpdateMode          = (VFXUpdateMode)resourceUpdateModeProperty.intValue;
            initialFixedDeltaTime      = !((initialUpdateMode & VFXUpdateMode.DeltaTime) == VFXUpdateMode.DeltaTime);
            initialProcessEveryFrame   = (initialUpdateMode & VFXUpdateMode.ExactFixedTimeStep) == VFXUpdateMode.ExactFixedTimeStep;
            initialIgnoreGameTimeScale = (initialUpdateMode & VFXUpdateMode.IgnoreTimeScale) == VFXUpdateMode.IgnoreTimeScale;
        }

        EditorGUI.showMixedValue = !initialFixedDeltaTime.HasValue;
        var deltaTimeContent         = EditorGUIUtility.TrTextContent("Fixed Delta Time", "If enabled, use visual effect manager fixed delta time mode, otherwise, use the default Time.deltaTime.");
        var processEveryFrameContent = EditorGUIUtility.TrTextContent("Exact Fixed Time", "Only relevant when using Fixed Delta Time. When enabled, several updates can be processed per frame (e.g.: if a frame is 10ms and the fixed frame rate is set to 5 ms, the effect will update twice with a 5ms deltaTime instead of once with a 10ms deltaTime). This method is expensive and should only be used for high-end scenarios.");
        var ignoreTimeScaleContent   = EditorGUIUtility.TrTextContent("Ignore Time Scale", "When enabled, the computed visual effect delta time ignores the game Time Scale value (Play Rate is still applied).");

        EditorGUI.BeginChangeCheck();

        VisualEffectEditor.ShowHeader(EditorGUIUtility.TrTextContent("Update mode"), false, false);
        bool newFixedDeltaTime     = EditorGUILayout.Toggle(deltaTimeContent, initialFixedDeltaTime ?? false);
        bool newExactFixedTimeStep = false;

        EditorGUI.showMixedValue = !initialProcessEveryFrame.HasValue;
        EditorGUI.BeginDisabledGroup((!initialFixedDeltaTime.HasValue || !initialFixedDeltaTime.Value) && !resourceUpdateModeProperty.hasMultipleDifferentValues);

#if CASE_1289829_HAS_BEEN_FIXED
        newExactFixedTimeStep = EditorGUILayout.Toggle(processEveryFrameContent, initialProcessEveryFrame ?? false);
#endif

        EditorGUI.EndDisabledGroup();
        EditorGUI.showMixedValue = !initialIgnoreGameTimeScale.HasValue;
        bool newIgnoreTimeScale = EditorGUILayout.Toggle(ignoreTimeScaleContent, initialIgnoreGameTimeScale ?? false);

        if (EditorGUI.EndChangeCheck())
        {
            if (!resourceUpdateModeProperty.hasMultipleDifferentValues)
            {
                var newUpdateMode = (VFXUpdateMode)0;
                if (!newFixedDeltaTime)
                {
                    newUpdateMode = newUpdateMode | VFXUpdateMode.DeltaTime;
                }
                if (newExactFixedTimeStep)
                {
                    newUpdateMode = newUpdateMode | VFXUpdateMode.ExactFixedTimeStep;
                }
                if (newIgnoreTimeScale)
                {
                    newUpdateMode = newUpdateMode | VFXUpdateMode.IgnoreTimeScale;
                }

                resourceUpdateModeProperty.intValue = (int)newUpdateMode;
                resourceObject.ApplyModifiedProperties();
            }
            else
            {
                var resourceUpdateModeProperties = resourceUpdateModeProperty.serializedObject.targetObjects.Select(o => new SerializedObject(o).FindProperty(resourceUpdateModeProperty.propertyPath));
                foreach (var property in resourceUpdateModeProperties)
                {
                    var updateMode = (VFXUpdateMode)property.intValue;

                    if (initialFixedDeltaTime.HasValue)
                    {
                        if (!newFixedDeltaTime)
                        {
                            updateMode = updateMode | VFXUpdateMode.DeltaTime;
                        }
                        else
                        {
                            updateMode = updateMode & ~VFXUpdateMode.DeltaTime;
                        }
                    }
                    else
                    {
                        if (newFixedDeltaTime)
                        {
                            updateMode = updateMode & ~VFXUpdateMode.DeltaTime;
                        }
                    }

                    if (newExactFixedTimeStep)
                    {
                        updateMode = updateMode | VFXUpdateMode.ExactFixedTimeStep;
                    }
                    else if (initialProcessEveryFrame.HasValue)
                    {
                        updateMode = updateMode & ~VFXUpdateMode.ExactFixedTimeStep;
                    }

                    if (newIgnoreTimeScale)
                    {
                        updateMode = updateMode | VFXUpdateMode.IgnoreTimeScale;
                    }
                    else if (initialIgnoreGameTimeScale.HasValue)
                    {
                        updateMode = updateMode & ~VFXUpdateMode.IgnoreTimeScale;
                    }

                    property.intValue = (int)updateMode;
                    property.serializedObject.ApplyModifiedProperties();
                }
            }
        }

        EditorGUILayout.BeginHorizontal();
        EditorGUI.showMixedValue = cullingFlagsProperty.hasMultipleDifferentValues;
        EditorGUILayout.PrefixLabel(EditorGUIUtility.TrTextContent("Culling Flags", "Specifies how the system recomputes its bounds and simulates when off-screen."));
        EditorGUI.BeginChangeCheck();
        int newOption = EditorGUILayout.Popup(Array.IndexOf(k_CullingOptionsValue, (VFXCullingFlags)cullingFlagsProperty.intValue), k_CullingOptionsContents);
        if (EditorGUI.EndChangeCheck())
        {
            cullingFlagsProperty.intValue = (int)k_CullingOptionsValue[newOption];
            resourceObject.ApplyModifiedProperties();
        }
        EditorGUILayout.EndHorizontal();

        VisualEffectEditor.ShowHeader(EditorGUIUtility.TrTextContent("Initial state"), false, false);
        if (prewarmDeltaTime != null && prewarmStepCount != null)
        {
            if (!prewarmDeltaTime.hasMultipleDifferentValues && !prewarmStepCount.hasMultipleDifferentValues)
            {
                var currentDeltaTime = prewarmDeltaTime.floatValue;
                var currentStepCount = prewarmStepCount.intValue;
                var currentTotalTime = currentDeltaTime * currentStepCount;
                EditorGUI.BeginChangeCheck();
                currentTotalTime = EditorGUILayout.FloatField(EditorGUIUtility.TrTextContent("PreWarm Total Time", "Sets the time in seconds to advance the current effect to when it is initially played. "), currentTotalTime);
                if (EditorGUI.EndChangeCheck())
                {
                    if (currentStepCount <= 0)
                    {
                        prewarmStepCount.intValue = currentStepCount = 1;
                    }

                    currentDeltaTime            = currentTotalTime / currentStepCount;
                    prewarmDeltaTime.floatValue = currentDeltaTime;
                    resourceObject.ApplyModifiedProperties();
                }

                EditorGUI.BeginChangeCheck();
                currentStepCount = EditorGUILayout.IntField(EditorGUIUtility.TrTextContent("PreWarm Step Count", "Sets the number of simulation steps the prewarm should be broken down to. "), currentStepCount);
                if (EditorGUI.EndChangeCheck())
                {
                    if (currentStepCount <= 0 && currentTotalTime != 0.0f)
                    {
                        prewarmStepCount.intValue = currentStepCount = 1;
                    }

                    currentDeltaTime            = currentTotalTime == 0.0f ? 0.0f : currentTotalTime / currentStepCount;
                    prewarmDeltaTime.floatValue = currentDeltaTime;
                    prewarmStepCount.intValue   = currentStepCount;
                    resourceObject.ApplyModifiedProperties();
                }

                EditorGUI.BeginChangeCheck();
                currentDeltaTime = EditorGUILayout.FloatField(EditorGUIUtility.TrTextContent("PreWarm Delta Time", "Sets the time in seconds for each step to achieve the desired total prewarm time."), currentDeltaTime);
                if (EditorGUI.EndChangeCheck())
                {
                    if (currentDeltaTime < k_MinimalCommonDeltaTime)
                    {
                        prewarmDeltaTime.floatValue = currentDeltaTime = k_MinimalCommonDeltaTime;
                    }

                    if (currentDeltaTime > currentTotalTime)
                    {
                        currentTotalTime = currentDeltaTime;
                    }

                    if (currentTotalTime != 0.0f)
                    {
                        var candidateStepCount_A = Mathf.FloorToInt(currentTotalTime / currentDeltaTime);
                        var candidateStepCount_B = Mathf.RoundToInt(currentTotalTime / currentDeltaTime);

                        var totalTime_A = currentDeltaTime * candidateStepCount_A;
                        var totalTime_B = currentDeltaTime * candidateStepCount_B;

                        if (Mathf.Abs(totalTime_A - currentTotalTime) < Mathf.Abs(totalTime_B - currentTotalTime))
                        {
                            currentStepCount = candidateStepCount_A;
                        }
                        else
                        {
                            currentStepCount = candidateStepCount_B;
                        }

                        prewarmStepCount.intValue = currentStepCount;
                    }
                    prewarmDeltaTime.floatValue = currentDeltaTime;
                    resourceObject.ApplyModifiedProperties();
                }
            }
            else
            {
                //Multi selection case, can't resolve total time easily
                EditorGUI.BeginChangeCheck();
                EditorGUI.showMixedValue = prewarmStepCount.hasMultipleDifferentValues;
                EditorGUILayout.PropertyField(prewarmStepCount, EditorGUIUtility.TrTextContent("PreWarm Step Count", "Sets the number of simulation steps the prewarm should be broken down to."));
                EditorGUI.showMixedValue = prewarmDeltaTime.hasMultipleDifferentValues;
                EditorGUILayout.PropertyField(prewarmDeltaTime, EditorGUIUtility.TrTextContent("PreWarm Delta Time", "Sets the time in seconds for each step to achieve the desired total prewarm time."));
                if (EditorGUI.EndChangeCheck())
                {
                    if (prewarmDeltaTime.floatValue < k_MinimalCommonDeltaTime)
                    {
                        prewarmDeltaTime.floatValue = k_MinimalCommonDeltaTime;
                    }
                    resourceObject.ApplyModifiedProperties();
                }
            }
        }

        if (initialEventName != null)
        {
            EditorGUI.BeginChangeCheck();
            EditorGUI.showMixedValue = initialEventName.hasMultipleDifferentValues;
            EditorGUILayout.PropertyField(initialEventName, new GUIContent("Initial Event Name", "Sets the name of the event which triggers once the system is activated. Default: ‘OnPlay’."));
            if (EditorGUI.EndChangeCheck())
            {
                resourceObject.ApplyModifiedProperties();
            }
        }

        if (!serializedObject.isEditingMultipleObjects)
        {
            VisualEffectAsset    asset    = (VisualEffectAsset)target;
            VisualEffectResource resource = asset.GetResource();

            m_OutputContexts.Clear();
            m_OutputContexts.AddRange(resource.GetOrCreateGraph().children.OfType <IVFXSubRenderer>().OrderBy(t => t.sortPriority));

            m_ReorderableList.DoLayoutList();

            VisualEffectEditor.ShowHeader(EditorGUIUtility.TrTextContent("Shaders"), false, false);

            string        assetPath = AssetDatabase.GetAssetPath(asset);
            UnityObject[] objects   = AssetDatabase.LoadAllAssetsAtPath(assetPath);
            string        directory = Path.GetDirectoryName(assetPath) + "/" + VFXExternalShaderProcessor.k_ShaderDirectory + "/" + asset.name + "/";

            foreach (var obj in objects)
            {
                if (obj is Material || obj is ComputeShader)
                {
                    GUILayout.BeginHorizontal();
                    Rect r = GUILayoutUtility.GetRect(0, 18, GUILayout.ExpandWidth(true));

                    int buttonsWidth = VFXExternalShaderProcessor.allowExternalization ? 240 : 160;

                    int index = resource.GetShaderIndex(obj);

                    var shader = obj;
                    if (obj is Material) // Retrieve the shader from the material
                    {
                        shader = ((Material)(obj)).shader;
                    }
                    if (shader == null)
                    {
                        continue;
                    }

                    Rect labelR = r;
                    labelR.width -= buttonsWidth;
                    GUI.Label(labelR, shader.name);

                    if (index >= 0)
                    {
                        if (VFXExternalShaderProcessor.allowExternalization && index < resource.GetShaderSourceCount())
                        {
                            string shaderSourceName = resource.GetShaderSourceName(index);
                            string externalPath     = directory + shaderSourceName;

                            externalPath = directory + shaderSourceName.Replace('/', '_') + VFXExternalShaderProcessor.k_ShaderExt;

                            Rect buttonRect = r;
                            buttonRect.xMin  = labelR.xMax;
                            buttonRect.width = 80;
                            labelR.width    += 80;
                            if (System.IO.File.Exists(externalPath))
                            {
                                if (GUI.Button(buttonRect, "Reveal External"))
                                {
                                    EditorUtility.RevealInFinder(externalPath);
                                }
                            }
                            else
                            {
                                if (GUI.Button(buttonRect, "Externalize"))
                                {
                                    Directory.CreateDirectory(directory);

                                    File.WriteAllText(externalPath, "//" + shaderSourceName + "," + index.ToString() + "\n//Don't delete the previous line or this one\n" + resource.GetShaderSource(index));
                                }
                            }
                        }

                        Rect buttonR = r;
                        buttonR.xMin  = labelR.xMax;
                        buttonR.width = 110;
                        labelR.width += 110;
                        if (GUI.Button(buttonR, "Show Generated"))
                        {
                            resource.ShowGeneratedShaderFile(index);
                        }
                    }

                    Rect selectButtonR = r;
                    selectButtonR.xMin  = labelR.xMax;
                    selectButtonR.width = 50;
                    if (GUI.Button(selectButtonR, "Select"))
                    {
                        Selection.activeObject = shader;
                    }
                    GUILayout.EndHorizontal();
                }
            }
        }
        GUI.enabled = false;
    }
Beispiel #5
0
    public override void OnInspectorGUI()
    {
        resourceObject.Update();

        GUI.enabled = AssetDatabase.IsOpenForEdit(this.target, StatusQueryOptions.UseCachedIfPossible);

        VFXUpdateMode initialUpdateMode          = (VFXUpdateMode)0;
        bool?         initialFixedDeltaTime      = null;
        bool?         initialProcessEveryFrame   = null;
        bool?         initialIgnoreGameTimeScale = null;

        if (resourceUpdateModeProperty.hasMultipleDifferentValues)
        {
            var resourceUpdateModeProperties = resourceUpdateModeProperty.serializedObject.targetObjects
                                               .Select(o => new SerializedObject(o)
                                                       .FindProperty(resourceUpdateModeProperty.propertyPath))
                                               .ToArray();  //N.B.: This will create garbage
            var allDeltaTime = resourceUpdateModeProperties.Select(o => ((VFXUpdateMode)o.intValue & VFXUpdateMode.DeltaTime) == VFXUpdateMode.DeltaTime)
                               .Distinct();
            var allProcessEveryFrame = resourceUpdateModeProperties.Select(o => ((VFXUpdateMode)o.intValue & VFXUpdateMode.ExactFixedTimeStep) == VFXUpdateMode.ExactFixedTimeStep)
                                       .Distinct();
            var allIgnoreScale = resourceUpdateModeProperties.Select(o => ((VFXUpdateMode)o.intValue & VFXUpdateMode.IgnoreTimeScale) == VFXUpdateMode.IgnoreTimeScale)
                                 .Distinct();
            if (allDeltaTime.Count() == 1)
            {
                initialFixedDeltaTime = !allDeltaTime.First();
            }
            if (allProcessEveryFrame.Count() == 1)
            {
                initialProcessEveryFrame = allProcessEveryFrame.First();
            }
            if (allIgnoreScale.Count() == 1)
            {
                initialIgnoreGameTimeScale = allIgnoreScale.First();
            }
        }
        else
        {
            initialUpdateMode          = (VFXUpdateMode)resourceUpdateModeProperty.intValue;
            initialFixedDeltaTime      = !((initialUpdateMode & VFXUpdateMode.DeltaTime) == VFXUpdateMode.DeltaTime);
            initialProcessEveryFrame   = (initialUpdateMode & VFXUpdateMode.ExactFixedTimeStep) == VFXUpdateMode.ExactFixedTimeStep;
            initialIgnoreGameTimeScale = (initialUpdateMode & VFXUpdateMode.IgnoreTimeScale) == VFXUpdateMode.IgnoreTimeScale;
        }

        EditorGUI.showMixedValue = !initialFixedDeltaTime.HasValue;
        var deltaTimeContent         = EditorGUIUtility.TrTextContent("Fixed Delta Time", "If enabled, use visual effect manager fixed delta time mode, otherwise, use the default Time.deltaTime.");
        var processEveryFrameContent = EditorGUIUtility.TrTextContent("Exact Fixed Time", "Only relevant when using Fixed Delta Time. When enabled, several updates can be processed per frame (e.g.: if a frame is 10ms and the fixed frame rate is set to 5 ms, the effect will update twice with a 5ms deltaTime instead of once with a 10ms deltaTime). This method is expensive and should only be used for high-end scenarios.");
        var ignoreTimeScaleContent   = EditorGUIUtility.TrTextContent("Ignore Time Scale", "When enabled, the computed visual effect delta time ignores the game Time Scale value (Play Rate is still applied).");

        EditorGUI.BeginChangeCheck();

        VisualEffectEditor.ShowHeader(EditorGUIUtility.TrTextContent("Update mode"), false, false);
        bool newFixedDeltaTime     = EditorGUILayout.Toggle(deltaTimeContent, initialFixedDeltaTime ?? false);
        bool newExactFixedTimeStep = false;

        EditorGUI.showMixedValue = !initialProcessEveryFrame.HasValue;
        EditorGUI.BeginDisabledGroup((!initialFixedDeltaTime.HasValue || !initialFixedDeltaTime.Value) && !resourceUpdateModeProperty.hasMultipleDifferentValues);
        newExactFixedTimeStep = EditorGUILayout.Toggle(processEveryFrameContent, initialProcessEveryFrame ?? false);
        EditorGUI.EndDisabledGroup();
        EditorGUI.showMixedValue = !initialIgnoreGameTimeScale.HasValue;
        bool newIgnoreTimeScale = EditorGUILayout.Toggle(ignoreTimeScaleContent, initialIgnoreGameTimeScale ?? false);

        if (EditorGUI.EndChangeCheck())
        {
            if (!resourceUpdateModeProperty.hasMultipleDifferentValues)
            {
                var newUpdateMode = (VFXUpdateMode)0;
                if (!newFixedDeltaTime)
                {
                    newUpdateMode = newUpdateMode | VFXUpdateMode.DeltaTime;
                }
                if (newExactFixedTimeStep)
                {
                    newUpdateMode = newUpdateMode | VFXUpdateMode.ExactFixedTimeStep;
                }
                if (newIgnoreTimeScale)
                {
                    newUpdateMode = newUpdateMode | VFXUpdateMode.IgnoreTimeScale;
                }

                resourceUpdateModeProperty.intValue = (int)newUpdateMode;
                resourceObject.ApplyModifiedProperties();
            }
            else
            {
                var resourceUpdateModeProperties = resourceUpdateModeProperty.serializedObject.targetObjects.Select(o => new SerializedObject(o).FindProperty(resourceUpdateModeProperty.propertyPath));
                foreach (var property in resourceUpdateModeProperties)
                {
                    var updateMode = (VFXUpdateMode)property.intValue;

                    if (initialFixedDeltaTime.HasValue)
                    {
                        if (!newFixedDeltaTime)
                        {
                            updateMode = updateMode | VFXUpdateMode.DeltaTime;
                        }
                        else
                        {
                            updateMode = updateMode & ~VFXUpdateMode.DeltaTime;
                        }
                    }
                    else
                    {
                        if (newFixedDeltaTime)
                        {
                            updateMode = updateMode & ~VFXUpdateMode.DeltaTime;
                        }
                    }

                    if (newExactFixedTimeStep)
                    {
                        updateMode = updateMode | VFXUpdateMode.ExactFixedTimeStep;
                    }
                    else if (initialProcessEveryFrame.HasValue)
                    {
                        updateMode = updateMode & ~VFXUpdateMode.ExactFixedTimeStep;
                    }

                    if (newIgnoreTimeScale)
                    {
                        updateMode = updateMode | VFXUpdateMode.IgnoreTimeScale;
                    }
                    else if (initialIgnoreGameTimeScale.HasValue)
                    {
                        updateMode = updateMode & ~VFXUpdateMode.IgnoreTimeScale;
                    }

                    property.intValue = (int)updateMode;
                    property.serializedObject.ApplyModifiedProperties();
                }
            }
        }
        VisualEffectAsset    asset    = (VisualEffectAsset)target;
        VisualEffectResource resource = asset.GetResource();

        //The following should be working, and works for newly created systems, but fails for old systems,
        //due probably to incorrectly pasting the VFXData when creating them.
        // bool hasAutomaticBoundsSystems = resource.GetOrCreateGraph().children
        //     .OfType<VFXDataParticle>().Any(d => d.boundsMode == BoundsSettingMode.Automatic);

        bool hasAutomaticBoundsSystems = resource.GetOrCreateGraph().children
                                         .OfType <VFXBasicInitialize>().Any(d => (d.GetData() as VFXDataParticle).boundsMode == BoundsSettingMode.Automatic);

        using (new EditorGUI.DisabledScope(hasAutomaticBoundsSystems))
        {
            EditorGUILayout.BeginHorizontal();
            EditorGUI.showMixedValue = cullingFlagsProperty.hasMultipleDifferentValues;
            string forceSimulateTooltip = hasAutomaticBoundsSystems
                ? " When using systems with Bounds Mode set to Automatic, this has to be set to Always recompute bounds and simulate."
                : "";
            EditorGUILayout.PrefixLabel(EditorGUIUtility.TrTextContent("Culling Flags", "Specifies how the system recomputes its bounds and simulates when off-screen." + forceSimulateTooltip));
            EditorGUI.BeginChangeCheck();

            int newOption =
                EditorGUILayout.Popup(
                    Array.IndexOf(k_CullingOptionsValue, (VFXCullingFlags)cullingFlagsProperty.intValue),
                    k_CullingOptionsContents);
            if (EditorGUI.EndChangeCheck())
            {
                cullingFlagsProperty.intValue = (int)k_CullingOptionsValue[newOption];
                resourceObject.ApplyModifiedProperties();
            }
        }

        EditorGUILayout.EndHorizontal();

        VisualEffectEditor.ShowHeader(EditorGUIUtility.TrTextContent("Initial state"), false, false);
        if (prewarmDeltaTime != null && prewarmStepCount != null)
        {
            DisplayPrewarmInspectorGUI(resourceObject, prewarmDeltaTime, prewarmStepCount);
        }

        if (initialEventName != null)
        {
            EditorGUI.BeginChangeCheck();
            EditorGUI.showMixedValue = initialEventName.hasMultipleDifferentValues;
            EditorGUILayout.PropertyField(initialEventName, new GUIContent("Initial Event Name", "Sets the name of the event which triggers once the system is activated. Default: ‘OnPlay’."));
            if (EditorGUI.EndChangeCheck())
            {
                resourceObject.ApplyModifiedProperties();
            }
        }

        if (!serializedObject.isEditingMultipleObjects)
        {
            asset    = (VisualEffectAsset)target;
            resource = asset.GetResource();

            m_OutputContexts.Clear();
            m_OutputContexts.AddRange(resource.GetOrCreateGraph().children.OfType <IVFXSubRenderer>().OrderBy(t => t.vfxSystemSortPriority));

            m_ReorderableList.DoLayoutList();

            VisualEffectEditor.ShowHeader(EditorGUIUtility.TrTextContent("Shaders"), false, false);

            string        assetPath = AssetDatabase.GetAssetPath(asset);
            UnityObject[] objects   = AssetDatabase.LoadAllAssetsAtPath(assetPath);
            string        directory = Path.GetDirectoryName(assetPath) + "/" + VFXExternalShaderProcessor.k_ShaderDirectory + "/" + asset.name + "/";

            foreach (var obj in objects)
            {
                if (obj is Material || obj is ComputeShader)
                {
                    GUILayout.BeginHorizontal();
                    Rect r = GUILayoutUtility.GetRect(0, 18, GUILayout.ExpandWidth(true));

                    int buttonsWidth = VFXExternalShaderProcessor.allowExternalization ? 240 : 160;

                    int index = resource.GetShaderIndex(obj);

                    var shader = obj;
                    if (obj is Material) // Retrieve the shader from the material
                    {
                        shader = ((Material)(obj)).shader;
                    }
                    if (shader == null)
                    {
                        continue;
                    }

                    Rect labelR = r;
                    labelR.width -= buttonsWidth;
                    GUI.Label(labelR, shader.name.Replace('\n', ' '));

                    if (index >= 0)
                    {
                        if (VFXExternalShaderProcessor.allowExternalization && index < resource.GetShaderSourceCount())
                        {
                            string shaderSourceName = resource.GetShaderSourceName(index);
                            string externalPath     = directory + shaderSourceName;

                            externalPath = directory + shaderSourceName.Replace('/', '_') + VFXExternalShaderProcessor.k_ShaderExt;

                            Rect buttonRect = r;
                            buttonRect.xMin  = labelR.xMax;
                            buttonRect.width = 80;
                            labelR.width    += 80;
                            if (System.IO.File.Exists(externalPath))
                            {
                                if (GUI.Button(buttonRect, "Reveal External"))
                                {
                                    EditorUtility.RevealInFinder(externalPath);
                                }
                            }
                            else
                            {
                                if (GUI.Button(buttonRect, "Externalize"))
                                {
                                    Directory.CreateDirectory(directory);

                                    File.WriteAllText(externalPath, "//" + shaderSourceName + "," + index.ToString() + "\n//Don't delete the previous line or this one\n" + resource.GetShaderSource(index));
                                }
                            }
                        }

                        Rect buttonR = r;
                        buttonR.xMin  = labelR.xMax;
                        buttonR.width = 110;
                        labelR.width += 110;
                        if (GUI.Button(buttonR, "Show Generated"))
                        {
                            resource.ShowGeneratedShaderFile(index);
                        }
                    }

                    Rect selectButtonR = r;
                    selectButtonR.xMin  = labelR.xMax;
                    selectButtonR.width = 50;
                    if (GUI.Button(selectButtonR, "Select"))
                    {
                        Selection.activeObject = shader;
                    }
                    GUILayout.EndHorizontal();
                }
            }
        }
        GUI.enabled = false;
    }