// --------------------------------------------------------------------------------------------------------------------
//
// Copyright (c) VRMADA, All rights reserved.
//
// --------------------------------------------------------------------------------------------------------------------
using System;
using UltimateXR.Core;
using UnityEngine;
namespace UltimateXR.Avatar
{
///
/// Contains information about an that has moved/rotated. Avatars are moved/rotated
/// through functionality such as:
///
/// -
///
/// UxrManager.Instance.MoveAvatarTo
///
///
/// -
/// UxrManager.Instance.RotateAvatar
///
/// -
///
/// UxrManager.Instance.TeleportLocalAvatar
///
///
///
/// These methods will move/rotate the root transform of the avatar. If a user moves or rotates in the real-world, the
/// camera transform will be updated but the root avatar transform will remain fixed. Only moving or teleporting the
/// avatar will generate events.
///
public class UxrAvatarMoveEventArgs : EventArgs
{
#region Public Types & Data
///
/// Gets the old position.
///
public Vector3 OldPosition { get; }
///
/// Gets the old rotation.
///
public Quaternion OldRotation { get; }
///
/// Gets the new position.
///
public Vector3 NewPosition { get; }
///
/// Gets the new rotation.
///
public Quaternion NewRotation { get; }
///
/// Gets the old forward vector.
///
public Vector3 OldForward { get; private set; }
///
/// Gets the new forward vector.
///
public Vector3 NewForward { get; private set; }
///
/// Gets the old local to world matrix.
///
public Matrix4x4 OldWorldMatrix { get; private set; }
///
/// Gets the new local to world matrix.
///
public Matrix4x4 NewWorldMatrix { get; private set; }
///
/// Gets whether the avatar has changed its position.
///
public bool HasTranslation { get; private set; }
///
/// Gets whether the avatar has changed its rotation.
///
public bool HasRotation { get; private set; }
#endregion
#region Constructors & Finalizer
///
/// Constructor.
///
/// Old position
/// Old rotation
/// New position
/// New rotation
public UxrAvatarMoveEventArgs(Vector3 oldPosition, Quaternion oldRotation, Vector3 newPosition, Quaternion newRotation)
{
OldPosition = oldPosition;
OldRotation = oldRotation;
NewPosition = newPosition;
NewRotation = newRotation;
ComputeInternalData();
}
#endregion
#region Public Overrides object
///
public override string ToString()
{
if (HasTranslation && HasRotation)
{
return $"Avatar moved (OldPosition={OldPosition}, OldRotation={OldRotation}, NewPosition={NewPosition}, NewRotation={NewRotation})";
}
if (HasTranslation)
{
return $"Avatar moved (OldPosition={OldPosition}, NewPosition={NewPosition})";
}
return $"Avatar moved (OldRotation={OldPosition}, NewRotation={NewPosition})";
}
#endregion
#region Public Methods
///
/// Reorients and repositions a transform so that it keeps the relative position/orientation to the avatar after the
/// position changed event.
///
/// Transform to reorient/reposition
public void ReorientRelativeToAvatar(Transform transform)
{
GetKeepRelativeOrientationToAvatar(transform, out Vector3 position, out Quaternion rotation);
transform.SetPositionAndRotation(position, rotation);
}
///
/// Gets the new position and rotation an object would need to have to keep the same relative position/rotation to
/// the avatar after moving.
///
/// The transform to get the new position/rotation of
/// The new position
/// The new rotation
public void GetKeepRelativeOrientationToAvatar(Transform transform, out Vector3 position, out Quaternion rotation)
{
Vector3 relativePos = _oldWorldMatrixInverse.MultiplyPoint(transform.position);
Quaternion relativeRot = _oldRotationInverse * transform.rotation;
position = NewWorldMatrix.MultiplyPoint(relativePos);
rotation = NewRotation * relativeRot;
}
#endregion
#region Private Methods
///
/// Computes the helper properties and internal variables.
///
private void ComputeInternalData()
{
OldForward = OldRotation * Vector3.forward;
NewForward = NewRotation * Vector3.forward;
OldWorldMatrix = Matrix4x4.TRS(OldPosition, OldRotation, Vector3.one);
NewWorldMatrix = Matrix4x4.TRS(NewPosition, NewRotation, Vector3.one);
_oldWorldMatrixInverse = OldWorldMatrix.inverse;
_oldRotationInverse = Quaternion.Inverse(OldRotation);
HasTranslation = OldPosition != NewPosition;
HasRotation = OldRotation != NewRotation;
}
#endregion
#region Private Types & Data
private Matrix4x4 _oldWorldMatrixInverse;
private Quaternion _oldRotationInverse;
#endregion
}
}