// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using Microsoft.MixedReality.Toolkit.Input; using System; using System.Collections.Generic; using UnityEngine; namespace Microsoft.MixedReality.Toolkit.UI { /// /// Adds or removes materials to target renderer for highlighting Focused GameObjects. /// /// Useful with focusable GameObjects [System.Obsolete("This component is no longer supported", true)] [AddComponentMenu("Scripts/MRTK/Obsolete/InteractableHighlight")] public class InteractableHighlight : BaseFocusHandler { [Flags] public enum HighlightedMaterialStyle { None = 0 << 0, /// /// A highlight to indicate focus. /// Highlight = 1 << 0, /// /// An overlay to indicate intent. /// Overlay = 1 << 1, /// /// Both highlight and overlay. /// Both = Highlight | Overlay, } public bool Highlight { get { return highlight; } set { if (value != highlight) { highlight = value; Refresh(); } } } [SerializeField] private bool highlight = false; public HighlightedMaterialStyle Style { set { if (targetStyle != value) { targetStyle = value; Refresh(); } } } /// /// The target renderers that will get the styles applied. /// public Renderer[] TargetRenderers { set { if (targetRenderers != value) { targetRenderers = value; Refresh(); } } } [SerializeField] [Tooltip("The target renderers that will get the styles applied.")] private Renderer[] targetRenderers = null; [SerializeField] [Tooltip("The material property that will be used for the highlight color.")] private string highlightColorProperty = "_Color"; [SerializeField] [Tooltip("The material property that will be used for the outline color.")] private string outlineColorProperty = "_Color"; [SerializeField] private Color highlightColor = Color.green; [SerializeField] private Color outlineColor = Color.white; [SerializeField] private Material highlightMaterial = null; [SerializeField] private Material overlayMaterial = null; [SerializeField] private HighlightedMaterialStyle targetStyle = HighlightedMaterialStyle.Highlight; private HighlightedMaterialStyle currentStyle = HighlightedMaterialStyle.None; private Dictionary> materialsBeforeFocus; #region MonoBehaviour Implementation private void Awake() { Debug.LogError(this.GetType().Name + " is deprecated"); } public virtual void OnEnable() { if (targetRenderers == null || targetRenderers.Length == 0) { targetRenderers = GetComponentsInChildren(); } Refresh(); } public virtual void OnDisable() { Highlight = false; Refresh(); } #endregion MonoBehaviour Implementation private void Refresh() { if (isActiveAndEnabled && highlight) { AddHighlightMaterials(); } else { RemoveHighlightMaterials(); } } private void AddHighlightMaterials() { // If we've added our focus materials already, split if ((currentStyle & targetStyle) != 0) { return; } if (materialsBeforeFocus == null) { materialsBeforeFocus = new Dictionary>(); } for (int i = 0; i < targetRenderers.Length; i++) { List preFocusMaterials; if (!materialsBeforeFocus.TryGetValue(targetRenderers[i], out preFocusMaterials)) { preFocusMaterials = new List(); materialsBeforeFocus.Add(targetRenderers[i], preFocusMaterials); } else { preFocusMaterials.Clear(); } preFocusMaterials.AddRange(targetRenderers[i].sharedMaterials); // Remove any references to outline and highlight materials preFocusMaterials.Remove(highlightMaterial); preFocusMaterials.Remove(overlayMaterial); } // If we're using a highlight if ((targetStyle & HighlightedMaterialStyle.Highlight) != 0) { // And we haven't added it yet if ((currentStyle & HighlightedMaterialStyle.Highlight) == 0) { AddMaterialToRenderers(targetRenderers, highlightMaterial, highlightColorProperty, highlightColor); } } // If we're using an outline if ((targetStyle & HighlightedMaterialStyle.Overlay) != 0) { // And we haven't added it yet if ((currentStyle & HighlightedMaterialStyle.Overlay) == 0) { AddMaterialToRenderers(targetRenderers, overlayMaterial, outlineColorProperty, outlineColor); } } currentStyle = targetStyle; } private void RemoveHighlightMaterials() { if (materialsBeforeFocus == null) { return; } foreach (KeyValuePair> preFocusMats in materialsBeforeFocus) { preFocusMats.Key.sharedMaterials = preFocusMats.Value.ToArray(); } materialsBeforeFocus.Clear(); currentStyle = HighlightedMaterialStyle.None; } private static void AddMaterialToRenderers(Renderer[] renderers, Material material, string propName, Color color) { material.SetColor(propName, color); for (int i = 0; i < renderers.Length; i++) { if (renderers[i] == null) { continue; } var currentMaterials = new List(renderers[i].sharedMaterials); if (!currentMaterials.Contains(material)) { currentMaterials.Add(material); renderers[i].sharedMaterials = currentMaterials.ToArray(); } } } private static void RemoveMatFromRenderers(Renderer[] renderers, List materials) { for (int i = 0; i < materials.Count; i++) { RemoveMatFromRenderers(renderers, materials[i]); } } private static void RemoveMatFromRenderers(Renderer[] renderers, Material material) { if (material == null) { return; } for (int i = 0; i < renderers.Length; i++) { if (renderers[i] == null) { continue; } var currentMaterials = new List(renderers[i].sharedMaterials); // use the name because it may be instanced for (int j = currentMaterials.Count - 1; j >= 0; j--) { if (currentMaterials[j] != null && currentMaterials[j].name == material.name) { currentMaterials.RemoveAt(j); } } currentMaterials.Remove(material); renderers[i].sharedMaterials = currentMaterials.ToArray(); } } #region IMixedRealityFocusHandler Implementation /// public override void OnFocusEnter(FocusEventData eventData) { base.OnFocusEnter(eventData); if (HasFocus) { Highlight = true; } } /// public override void OnFocusExit(FocusEventData eventData) { base.OnFocusExit(eventData); Highlight = false; } #endregion IMixedRealityFocusHandler Implementation } }