// Copyright (c) Microsoft Corporation. // Licensed under the MIT License. using System; using System.Collections.Generic; using UnityEngine; namespace Microsoft.MixedReality.Toolkit.UI { /// /// Theme Engine to control a GameObject's rotation based on state changes /// public class InteractableRotationTheme : InteractableThemeBase { /// /// If true, the theme rotation value will be added to the initial Gameobject's rotation. Otherwise, it will set directly as absolute euler angles. /// public bool IsRelativeRotation => GetThemeProperty(RelativeRotationPropertyIndex).Value.Bool; /// /// If true, the theme manipulate the target's local rotation. Otherwise, the theme will control the world space rotation. /// public bool IsLocalRotation => GetThemeProperty(LocalRotationPropertyIndex).Value.Bool; protected Vector3 originalLocalRotation; protected Vector3 originalRotation; protected Transform hostTransform; private const int RelativeRotationPropertyIndex = 0; private const int LocalRotationPropertyIndex = 1; public InteractableRotationTheme() { Types = new Type[] { typeof(Transform) }; Name = "Rotation Theme"; } /// public override ThemeDefinition GetDefaultThemeDefinition() { return new ThemeDefinition() { ThemeType = GetType(), StateProperties = new List() { new ThemeStateProperty() { Name = "Rotation", Type = ThemePropertyTypes.Vector3, Values = new List(), Default = new ThemePropertyValue() { Vector3 = Vector3.zero } }, }, CustomProperties = new List() { new ThemeProperty() { Name = "Relative Rotation", Tooltip = "Should the theme rotation value be added to the initial Gameobject's rotation, or set directly as absolute euler angles", Type = ThemePropertyTypes.Bool, Value = new ThemePropertyValue() { Bool = false } }, new ThemeProperty() { Name = "Local Rotation", Tooltip = "Should the theme manipulate the target's local rotation or world space rotation", Type = ThemePropertyTypes.Bool, Value = new ThemePropertyValue() { Bool = true } }, }, }; } /// public override void Init(GameObject host, ThemeDefinition settings) { hostTransform = host.transform; originalLocalRotation = hostTransform.localEulerAngles; originalRotation = hostTransform.eulerAngles; base.Init(host, settings); } /// public override void Reset() { if (hostTransform != null) { hostTransform.localEulerAngles = originalLocalRotation; hostTransform.eulerAngles = originalRotation; } } /// public override ThemePropertyValue GetProperty(ThemeStateProperty property) { ThemePropertyValue start = new ThemePropertyValue(); start.Vector3 = IsLocalRotation ? hostTransform.localEulerAngles : hostTransform.eulerAngles; return start; } /// public override void SetValue(ThemeStateProperty property, int index, float percentage) { Vector3 lerpTarget = property.Values[index].Vector3; if (IsRelativeRotation) { lerpTarget = (IsLocalRotation ? originalLocalRotation : originalRotation) + lerpTarget; } SetRotation(Quaternion.Euler(Vector3.Lerp(property.StartValue.Vector3, lerpTarget, percentage))); } /// protected override void SetValue(ThemeStateProperty property, ThemePropertyValue value) { SetRotation(value.Quaternion); } private void SetRotation(Quaternion rot) { if (IsLocalRotation) { hostTransform.localRotation = rot; } else { hostTransform.rotation = rot; } } } }