// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.UI.BoundsControlTypes;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.UI.BoundsControl
{
///
/// BoxDisplay can be used to attach a solid box visualization to a
/// The box will only be rendered if a material is assigned
///
public class BoxDisplay
{
// GameObject used to display the box. Parented to the rig root
private GameObject boxDisplay;
private BoxDisplayConfiguration config;
private Vector3 cachedExtents = Vector3.zero;
private FlattenModeType cachedFlattenMode;
private bool isVisible = true;
internal BoxDisplay(BoxDisplayConfiguration configuration)
{
Debug.Assert(configuration != null, "Can't create BoundsControlBoxDisplay without valid configuration");
config = configuration;
config.flattenAxisScaleChanged.AddListener(UpdateDisplayWithCache);
config.materialChanged.AddListener(UpdateBoxDisplayMaterial);
}
~BoxDisplay()
{
config.flattenAxisScaleChanged.RemoveListener(UpdateDisplayWithCache);
config.materialChanged.RemoveListener(UpdateBoxDisplayMaterial);
}
internal void AddBoxDisplay(Transform parent, Vector3 currentBoundsExtents, FlattenModeType flattenAxis)
{
// This has to be cube even in flattened mode as flattened box display can still have a thickness of flattenAxisDisplayScale
boxDisplay = GameObject.CreatePrimitive(PrimitiveType.Cube);
Object.Destroy(boxDisplay.GetComponent());
boxDisplay.name = "box display";
cachedFlattenMode = flattenAxis;
cachedExtents = currentBoundsExtents;
Reset(isVisible);
boxDisplay.transform.localScale = GetBoxDisplayScale(currentBoundsExtents, flattenAxis);
boxDisplay.transform.parent = parent;
}
private Vector3 GetBoxDisplayScale(Vector3 currentBoundsExtents, FlattenModeType flattenAxis)
{
// When a box is flattened one axis is normally scaled to zero, this doesn't always work well with visuals so we take
// that flattened axis and re-scale it to the flattenAxisDisplayScale.
Vector3 displayScale = VisualUtils.FlattenBounds(currentBoundsExtents, flattenAxis, config.FlattenAxisDisplayScale);
return 2.0f * displayScale;
}
internal void UpdateVisibilityInInspector(HideFlags desiredFlags)
{
if (boxDisplay != null)
{
boxDisplay.hideFlags = desiredFlags;
}
}
internal void SetHighlighted()
{
// Update the box material to the grabbed material
if (boxDisplay != null)
{
VisualUtils.ApplyMaterialToAllRenderers(boxDisplay, config.BoxGrabbedMaterial);
}
}
internal void Reset(bool visible)
{
isVisible = visible;
// Set box display visibility
if (boxDisplay != null)
{
bool activate = config.BoxMaterial != null && isVisible; // only set active if material is set
boxDisplay.SetActive(activate);
if (activate)
{
VisualUtils.ApplyMaterialToAllRenderers(boxDisplay, config.BoxMaterial);
}
}
}
internal void UpdateDisplay(Vector3 boundsExtents, FlattenModeType flattenAxis)
{
if (boxDisplay != null)
{
Transform parent = boxDisplay.transform.parent;
boxDisplay.transform.parent = null;
boxDisplay.transform.localScale = GetBoxDisplayScale(boundsExtents, flattenAxis);
boxDisplay.transform.parent = parent;
}
cachedExtents = boundsExtents;
cachedFlattenMode = flattenAxis;
}
internal void UpdateDisplayWithCache()
{
UpdateDisplay(cachedExtents, cachedFlattenMode);
}
internal void UpdateFlattenAxis(FlattenModeType flattenAxis)
{
cachedFlattenMode = flattenAxis;
UpdateDisplay(cachedExtents, flattenAxis);
}
internal void UpdateBoxDisplayMaterial()
{
Reset(isVisible);
}
}
}