// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using System.Collections.Generic;
using UnityEngine;
namespace Microsoft.MixedReality.GraphicsTools
{
///
/// Component which can be used to render an outline around a hierarchy of mesh renderers using
/// the component.
///
[DisallowMultipleComponent, AddComponentMenu("Scripts/GraphicsTools/MeshOutlineHierarchy")]
public class MeshOutlineHierarchy : BaseMeshOutline
{
///
/// Defines how to exclude objects from the outline hierarchy.
///
public enum ExclusionMode
{
None,
Tag,
NameStartsWith,
NameContains,
}
///
/// Whether and how to exclude objects from the outline hierarchy.
///
public ExclusionMode Exclusion
{
get { return exclusionMode; }
set
{
if (exclusionMode != value)
{
exclusionMode = value;
Refresh();
}
}
}
[Tooltip("Whether and how to exclude objects from the outline hierarchy.")]
[SerializeField, HideInInspector]
private ExclusionMode exclusionMode = ExclusionMode.None;
///
/// When exclusionMode is set to "NameStartsWith" or "NameContains" what string to match against.
///
public string ExclusionString
{
get { return exclusionString; }
set
{
if (exclusionString != value)
{
exclusionString = value;
Refresh();
}
}
}
[Tooltip("When exclusionMode is set to \"NameStartsWith\" or \"NameContains\" what string to match against.")]
[SerializeField, HideInInspector]
private string exclusionString = string.Empty;
///
/// When exclusionMode is set to "NameStartsWith" or "NameContains" what string to match against.
///
public string ExclusionTag
{
get { return exclusionTag; }
set
{
if (exclusionTag != value)
{
exclusionTag = value;
Refresh();
}
}
}
[Tooltip("When exclusionMode is set to \"Tag\" what tag to compare against.")]
[SerializeField, HideInInspector]
private string exclusionTag = "Untagged";
private List meshOutlines = new List();
#region MonoBehaviour Implementation
///
/// Creates a component on each child MeshRenderer/SkinnedMeshRenderer.
///
private void Awake()
{
Create();
}
///
/// Enables all child mesh outlines.
///
private void OnEnable()
{
foreach (var meshOutline in meshOutlines)
{
if (meshOutline != null)
{
meshOutline.enabled = true;
}
}
}
///
/// Disables all child mesh outlines.
///
private void OnDisable()
{
foreach (var meshOutline in meshOutlines)
{
if (meshOutline != null)
{
meshOutline.enabled = false;
}
}
}
///
/// Removes any components this component has created.
///
private void OnDestroy()
{
// Don't use DestroyImmediate on the same object in OnDisable or OnDestroy.
Clear(false);
}
#endregion MonoBehaviour Implementation
#region BaseMeshOutline Implementation
///
/// Forwards settings to all children s.
///
public override void ApplyOutlineMaterial()
{
ApplyToChildren();
}
///
/// Forwards settings to all children s.
///
public override void ApplyOutlineWidth()
{
ApplyToChildren();
}
///
/// Forwards settings to all children s.
///
public override void ApplyStencilReference()
{
ApplyToChildren();
}
#endregion BaseMeshOutline Implementation
///
/// Removes and re-adds all this component has created.
///
public void Refresh()
{
Clear(true);
Create();
}
///
/// Creates a component on each child MeshRenderer/SkinnedMeshRenderer.
///
private void Create()
{
var meshRenderers = GetComponentsInChildren();
for (int i = 0; i < meshRenderers.Length; ++i)
{
AddMeshOutline(meshRenderers[i]);
}
var skinnedMeshRenderers = GetComponentsInChildren();
for (int i = 0; i < skinnedMeshRenderers.Length; ++i)
{
AddMeshOutline(skinnedMeshRenderers[i]);
}
}
///
/// Removes any components this component has created.
///
private void Clear(bool destroyImmediately)
{
for (int i = 0; i < meshOutlines.Count; ++i)
{
if (destroyImmediately)
{
DestroyImmediate(meshOutlines[i]);
}
else
{
Destroy(meshOutlines[i]);
}
}
meshOutlines.Clear();
}
private void AddMeshOutline(Renderer target)
{
switch (exclusionMode)
{
case ExclusionMode.None:
default:
break;
case ExclusionMode.NameStartsWith:
if (target.name.StartsWith(exclusionString))
{
return;
}
break;
case ExclusionMode.NameContains:
if (target.name.Contains(exclusionString))
{
return;
}
break;
case ExclusionMode.Tag:
if (target.CompareTag(exclusionTag))
{
return;
}
break;
}
var meshOutline = target.gameObject.EnsureComponent();
meshOutline.CopyFrom(this);
meshOutlines.Add(meshOutline);
}
private void ApplyToChildren()
{
foreach (var meshOutline in meshOutlines)
{
if (meshOutline != null)
{
meshOutline.CopyFrom(this);
}
}
}
}
}