using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using UnityEditor.SceneManagement; using UnityEngine; using UnityEditor.Search; using UnityEditor.UIElements; using UnityEngine.UIElements; using UnityEngine.Assertions; using UnityEngine.Rendering; using UnityEngine.SceneManagement; using UnityEditor.Rendering.Analytics; namespace UnityEditor.Rendering.Universal { // Status for each row item to say in which state they are in. // This will make sure they are showing the correct icon [Serializable] enum Status { Pending, Warning, Error, Success } // This is the serialized class that stores the state of each item in the list of items to convert [Serializable] class ConverterItemState { public bool isActive; // Message that will be displayed on the icon if warning or failed. public string message; // Status of the converted item, Pending, Warning, Error or Success public Status status; internal bool hasConverted = false; } // Each converter uses the active bool // Each converter has a list of active items/assets // We do this so that we can use the binding system of the UI Elements [Serializable] class ConverterState { // This is the enabled state of the whole converter public bool isEnabled; public bool isActive; public bool isLoading; // to name public bool isInitialized; public List items = new List(); public int pending; public int warnings; public int errors; public int success; internal int index; public bool isActiveAndEnabled => isEnabled && isActive; public bool requiresInitialization => !isInitialized && isActiveAndEnabled; } [Serializable] internal struct ConverterItems { public List itemDescriptors; } [Serializable] [EditorWindowTitle(title = "Render Pipeline Converters")] internal class RenderPipelineConvertersEditor : EditorWindow { Tuple converterStateInfoDisabled; Tuple converterStateInfoPendingInitialization; Tuple converterStateInfoPendingConversion; Tuple converterStateInfoPendingConversionWarning; Tuple converterStateInfoCompleteErrors; Tuple converterStateInfoComplete; public VisualTreeAsset converterEditorAsset; public VisualTreeAsset converterItem; public VisualTreeAsset converterWidgetMainAsset; ScrollView m_ScrollView; VisualElement m_ConverterSelectedVE; Button m_ConvertButton; Button m_InitButton; Button m_InitAnConvertButton; Button m_ContainerHelpButton; bool m_InitAndConvert; List m_CoreConvertersList = new List(); List m_VEList = new List(); // This list needs to be as long as the amount of converters List m_ItemsToConvert = new List(); //List> m_ItemsToConvert = new List>(); SerializedObject m_SerializedObject; List m_ContainerChoices = new List(); List m_Containers = new List(); int m_ContainerChoiceIndex = 0; int m_WorkerCount; // This is a list of Converter States which holds a list of which converter items/assets are active // There is one for each Converter. [SerializeField] List m_ConverterStates = new List(); TypeCache.TypeCollection m_ConverterContainers; RenderPipelineConverterContainer currentContainer => m_Containers[m_ContainerChoiceIndex]; // Name of the index file string m_URPConverterIndex = "URPConverterIndex"; [MenuItem("Window/Rendering/Render Pipeline Converter", false, 50)] public static void ShowWindow() { RenderPipelineConvertersEditor wnd = GetWindow(); wnd.titleContent = new GUIContent("Render Pipeline Converter"); DontSaveToLayout(wnd); wnd.minSize = new Vector2(650f, 400f); wnd.Show(); } internal static void DontSaveToLayout(EditorWindow wnd) { // Making sure that the window is not saved in layouts. Assembly assembly = typeof(EditorWindow).Assembly; var editorWindowType = typeof(EditorWindow); var hostViewType = assembly.GetType("UnityEditor.HostView"); var containerWindowType = assembly.GetType("UnityEditor.ContainerWindow"); var parentViewField = editorWindowType.GetField("m_Parent", BindingFlags.Instance | BindingFlags.NonPublic); var parentViewValue = parentViewField.GetValue(wnd); // window should not be saved to layout var containerWindowProperty = hostViewType.GetProperty("window", BindingFlags.Instance | BindingFlags.Public); var parentContainerWindowValue = containerWindowProperty.GetValue(parentViewValue); var dontSaveToLayoutField = containerWindowType.GetField("m_DontSaveToLayout", BindingFlags.Instance | BindingFlags.NonPublic); dontSaveToLayoutField.SetValue(parentContainerWindowValue, true); } void OnEnable() { InitIfNeeded(); GraphicsToolLifetimeAnalytic.WindowOpened(); } private void OnDisable() { GraphicsToolLifetimeAnalytic.WindowClosed(); } void InitIfNeeded() { if (m_CoreConvertersList.Any()) return; m_CoreConvertersList = new List(); // This is the drop down choices. m_ConverterContainers = TypeCache.GetTypesDerivedFrom(); foreach (var containerType in m_ConverterContainers) { var container = (RenderPipelineConverterContainer)Activator.CreateInstance(containerType); m_Containers.Add(container); } // this need to be sorted by Priority property m_Containers = m_Containers .OrderBy(o => o.priority).ToList(); foreach (var container in m_Containers) { m_ContainerChoices.Add(container.name); } if (m_ConverterContainers.Any()) { GetConverters(); } else { ClearConverterStates(); } } void ClearConverterStates() { m_CoreConvertersList.Clear(); m_ConverterStates.Clear(); m_ItemsToConvert.Clear(); m_VEList.Clear(); } void GetConverters() { ClearConverterStates(); var converterList = TypeCache.GetTypesDerivedFrom(); for (int i = 0; i < converterList.Count; ++i) { // Iterate over the converters that are used by the current container RenderPipelineConverter conv = (RenderPipelineConverter)Activator.CreateInstance(converterList[i]); m_CoreConvertersList.Add(conv); } // this need to be sorted by Priority property m_CoreConvertersList = m_CoreConvertersList .OrderBy(o => o.priority).ToList(); for (int i = 0; i < m_CoreConvertersList.Count; i++) { // Create a new ConvertState which holds the active state of the converter var converterState = new ConverterState { isEnabled = m_CoreConvertersList[i].isEnabled, isActive = false, isInitialized = false, items = new List(), index = i, }; m_ConverterStates.Add(converterState); // This just creates empty entries in the m_ItemsToConvert. // This list need to have the same amount of entries as the converters List converterItemInfos = new List(); m_ItemsToConvert.Add(new ConverterItems { itemDescriptors = converterItemInfos }); } } public void CreateGUI() { converterStateInfoDisabled = new("Converter Disabled", null); converterStateInfoPendingInitialization = new("Pending Initialization", CoreEditorStyles.iconPending); converterStateInfoPendingConversion = new("Pending Conversion", CoreEditorStyles.iconPending); converterStateInfoPendingConversionWarning = new("Pending Conversion with Warnings", CoreEditorStyles.iconWarn); converterStateInfoCompleteErrors = new("Conversion Complete with Errors", CoreEditorStyles.iconFail); converterStateInfoComplete = new("Conversion Complete", CoreEditorStyles.iconComplete); string theme = EditorGUIUtility.isProSkin ? "dark" : "light"; InitIfNeeded(); if (m_ConverterContainers.Any()) { m_SerializedObject = new SerializedObject(this); converterEditorAsset.CloneTree(rootVisualElement); rootVisualElement.Q("conversionsDropDown").choices = m_ContainerChoices; rootVisualElement.Q("conversionsDropDown").index = m_ContainerChoiceIndex; // Getting the scrollview where the converters should be added m_ScrollView = rootVisualElement.Q("convertersScrollView"); m_ConvertButton = rootVisualElement.Q