forked from BilalY/Rasagar
480 lines
20 KiB
C#
480 lines
20 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.IO;
|
|
using System.Linq;
|
|
using UnityEditor.Inspector.GraphicsSettingsInspectors;
|
|
using UnityEditorInternal;
|
|
using UnityEngine;
|
|
using UnityEngine.Rendering.HighDefinition;
|
|
using UnityEngine.UIElements;
|
|
using RenderingLayerMask = UnityEngine.RenderingLayerMask;
|
|
using UnityEngine.Rendering;
|
|
|
|
namespace UnityEditor.Rendering.HighDefinition
|
|
{
|
|
/// <summary>
|
|
/// A collection of utilities used by editor code of the HDRP.
|
|
/// </summary>
|
|
class HDEditorUtils
|
|
{
|
|
internal const string FormatingPath =
|
|
@"Packages/com.unity.render-pipelines.high-definition/Editor/USS/Formating";
|
|
|
|
internal const string QualitySettingsSheetPath =
|
|
@"Packages/com.unity.render-pipelines.high-definition/Editor/USS/QualitySettings";
|
|
|
|
internal const string WizardSheetPath =
|
|
@"Packages/com.unity.render-pipelines.high-definition/Editor/USS/Wizard";
|
|
|
|
internal const string HDRPAssetBuildLabel = "HDRP:IncludeInBuild";
|
|
|
|
internal static bool NeedsToBeIncludedInBuild(HDRenderPipelineAsset hdRenderPipelineAsset)
|
|
{
|
|
var labelList = AssetDatabase.GetLabels(hdRenderPipelineAsset);
|
|
foreach (string item in labelList)
|
|
{
|
|
if (item == HDUtils.k_HdrpAssetBuildLabel)
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private static (StyleSheet baseSkin, StyleSheet professionalSkin, StyleSheet personalSkin) LoadStyleSheets(string basePath)
|
|
=> (
|
|
AssetDatabase.LoadAssetAtPath<StyleSheet>($"{basePath}.uss"),
|
|
AssetDatabase.LoadAssetAtPath<StyleSheet>($"{basePath}Light.uss"),
|
|
AssetDatabase.LoadAssetAtPath<StyleSheet>($"{basePath}Dark.uss")
|
|
);
|
|
|
|
internal static void AddStyleSheets(VisualElement element, string baseSkinPath)
|
|
{
|
|
(StyleSheet @base, StyleSheet personal, StyleSheet professional) = LoadStyleSheets(baseSkinPath);
|
|
element.styleSheets.Add(@base);
|
|
if (EditorGUIUtility.isProSkin)
|
|
{
|
|
if (professional != null && !professional.Equals(null))
|
|
element.styleSheets.Add(professional);
|
|
}
|
|
else
|
|
{
|
|
if (personal != null && !personal.Equals(null))
|
|
element.styleSheets.Add(personal);
|
|
}
|
|
}
|
|
|
|
static readonly Action<SerializedProperty, GUIContent> k_DefaultDrawer = (p, l) => EditorGUILayout.PropertyField(p, l);
|
|
|
|
|
|
internal static T LoadAsset<T>(string relativePath) where T : UnityEngine.Object
|
|
=> AssetDatabase.LoadAssetAtPath<T>(HDUtils.GetHDRenderPipelinePath() + relativePath);
|
|
|
|
/// <summary>
|
|
/// Reset the dedicated Keyword and Pass regarding the shader kind.
|
|
/// Also re-init the drawers and set the material dirty for the engine.
|
|
/// </summary>
|
|
/// <param name="material">The material that nees to be setup</param>
|
|
/// <returns>
|
|
/// True: managed to do the operation.
|
|
/// False: unknown shader used in material
|
|
/// </returns>
|
|
[Obsolete("Use HDShaderUtils.ResetMaterialKeywords instead")]
|
|
public static bool ResetMaterialKeywords(Material material)
|
|
=> HDShaderUtils.ResetMaterialKeywords(material);
|
|
|
|
static readonly GUIContent s_OverrideTooltip = EditorGUIUtility.TrTextContent("", "Override this setting in component.");
|
|
|
|
internal static bool FlagToggle<TEnum>(TEnum v, SerializedProperty property)
|
|
where TEnum : struct, IConvertible // restrict to ~enum
|
|
{
|
|
var intV = (int)(object)v;
|
|
var isOn = (property.intValue & intV) != 0;
|
|
var rect = ReserveAndGetFlagToggleRect();
|
|
isOn = GUI.Toggle(rect, isOn, s_OverrideTooltip, CoreEditorStyles.smallTickbox);
|
|
if (isOn)
|
|
property.intValue |= intV;
|
|
else
|
|
property.intValue &= ~intV;
|
|
|
|
return isOn;
|
|
}
|
|
|
|
internal static Rect ReserveAndGetFlagToggleRect()
|
|
{
|
|
var rect = GUILayoutUtility.GetRect(11, 17, GUILayout.ExpandWidth(false));
|
|
rect.y += 4;
|
|
return rect;
|
|
}
|
|
|
|
internal static bool IsAssetPath(string path)
|
|
{
|
|
var isPathRooted = Path.IsPathRooted(path);
|
|
return isPathRooted && path.StartsWith(Application.dataPath)
|
|
|| !isPathRooted && path.StartsWith("Assets");
|
|
}
|
|
|
|
// Copy texture from cache
|
|
internal static bool CopyFileWithRetryOnUnauthorizedAccess(string s, string path)
|
|
{
|
|
UnauthorizedAccessException exception = null;
|
|
for (var k = 0; k < 20; ++k)
|
|
{
|
|
try
|
|
{
|
|
File.Copy(s, path, true);
|
|
exception = null;
|
|
}
|
|
catch (UnauthorizedAccessException e)
|
|
{
|
|
exception = e;
|
|
}
|
|
}
|
|
|
|
if (exception != null)
|
|
{
|
|
Debug.LogException(exception);
|
|
// Abort the update, something else is preventing the copy
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
internal static void PropertyFieldWithoutToggle<TEnum>(
|
|
TEnum v, SerializedProperty property, GUIContent label, TEnum displayed,
|
|
Action<SerializedProperty, GUIContent> drawer = null, int indent = 0
|
|
)
|
|
where TEnum : struct, IConvertible // restrict to ~enum
|
|
{
|
|
var intDisplayed = (int)(object)displayed;
|
|
var intV = (int)(object)v;
|
|
if ((intDisplayed & intV) == intV)
|
|
{
|
|
EditorGUILayout.BeginHorizontal();
|
|
|
|
var i = EditorGUI.indentLevel;
|
|
EditorGUI.indentLevel = i + indent;
|
|
(drawer ?? k_DefaultDrawer)(property, label);
|
|
EditorGUI.indentLevel = i;
|
|
|
|
EditorGUILayout.EndHorizontal();
|
|
}
|
|
}
|
|
|
|
internal static void DrawToolBarButton<TEnum>(
|
|
TEnum button, Editor owner,
|
|
Dictionary<TEnum, EditMode.SceneViewEditMode> toolbarMode,
|
|
Dictionary<TEnum, GUIContent> toolbarContent,
|
|
params GUILayoutOption[] options
|
|
)
|
|
where TEnum : struct, IConvertible
|
|
{
|
|
var intButton = (int)(object)button;
|
|
bool enabled = toolbarMode[button] == EditMode.editMode;
|
|
EditorGUI.BeginChangeCheck();
|
|
enabled = GUILayout.Toggle(enabled, toolbarContent[button], EditorStyles.miniButton, options);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
EditMode.SceneViewEditMode targetMode = EditMode.editMode == toolbarMode[button] ? EditMode.SceneViewEditMode.None : toolbarMode[button];
|
|
EditMode.ChangeEditMode(targetMode, GetBoundsGetter(owner)(), owner);
|
|
}
|
|
}
|
|
|
|
internal static Func<Bounds> GetBoundsGetter(Editor o)
|
|
{
|
|
return () =>
|
|
{
|
|
var bounds = new Bounds();
|
|
var rp = ((Component)o.target).transform;
|
|
var b = rp.position;
|
|
bounds.Encapsulate(b);
|
|
return bounds;
|
|
};
|
|
}
|
|
|
|
/// <summary>
|
|
/// Give a human readable string representing the inputed weight given in byte.
|
|
/// </summary>
|
|
/// <param name="weightInByte">The weigth in byte</param>
|
|
/// <returns>Human readable weight</returns>
|
|
internal static string HumanizeWeight(long weightInByte)
|
|
{
|
|
if (weightInByte < 500)
|
|
{
|
|
return weightInByte + " B";
|
|
}
|
|
else if (weightInByte < 500000L)
|
|
{
|
|
float res = weightInByte / 1000f;
|
|
return res.ToString("n2") + " KB";
|
|
}
|
|
else if (weightInByte < 500000000L)
|
|
{
|
|
float res = weightInByte / 1000000f;
|
|
return res.ToString("n2") + " MB";
|
|
}
|
|
else
|
|
{
|
|
float res = weightInByte / 1000000000f;
|
|
return res.ToString("n2") + " GB";
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Should be placed between BeginProperty / EndProperty
|
|
/// </summary>
|
|
internal static uint DrawRenderingLayerMask(Rect rect, uint renderingLayer, GUIContent label = null, bool allowHelpBox = true)
|
|
{
|
|
var value = EditorGUI.RenderingLayerMaskField(rect, label ?? GUIContent.none, renderingLayer);
|
|
return value;
|
|
}
|
|
|
|
internal static void DrawRenderingLayerMask(Rect rect, SerializedProperty property, GUIContent label)
|
|
{
|
|
EditorGUI.BeginProperty(rect, label, property);
|
|
|
|
EditorGUI.BeginChangeCheck();
|
|
var renderingLayer = DrawRenderingLayerMask(rect, property.uintValue, label);
|
|
if (EditorGUI.EndChangeCheck())
|
|
{
|
|
if(property.numericType == SerializedPropertyNumericType.UInt32)
|
|
property.uintValue = renderingLayer;
|
|
else
|
|
property.intValue = unchecked((int)renderingLayer);
|
|
}
|
|
|
|
EditorGUI.EndProperty();
|
|
}
|
|
|
|
internal static void DrawRenderingLayerMask(SerializedProperty property, GUIContent style)
|
|
{
|
|
Rect rect = EditorGUILayout.GetControlRect(true);
|
|
DrawRenderingLayerMask(rect, property, style);
|
|
}
|
|
|
|
// IsPreset is an internal API - lets reuse the usable part of this function
|
|
// 93 is a "magic number" and does not represent a combination of other flags here
|
|
internal static bool IsPresetEditor(UnityEditor.Editor editor)
|
|
{
|
|
return (int)((editor.target as Component).gameObject.hideFlags) == 93;
|
|
}
|
|
|
|
internal static void QualitySettingsHelpBox(string message, MessageType type, HDRenderPipelineUI.ExpandableGroup uiGroupSection, string propertyPath)
|
|
{
|
|
CoreEditorUtils.DrawFixMeBox(message, type, "Open", () =>
|
|
{
|
|
SettingsService.OpenProjectSettings("Project/Quality/HDRP");
|
|
HDRenderPipelineUI.Inspector.Expand((int)uiGroupSection);
|
|
CoreEditorUtils.Highlight("Project Settings", propertyPath, HighlightSearchMode.Identifier);
|
|
GUIUtility.ExitGUI();
|
|
});
|
|
}
|
|
|
|
internal static void QualitySettingsHelpBox<TEnum>(string message, MessageType type, HDRenderPipelineUI.ExpandableGroup uiGroupSection, TEnum uiSection, string propertyPath)
|
|
where TEnum : struct, IConvertible
|
|
{
|
|
QualitySettingsHelpBoxForReflection(message, type, uiGroupSection, uiSection.ToInt32(System.Globalization.CultureInfo.InvariantCulture), propertyPath);
|
|
}
|
|
|
|
internal static void QualitySettingsHelpBoxForReflection(string message, MessageType type, HDRenderPipelineUI.ExpandableGroup uiGroupSection, int uiSection, string propertyPath)
|
|
{
|
|
CoreEditorUtils.DrawFixMeBox(message, type, "Open", () =>
|
|
{
|
|
SettingsService.OpenProjectSettings("Project/Quality/HDRP");
|
|
HDRenderPipelineUI.SubInspectors[uiGroupSection].Expand(uiSection);
|
|
|
|
CoreEditorUtils.Highlight("Project Settings", propertyPath, HighlightSearchMode.Identifier);
|
|
GUIUtility.ExitGUI();
|
|
});
|
|
}
|
|
|
|
internal static void GlobalSettingsHelpBox<TGraphicsSettings>(string message, MessageType type)
|
|
where TGraphicsSettings: IRenderPipelineGraphicsSettings
|
|
{
|
|
CoreEditorUtils.DrawFixMeBox(message, type, "Open", () =>
|
|
{
|
|
GraphicsSettingsInspectorUtility.OpenAndScrollTo<TGraphicsSettings>();
|
|
});
|
|
}
|
|
|
|
internal static void GlobalSettingsHelpBox(string message, MessageType type, FrameSettingsField field, string displayName)
|
|
{
|
|
CoreEditorUtils.DrawFixMeBox(message, type, "Open", () =>
|
|
{
|
|
var attribute = FrameSettingsExtractedDatas.GetFieldAttribute(field);
|
|
|
|
GraphicsSettingsInspectorUtility.OpenAndScrollTo<RenderingPathFrameSettings, FrameSettingsArea.LineField>(line =>
|
|
{
|
|
if (line.name != $"line-field-{field}")
|
|
return false;
|
|
|
|
FrameSettingsPropertyDrawer.SetExpended(FrameSettingsRenderType.Camera.ToString(), attribute.group, true);
|
|
return true;
|
|
});
|
|
});
|
|
}
|
|
|
|
// This is used through reflection by inspector in srp core
|
|
static bool DataDrivenLensFlareHelpBox()
|
|
{
|
|
if (!HDRenderPipeline.currentAsset?.currentPlatformRenderPipelineSettings.supportDataDrivenLensFlare ?? false)
|
|
{
|
|
EditorGUILayout.Space();
|
|
HDEditorUtils.QualitySettingsHelpBox("The current HDRP Asset does not support Data Driven Lens Flare.", MessageType.Error,
|
|
HDRenderPipelineUI.ExpandableGroup.PostProcess, HDRenderPipelineUI.ExpandablePostProcess.LensFlare, "m_RenderPipelineSettings.supportDataDrivenLensFlare");
|
|
return false;
|
|
}
|
|
|
|
HDEditorUtils.EnsureFrameSetting(FrameSettingsField.LensFlareDataDriven, "Lens Flare Data Driven");
|
|
return true;
|
|
}
|
|
|
|
static void OpenRenderingDebugger(string panelName)
|
|
{
|
|
EditorApplication.ExecuteMenuItem("Window/Analysis/Rendering Debugger");
|
|
|
|
if (panelName != null)
|
|
{
|
|
var manager = DebugManager.instance;
|
|
manager.RequestEditorWindowPanelIndex(manager.FindPanelIndex(panelName));
|
|
}
|
|
}
|
|
|
|
static void HighlightInDebugger(HDCamera hdCamera, FrameSettingsField field, string displayName)
|
|
{
|
|
OpenRenderingDebugger(hdCamera.camera.name);
|
|
|
|
// Doesn't work for some reason
|
|
//CoreEditorUtils.Highlight("Rendering Debugger", displayName, HighlightSearchMode.Auto);
|
|
//GUIUtility.ExitGUI();
|
|
}
|
|
|
|
internal static void FrameSettingsHelpBox(HDCamera hdCamera, FrameSettingsField field, string displayName)
|
|
{
|
|
var data = HDUtils.TryGetAdditionalCameraDataOrDefault(hdCamera.camera);
|
|
var defaults = GraphicsSettings.GetRenderPipelineSettings<RenderingPathFrameSettings>().GetDefaultFrameSettings(FrameSettingsRenderType.Camera);
|
|
|
|
var type = MessageType.Warning;
|
|
var attribute = FrameSettingsExtractedDatas.GetFieldAttribute(field);
|
|
|
|
bool disabledInGlobal = !defaults.IsEnabled(field);
|
|
bool disabledByCamera = data.renderingPathCustomFrameSettingsOverrideMask.mask[(uint)field] &&
|
|
!data.renderingPathCustomFrameSettings.IsEnabled(field);
|
|
bool disabledByDependency = !attribute.dependencies.All(hdCamera.frameSettings.IsEnabled);
|
|
|
|
var historyContainer = hdCamera.camera.cameraType == CameraType.SceneView
|
|
? FrameSettingsHistory.sceneViewFrameSettingsContainer
|
|
: HDUtils.TryGetAdditionalCameraDataOrDefault(hdCamera.camera);
|
|
bool disabledByDebug = FrameSettingsHistory.enabled && !historyContainer.frameSettingsHistory.debug.IsEnabled(field) && historyContainer.frameSettingsHistory.sanitazed.IsEnabled(field);
|
|
|
|
var textBase = $"The FrameSetting required to render this effect in the {(hdCamera.camera.cameraType == CameraType.SceneView ? "Scene" : "Game")} view ";
|
|
|
|
if (disabledByDebug)
|
|
CoreEditorUtils.DrawFixMeBox(textBase + "is disabled in the Rendering Debugger.", type, "Open", () => HighlightInDebugger(hdCamera, field, displayName));
|
|
else if (disabledByCamera)
|
|
CoreEditorUtils.DrawFixMeBox(textBase + "is disabled on a Camera.", type, "Open", () => EditorUtility.OpenPropertyEditor(hdCamera.camera));
|
|
else if (disabledInGlobal)
|
|
GlobalSettingsHelpBox(textBase + "is disabled in the HDRP Global Settings.", type, field, displayName);
|
|
else if (disabledByDependency)
|
|
GlobalSettingsHelpBox(textBase + "depends on a disabled FrameSetting.", type, field, displayName);
|
|
}
|
|
|
|
internal static HDCamera[] GetDisplayedCameras()
|
|
{
|
|
HashSet<HDCamera> visibleCamera = new();
|
|
|
|
foreach (SceneView sceneView in SceneView.sceneViews)
|
|
{
|
|
if (!sceneView.hasFocus) continue;
|
|
visibleCamera.Add(HDCamera.GetOrCreate(sceneView.camera));
|
|
}
|
|
|
|
var assembly = typeof(EditorWindow).Assembly;
|
|
var type = assembly.GetType("UnityEditor.GameView");
|
|
var targetDisplayProp = type.GetProperty("targetDisplay");
|
|
|
|
foreach (EditorWindow gameView in Resources.FindObjectsOfTypeAll(type))
|
|
{
|
|
if (!gameView.hasFocus) continue;
|
|
|
|
var targetDisplay = (int)targetDisplayProp.GetValue(gameView);
|
|
foreach (var camera in HDCamera.GetHDCameras())
|
|
{
|
|
if (camera == null || camera.camera == null)
|
|
continue;
|
|
if (camera.camera.cameraType == CameraType.Game && camera.camera.targetDisplay == targetDisplay)
|
|
visibleCamera.Add(camera);
|
|
}
|
|
}
|
|
|
|
return visibleCamera.ToArray();
|
|
}
|
|
|
|
internal static bool EnsureFrameSetting(FrameSettingsField field, string displayName)
|
|
{
|
|
foreach (var camera in GetDisplayedCameras())
|
|
{
|
|
if (!camera.frameSettings.IsEnabled(field))
|
|
{
|
|
FrameSettingsHelpBox(camera, field, displayName);
|
|
EditorGUILayout.Space();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
internal static bool EnsureVolumeAndFrameSetting<T>(Func<T, string> volumeValidator, FrameSettingsField field, string displayName) where T : UnityEngine.Rendering.VolumeComponent
|
|
{
|
|
// Wait for volume system to be initialized
|
|
if (VolumeManager.instance.baseComponentTypeArray == null)
|
|
return true;
|
|
|
|
var cameras = GetDisplayedCameras();
|
|
|
|
foreach (var camera in cameras)
|
|
{
|
|
var errorString = volumeValidator(camera.volumeStack.GetComponent<T>());
|
|
if (!string.IsNullOrEmpty(errorString))
|
|
{
|
|
EditorGUILayout.HelpBox(errorString, MessageType.Warning);
|
|
EditorGUILayout.Space();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
foreach (var camera in cameras)
|
|
{
|
|
if (!camera.frameSettings.IsEnabled(field))
|
|
{
|
|
FrameSettingsHelpBox(camera, field, displayName);
|
|
EditorGUILayout.Space();
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
// Due to a UI bug/limitation, we have to do it this way to support bold labels
|
|
internal class BoldLabelScope : GUI.Scope
|
|
{
|
|
FontStyle origFontStyle;
|
|
|
|
public BoldLabelScope()
|
|
{
|
|
origFontStyle = EditorStyles.label.fontStyle;
|
|
EditorStyles.label.fontStyle = FontStyle.Bold;
|
|
}
|
|
|
|
protected override void CloseScope()
|
|
{
|
|
EditorStyles.label.fontStyle = origFontStyle;
|
|
}
|
|
}
|
|
}
|