mixedreality/com.microsoft.mixedreality..../SDK/Features/UX/Scripts/BoundsControl/Visuals/Links.cs

255 lines
9.9 KiB
C#

// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
using Microsoft.MixedReality.Toolkit.UI.BoundsControlTypes;
using System.Collections.Generic;
using UnityEngine;
namespace Microsoft.MixedReality.Toolkit.UI.BoundsControl
{
/// <summary>
/// Links that are rendered in between the corners of <see cref="BoundsControl"/>
/// </summary>
public class Links
{
/// <summary>
/// defines a bounds control link - the line between 2 corners of a box
/// it keeps track of the transform and the axis the link is representing
/// </summary>
private class Link
{
public Transform transform;
public CardinalAxisType axisType;
public Link(Transform linkTransform, CardinalAxisType linkAxis)
{
transform = linkTransform;
axisType = linkAxis;
}
}
private List<Link> links = new List<Link>();
private LinksConfiguration config;
private Vector3 cachedExtents;
private FlattenModeType cachedFlattenAxis;
internal Links(LinksConfiguration configuration)
{
Debug.Assert(configuration != null, "Can't create BoundsControlLinks without valid configuration");
config = configuration;
config.wireFrameChanged.AddListener(UpdateWireframe);
}
~Links()
{
config.wireFrameChanged.RemoveListener(UpdateWireframe);
}
private void UpdateWireframe(LinksConfiguration.WireframeChangedEventType changedType)
{
switch (changedType)
{
case LinksConfiguration.WireframeChangedEventType.Visibility:
Reset(config.ShowWireFrame, cachedFlattenAxis);
break;
case LinksConfiguration.WireframeChangedEventType.Radius:
UpdateLinkScales(cachedExtents);
break;
case LinksConfiguration.WireframeChangedEventType.Shape:
UpdateLinkPrimitive();
break;
case LinksConfiguration.WireframeChangedEventType.Material:
UpdateMaterial();
break;
}
}
internal void Clear()
{
if (links != null)
{
foreach (Link link in links)
{
Object.Destroy(link.transform.gameObject);
}
links.Clear();
}
}
internal void UpdateMaterial()
{
if (links != null && config.WireframeMaterial != null)
{
for (int i = 0; i < links.Count; ++i)
{
Renderer linkRenderer = links[i].transform.gameObject.GetComponent<Renderer>();
if (linkRenderer != null)
{
linkRenderer.material = config.WireframeMaterial;
}
}
}
}
internal void UpdateVisibilityInInspector(HideFlags flags)
{
if (links != null)
{
foreach (var link in links)
{
link.transform.hideFlags = flags;
}
}
}
internal void Reset(bool isVisible, FlattenModeType flattenAxis)
{
cachedFlattenAxis = flattenAxis;
if (links != null)
{
for (int i = 0; i < links.Count; ++i)
{
links[i].transform.gameObject.SetActive(isVisible && config.ShowWireFrame);
}
List<int> flattenedHandles = VisualUtils.GetFlattenedIndices(cachedFlattenAxis, VisualUtils.EdgeAxisType);
if (flattenedHandles != null && VisualUtils.EdgeAxisType.Length == links.Count)
{
for (int i = 0; i < flattenedHandles.Count; ++i)
{
links[flattenedHandles[i]].transform.gameObject.SetActive(false);
}
}
}
}
private Vector3 GetLinkDimensions(Vector3 currentBoundsExtents)
{
float wireframeEdgeRadius = config.WireframeEdgeRadius;
float linkLengthAdjustor = config.WireframeShape == WireframeType.Cubic ? 2.0f : 1.0f - (6.0f * wireframeEdgeRadius);
return (currentBoundsExtents * linkLengthAdjustor) + new Vector3(wireframeEdgeRadius, wireframeEdgeRadius, wireframeEdgeRadius);
}
internal void UpdateLinkPositions(ref Vector3[] boundsCorners)
{
if (boundsCorners != null)
{
for (int i = 0; i < links.Count; ++i)
{
links[i].transform.position = VisualUtils.GetLinkPosition(i, ref boundsCorners);
}
}
}
internal void UpdateLinkScales(Vector3 currentBoundsExtents)
{
if (links != null)
{
for (int i = 0; i < links.Count; ++i)
{
Transform parent = links[i].transform.parent;
Vector3 rootScale = parent.lossyScale;
Vector3 invRootScale = new Vector3(1.0f / rootScale[0], 1.0f / rootScale[1], 1.0f / rootScale[2]);
// Compute the local scale that produces the desired world space dimensions
Vector3 linkDimensions = Vector3.Scale(GetLinkDimensions(currentBoundsExtents), invRootScale);
float wireframeEdgeRadius = config.WireframeEdgeRadius;
if (links[i].axisType == CardinalAxisType.X)
{
links[i].transform.localScale = new Vector3(wireframeEdgeRadius, linkDimensions.x, wireframeEdgeRadius);
}
else if (links[i].axisType == CardinalAxisType.Y)
{
links[i].transform.localScale = new Vector3(wireframeEdgeRadius, linkDimensions.y, wireframeEdgeRadius);
}
else//Z
{
links[i].transform.localScale = new Vector3(wireframeEdgeRadius, linkDimensions.z, wireframeEdgeRadius);
}
}
cachedExtents = currentBoundsExtents;
}
}
private void UpdateLinkPrimitive()
{
GameObject sharedMeshPrimitive;
if (config.WireframeShape == WireframeType.Cubic)
{
sharedMeshPrimitive = GameObject.CreatePrimitive(PrimitiveType.Cube);
}
else
{
sharedMeshPrimitive = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
}
var sharedMeshFilter = sharedMeshPrimitive.GetComponent<MeshFilter>();
if (sharedMeshFilter)
{
foreach (var link in links)
{
GameObject linkObj = link.transform.gameObject;
// replace shared mesh - note that we don't have a collider to replace in case of wireframe
linkObj.GetComponent<MeshFilter>().sharedMesh = sharedMeshFilter.sharedMesh;
}
}
Object.Destroy(sharedMeshPrimitive);
UpdateLinkScales(cachedExtents);
}
internal void CreateLinks(ref Vector3[] boundsCorners, Transform parent, Vector3 currentBoundsExtents)
{
// create links
if (links != null)
{
GameObject link;
Vector3 linkDimensions = GetLinkDimensions(currentBoundsExtents);
for (int i = 0; i < VisualUtils.EdgeAxisType.Length; ++i)
{
if (config.WireframeShape == WireframeType.Cubic)
{
link = GameObject.CreatePrimitive(PrimitiveType.Cube);
Object.Destroy(link.GetComponent<BoxCollider>());
}
else
{
link = GameObject.CreatePrimitive(PrimitiveType.Cylinder);
Object.Destroy(link.GetComponent<CapsuleCollider>());
}
link.name = "link_" + i.ToString();
CardinalAxisType axisType = VisualUtils.EdgeAxisType[i];
float wireframeEdgeRadius = config.WireframeEdgeRadius;
if (axisType == CardinalAxisType.Y)
{
link.transform.localScale = new Vector3(wireframeEdgeRadius, linkDimensions.y, wireframeEdgeRadius);
link.transform.Rotate(new Vector3(0.0f, 90.0f, 0.0f));
}
else if (axisType == CardinalAxisType.Z)
{
link.transform.localScale = new Vector3(wireframeEdgeRadius, linkDimensions.z, wireframeEdgeRadius);
link.transform.Rotate(new Vector3(90.0f, 0.0f, 0.0f));
}
else//X
{
link.transform.localScale = new Vector3(wireframeEdgeRadius, linkDimensions.x, wireframeEdgeRadius);
link.transform.Rotate(new Vector3(0.0f, 0.0f, 90.0f));
}
link.transform.position = VisualUtils.GetLinkPosition(i, ref boundsCorners);
link.transform.parent = parent;
Renderer linkRenderer = link.GetComponent<Renderer>();
if (config.WireframeMaterial != null)
{
linkRenderer.material = config.WireframeMaterial;
}
link.SetActive(config.ShowWireFrame);
links.Add(new Link(link.transform, axisType));
}
}
}
}
}