A game about forced loneliness, made by TACStudios
1using UnityEngine;
2using UnityEngine.Rendering;
3using System;
4using System.Collections.Generic;
5using UnityEngine.UIElements;
6using System.IO;
7using UnityEditor;
8using UnityEditor.UIElements;
9
10namespace UnityEditor.Rendering.LookDev
11{
12 /// <summary>
13 /// Class containing a collection of Environment
14 /// </summary>
15 [CoreRPHelpURL("Environment-Library")]
16 public class EnvironmentLibrary : ScriptableObject
17 {
18 [field: SerializeField]
19 List<Environment> environments { get; set; } = new List<Environment>();
20
21 /// <summary>
22 /// Number of elements in the collection
23 /// </summary>
24 public int Count => environments.Count;
25 /// <summary>
26 /// Indexer giving access to contained Environment
27 /// </summary>
28 /// <param name="index">The zero-based index of the environment to retrieve.</param>
29 /// <value>The Environment object at the specified index.</value>
30 public Environment this[int index] => environments[index];
31
32 /// <summary>
33 /// Create a new empty Environment at the end of the collection
34 /// </summary>
35 /// <returns>The created Environment</returns>
36 public Environment Add()
37 {
38 Undo.SetCurrentGroupName("Add Environment");
39 int group = Undo.GetCurrentGroup();
40
41 Environment environment = ScriptableObject.CreateInstance<Environment>();
42 environment.name = "New Environment";
43 Undo.RegisterCreatedObjectUndo(environment, "Add Environment");
44
45 Undo.RecordObject(this, "Add Environment");
46 environments.Add(environment);
47
48 // Store this new environment as a subasset so we can reference it safely afterwards.
49 AssetDatabase.AddObjectToAsset(environment, this);
50
51 Undo.CollapseUndoOperations(group);
52
53 // Force save / refresh. Important to do this last because SaveAssets can cause effect to become null!
54 EditorUtility.SetDirty(this);
55 AssetDatabase.SaveAssets();
56
57 return environment;
58 }
59
60 /// <summary>
61 /// Remove Environment of the collection at given index
62 /// </summary>
63 /// <param name="index">Index where to remove Environment</param>
64 public void Remove(int index)
65 {
66 Undo.SetCurrentGroupName("Remove Environment");
67 int group = Undo.GetCurrentGroup();
68
69 Environment environment = environments[index];
70 Undo.RecordObject(this, "Remove Environment");
71 environments.RemoveAt(index);
72 Undo.DestroyObjectImmediate(environment);
73
74 Undo.CollapseUndoOperations(group);
75
76 // Force save / refresh
77 EditorUtility.SetDirty(this);
78 AssetDatabase.SaveAssets();
79 }
80
81 /// <summary>
82 /// Duplicate the Environment at given index and add it at the end of the Collection
83 /// </summary>
84 /// <param name="fromIndex">Index where to take data for duplication</param>
85 /// <returns>The created Environment</returns>
86 public Environment Duplicate(int fromIndex)
87 {
88 Undo.SetCurrentGroupName("Duplicate Environment");
89 int group = Undo.GetCurrentGroup();
90
91 Environment environment = ScriptableObject.CreateInstance<Environment>();
92 Environment environmentToCopy = environments[fromIndex];
93 environmentToCopy.CopyTo(environment);
94
95 Undo.RegisterCreatedObjectUndo(environment, "Duplicate Environment");
96 Undo.RecordObject(this, "Duplicate Environment");
97 environments.Add(environment);
98
99 // Store this new environment as a subasset so we can reference it safely afterwards.
100 AssetDatabase.AddObjectToAsset(environment, this);
101
102 Undo.CollapseUndoOperations(group);
103
104 // Force save / refresh. Important to do this last because SaveAssets can cause effect to become null!
105 EditorUtility.SetDirty(this);
106 AssetDatabase.SaveAssets();
107
108 return environment;
109 }
110
111 /// <summary>
112 /// Compute position of given Environment in the collection
113 /// </summary>
114 /// <param name="environment">Environment to look at</param>
115 /// <returns>Index of the searched environment. If not found, -1.</returns>
116 public int IndexOf(Environment environment)
117 => environments.IndexOf(environment);
118 }
119
120 [CustomEditor(typeof(EnvironmentLibrary))]
121 class EnvironmentLibraryEditor : Editor
122 {
123 VisualElement m_Root;
124 VisualElement m_OpenButton;
125
126 public sealed override VisualElement CreateInspectorGUI()
127 {
128 var library = target as EnvironmentLibrary;
129 m_Root = new VisualElement();
130
131 m_OpenButton = new Button(() =>
132 {
133 if (!LookDev.open)
134 LookDev.Open();
135 LookDev.currentContext.UpdateEnvironmentLibrary(library);
136 LookDev.currentEnvironmentDisplayer.Repaint();
137 })
138 {
139 text = "Open in Look Dev window"
140 };
141 m_OpenButton.SetEnabled(LookDev.supported);
142
143 m_Root.Add(m_OpenButton);
144 return m_Root;
145 }
146
147 void OnEnable() => EditorApplication.update += Update;
148 void OnDisable() => EditorApplication.update -= Update;
149
150 void Update()
151 {
152 // Current SRP can be changed at any time so we need to do this at every update.
153 if (m_OpenButton != null)
154 m_OpenButton.SetEnabled(LookDev.supported);
155 }
156
157 // Don't use ImGUI
158 public sealed override void OnInspectorGUI() { }
159 }
160
161 class EnvironmentLibraryCreator : ProjectWindowCallback.EndNameEditAction
162 {
163 ObjectField m_Field = null;
164
165 public void SetField(ObjectField field)
166 => m_Field = field;
167
168 public override void Cancelled(int instanceId, string pathName, string resourceFile)
169 => m_Field = null;
170
171 public override void Action(int instanceId, string pathName, string resourceFile)
172 {
173 var newAsset = CreateInstance<EnvironmentLibrary>();
174 newAsset.name = Path.GetFileName(pathName);
175 AssetDatabase.CreateAsset(newAsset, pathName);
176 ProjectWindowUtil.ShowCreatedAsset(newAsset);
177 if (m_Field != null)
178 m_Field.value = newAsset;
179 m_Field = null;
180 }
181
182 [MenuItem("Assets/Create/Rendering/Environment Library (Look Dev)", priority = CoreUtils.Sections.section8 + CoreUtils.Priorities.assetsCreateRenderingMenuPriority)]
183 static void Create()
184 {
185 var icon = EditorGUIUtility.FindTexture("ScriptableObject Icon");
186 ProjectWindowUtil.StartNameEditingIfProjectWindowExists(0, ScriptableObject.CreateInstance<EnvironmentLibraryCreator>(), "New EnvironmentLibrary.asset", icon, null);
187 }
188
189 public static void CreateAndAssignTo(ObjectField field)
190 {
191 var icon = EditorGUIUtility.FindTexture("ScriptableObject Icon");
192 var assetCreator = ScriptableObject.CreateInstance<EnvironmentLibraryCreator>();
193 assetCreator.SetField(field);
194 ProjectWindowUtil.StartNameEditingIfProjectWindowExists(assetCreator.GetInstanceID(), assetCreator, "New EnvironmentLibrary.asset", icon, null);
195 }
196 }
197
198 static class EnvironmentLibraryLoader
199 {
200 static Action<UnityEngine.Object> LoadCallback(Action onUpdate)
201 {
202 return (UnityEngine.Object newLibrary) =>
203 {
204 LookDev.currentContext.UpdateEnvironmentLibrary(newLibrary as EnvironmentLibrary);
205 onUpdate?.Invoke();
206 };
207 }
208 }
209}