using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using UnityEngine; using UnityEditor.Search; using UnityEditor.UIElements; using UnityEngine.UIElements; using UnityEngine.Assertions; namespace UnityEditor.Rendering.Universal.Converters { // 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 { public VisualTreeAsset converterEditorAsset; public VisualTreeAsset converterListAsset; public VisualTreeAsset converterItem; ScrollView m_ScrollView; List m_CoreConvertersList = new List(); private bool convertButtonActive = false; // 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; // 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; // 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.maxSize = new Vector2(650f, 4000f); 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(); } void InitIfNeeded() { if (m_CoreConvertersList.Any()) return; m_CoreConvertersList = new List(); // This is the drop down choices. m_ConverterContainers = TypeCache.GetTypesDerivedFrom(); foreach (var continerType in m_ConverterContainers) { var container = (RenderPipelineConverterContainer)Activator.CreateInstance(continerType); m_Containers.Add(container); m_ContainerChoices.Add(container.name); } if (m_ConverterContainers.Any()) { GetConverters(); } else { ClearConverterStates(); } } void ClearConverterStates() { m_CoreConvertersList.Clear(); m_ConverterStates.Clear(); m_ItemsToConvert.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]); if (conv.container == m_ConverterContainers[m_ContainerChoiceIndex]) { 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(converterItemInfos); m_ItemsToConvert.Add(new ConverterItems { itemDescriptors = converterItemInfos }); } } public void CreateGUI() { 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; RecreateUI(); var button = rootVisualElement.Q