Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
160 changes: 125 additions & 35 deletions com.unity.render-pipelines.core/Editor/ContextualMenuDispatcher.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,71 +2,115 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

using UnityEngine.Rendering;

namespace UnityEditor.Rendering
{
internal static class RemoveComponentUtils
{
public static IEnumerable<Component> ComponentDependencies(Component component)
=> component.gameObject
.GetComponents<Component>()
.Where(c => c != component
&& c.GetType()
.GetCustomAttributes(typeof(RequireComponent), true)
.Count(att => att is RequireComponent rc
&& (rc.m_Type0 == component.GetType()
|| rc.m_Type1 == component.GetType()
|| rc.m_Type2 == component.GetType())) > 0);

public static bool CanRemoveComponent(Component component, IEnumerable<Component> dependencies)
{
if (dependencies.Count() == 0)
return true;

Component firstDependency = dependencies.First();
string error = $"Can't remove {component.GetType().Name} because {firstDependency.GetType().Name} depends on it.";
EditorUtility.DisplayDialog("Can't remove component", error, "Ok");
return false;
}
}

/// <summary>
/// Helper methods for overriding contextual menus
/// </summary>
static class ContextualMenuDispatcher
{
[MenuItem("CONTEXT/ReflectionProbe/Remove Component")]
static void RemoveReflectionProbeComponent(MenuCommand command)
{
RemoveComponent<ReflectionProbe>(command);
}

[MenuItem("CONTEXT/Light/Remove Component")]
static void RemoveLightComponent(MenuCommand command)
{
RemoveComponent<Light>(command);
}

[MenuItem("CONTEXT/Camera/Remove Component")]
static void RemoveCameraComponent(MenuCommand command)
{
Camera camera = command.context as Camera;
string error;
RemoveComponent<Camera>(command);
}

if (!DispatchRemoveComponent(camera))
[InitializeOnLoadMethod]
static void RegisterAdditionalDataMenus()
{
foreach (var additionalData in TypeCache.GetTypesDerivedFrom<IAdditionalData>())
{
//preserve built-in behavior
if (CanRemoveComponent(camera, out error))
Undo.DestroyObjectImmediate(command.context);
else
EditorUtility.DisplayDialog("Can't remove component", error, "Ok");
if (additionalData.GetCustomAttributes(typeof(RequireComponent), true).FirstOrDefault() is RequireComponent rc)
{
string types = rc.m_Type0.Name;
if (rc.m_Type1 != null)
types += $", {rc.m_Type1.Name}";
if (rc.m_Type2 != null)
types += $", {rc.m_Type2.Name}";

MenuManager.AddMenuItem($"CONTEXT/{additionalData.Name}/Remove Component",
string.Empty,
false,
0,
() => EditorUtility.DisplayDialog($"Remove {additionalData.Name} is blocked", $"You can not delete this component, you will have to remove the {types}.", "OK"),
() => true);
}
}
}

static bool DispatchRemoveComponent<T>(T component)
static void RemoveComponent<T>(MenuCommand command)
where T : Component
{
Type type = RenderPipelineEditorUtility.FetchFirstCompatibleTypeUsingScriptableRenderPipelineExtension<IRemoveAdditionalDataContextualMenu<T>>();
if (type != null)
T comp = command.context as T;

if (!DispatchRemoveComponent<T>(comp))
{
IRemoveAdditionalDataContextualMenu<T> instance = (IRemoveAdditionalDataContextualMenu<T>)Activator.CreateInstance(type);
instance.RemoveComponent(component, ComponentDependencies(component));
return true;
//preserve built-in behavior
if (RemoveComponentUtils.CanRemoveComponent(comp, RemoveComponentUtils.ComponentDependencies(comp)))
Undo.DestroyObjectImmediate(command.context);
}
return false;
}

static IEnumerable<Component> ComponentDependencies(Component component)
=> component.gameObject
.GetComponents<Component>()
.Where(c => c != component
&& c.GetType()
.GetCustomAttributes(typeof(RequireComponent), true)
.Count(att => att is RequireComponent rc
&& (rc.m_Type0 == component.GetType()
|| rc.m_Type1 == component.GetType()
|| rc.m_Type2 == component.GetType())) > 0);

static bool CanRemoveComponent(Component component, out string error)
static bool DispatchRemoveComponent<T>(T component)
where T : Component
{
var dependencies = ComponentDependencies(component);
if (dependencies.Count() == 0)
try
{
error = null;
var instance = new RemoveAdditionalDataContextualMenu<T>();
instance.RemoveComponent(component, RemoveComponentUtils.ComponentDependencies(component));
return true;
}

Component firstDependency = dependencies.First();
error = $"Can't remove {component.GetType().Name} because {firstDependency.GetType().Name} depends on it.";
return false;
catch
{
return false;
}
}
}

/// <summary>
/// Interface that should be used with [ScriptableRenderPipelineExtension(type))] attribute to dispatch ContextualMenu calls on the different SRPs
/// </summary>
/// <typeparam name="T">This must be a component that require AdditionalData in your SRP</typeparam>
[Obsolete("The menu items are handled automatically for components with the AdditionalComponentData attribute", false)]
public interface IRemoveAdditionalDataContextualMenu<T>
where T : Component
{
Expand All @@ -77,4 +121,50 @@ public interface IRemoveAdditionalDataContextualMenu<T>
/// <param name="dependencies">Dependencies.</param>
void RemoveComponent(T component, IEnumerable<Component> dependencies);
}

internal class RemoveAdditionalDataContextualMenu<T>
where T : Component
{
/// <summary>
/// Remove the given component
/// </summary>
/// <param name="component">The component to remove</param>
/// <param name="dependencies">Dependencies.</param>
public void RemoveComponent(T component, IEnumerable<Component> dependencies)
{
var additionalDatas = dependencies
.Where(c => c != component && typeof(IAdditionalData).IsAssignableFrom(c.GetType()))
.ToList();

if (!RemoveComponentUtils.CanRemoveComponent(component, dependencies.Where(c => !additionalDatas.Contains(c))))
return;

var isAssetEditing = EditorUtility.IsPersistent(component);
try
{
if (isAssetEditing)
{
AssetDatabase.StartAssetEditing();
}
Undo.SetCurrentGroupName($"Remove {typeof(T)} additional data components");

// The components with RequireComponent(typeof(T)) also contain the AdditionalData attribute, proceed with the remove
foreach (var additionalDataComponent in additionalDatas)
{
if (additionalDataComponent != null)
{
Undo.DestroyObjectImmediate(additionalDataComponent);
}
}
Undo.DestroyObjectImmediate(component);
}
finally
{
if (isAssetEditing)
{
AssetDatabase.StopAssetEditing();
}
}
}
}
}
2 changes: 1 addition & 1 deletion com.unity.render-pipelines.core/Editor/CoreEditorUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -975,7 +975,7 @@ public static void AddAdditionalData<T, AdditionalT>(GameObject go, Action<Addit
/// <param name="name">The wanted name (can be updated with a number if a sibling with same name exist</param>
/// <param name="types">Required component on this object in addition to Transform</param>
/// <returns>The created object</returns>
static public GameObject CreateGameObject(GameObject parent, string name, params Type[] types)
public static GameObject CreateGameObject(GameObject parent, string name, params Type[] types)
=> ObjectFactory.CreateGameObject(GameObjectUtility.GetUniqueNameForSibling(parent != null ? parent.transform : null, name), types);

/// <summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,8 @@ public override int GetHashCode()
{
int hash = 13;
hash = hash * 23 + m_QueryPath.GetHashCode();
hash = hash * 23 + m_Value.GetHashCode();
if (m_Value != null)
hash = hash * 23 + m_Value.GetHashCode();
return hash;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,9 @@ public void ApplyStates(bool forceApplyAll = false)

void ApplyState(string queryPath, DebugState state)
{
if (!(DebugManager.instance.GetItem(queryPath) is DebugUI.IValueField widget))
if (state == null ||
state.GetValue() == null ||
!(DebugManager.instance.GetItem(queryPath) is DebugUI.IValueField widget))
return;

widget.SetValue(state.GetValue());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
using System.Collections.Generic;
using System.Linq;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering.RendererUtils;

namespace UnityEngine.Rendering
{
Expand Down
2 changes: 2 additions & 0 deletions com.unity.render-pipelines.high-definition/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -392,6 +392,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
- Fixed wrong ordering in FrameSettings (Normalize Reflection Probes)
- Fixed ThreadMapDetail to saturate AO & smoothness strength inputs to prevent out-of-bounds values set by users (1357740)
- Allow negative wind speed parameter.
- Fixed remove of the Additional Light Data when removing the Light Component.
- Fixed remove of the Additional Camera Data when removing the Camera Component.

### Changed
- Changed Window/Render Pipeline/HD Render Pipeline Wizard to Window/Rendering/HDRP Wizard
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,9 @@ void ApplyAdditionalComponentsVisibility(bool hide)

protected override void OnSceneGUI()
{
if (targetAdditionalData == null)
return;

// Each handles manipulate only one light
// Thus do not rely on serialized properties
HDLightType lightType = targetAdditionalData.type;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,18 +6,6 @@ namespace UnityEditor.Rendering.HighDefinition
{
partial class HDLightUI
{
[MenuItem("CONTEXT/Light/Remove Component", false, 0)]
static void RemoveLight(MenuCommand menuCommand)
{
GameObject go = ((Light)menuCommand.context).gameObject;

Assert.IsNotNull(go);

Undo.IncrementCurrentGroup();
Undo.DestroyObjectImmediate(go.GetComponent<Light>());
Undo.DestroyObjectImmediate(go.GetComponent<HDAdditionalLightData>());
}

[MenuItem("CONTEXT/Light/Reset", false, 0)]
static void ResetLight(MenuCommand menuCommand)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,15 @@ protected virtual void DrawAdditionalCaptureSettings(TSerialized serialiezed, Ed

protected void OnSceneGUI()
{
EditorGUI.BeginChangeCheck();
if (target == null)
return;

var soo = m_SerializedHDProbePerTarget[target];
if (soo == null)
return;

EditorGUI.BeginChangeCheck();

soo.Update();
HDProbeUI.DrawHandles(soo, this);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,6 @@ namespace UnityEditor.Rendering.HighDefinition
sealed partial class HDReflectionProbeEditor : HDProbeEditor<HDProbeSettingsProvider, SerializedHDReflectionProbe>
{
#region Context Menu
[MenuItem("CONTEXT/ReflectionProbe/Remove Component", false, 0)]
static void RemoveReflectionProbe(MenuCommand menuCommand)
{
GameObject go = ((ReflectionProbe)menuCommand.context).gameObject;

Assert.IsNotNull(go);

Undo.SetCurrentGroupName("Remove HD Reflection Probe");
Undo.DestroyObjectImmediate(go.GetComponent<ReflectionProbe>());
Undo.DestroyObjectImmediate(go.GetComponent<HDAdditionalReflectionData>());
}

[MenuItem("CONTEXT/ReflectionProbe/Reset", false, 0)]
static void ResetReflectionProbe(MenuCommand menuCommand)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ void OnSceneGUI()
if (HDRenderPipeline.currentPipeline == null)
return;

var c = (Camera)target;
if (!(target is Camera c) || c == null)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm curious: target is Camera c if target is null, c is (Camera)null right? Then why do we need the null check?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

because is null on the c++ world, not in c# the is operator is not overriden

return;

if (!UnityEditor.Rendering.CameraEditorUtils.IsViewPortRectValidToRender(c.rect))
if (!CameraEditorUtils.IsViewPortRectValidToRender(c.rect))
return;

SceneViewOverlay_Window(EditorGUIUtility.TrTextContent("Camera Preview"), OnOverlayGUI, -100, target);
Expand Down
Loading