HeavenStudio/Assets/Plugins/BezierSolution/BezierPoint.cs

459 lines
13 KiB
C#

using UnityEngine;
namespace BezierSolution
{
[AddComponentMenu( "Bezier Solution/Bezier Point" )]
[HelpURL( "https://github.com/yasirkula/UnityBezierSolution" )]
public partial class BezierPoint : MonoBehaviour
{
public Vector3 localPosition
{
get { return transform.localPosition; }
set
{
if( transform.localPosition == value )
return;
transform.localPosition = value;
spline.dirtyFlags |= InternalDirtyFlags.EndPointTransformChange | InternalDirtyFlags.ControlPointPositionChange;
}
}
#pragma warning disable 0649
[SerializeField, HideInInspector]
private Vector3 m_position;
public Vector3 position
{
get { return m_position; }
set
{
if( transform.position == value )
return;
transform.position = value;
spline.dirtyFlags |= InternalDirtyFlags.EndPointTransformChange | InternalDirtyFlags.ControlPointPositionChange;
}
}
public Quaternion localRotation
{
get { return transform.localRotation; }
set
{
if( transform.localRotation == value )
return;
transform.localRotation = value;
spline.dirtyFlags |= InternalDirtyFlags.EndPointTransformChange | InternalDirtyFlags.ControlPointPositionChange;
}
}
public Quaternion rotation
{
get { return transform.rotation; }
set
{
if( transform.rotation == value )
return;
transform.rotation = value;
spline.dirtyFlags |= InternalDirtyFlags.EndPointTransformChange | InternalDirtyFlags.ControlPointPositionChange;
}
}
public Vector3 localEulerAngles
{
get { return transform.localEulerAngles; }
set
{
if( transform.localEulerAngles == value )
return;
transform.localEulerAngles = value;
spline.dirtyFlags |= InternalDirtyFlags.EndPointTransformChange | InternalDirtyFlags.ControlPointPositionChange;
}
}
public Vector3 eulerAngles
{
get { return transform.eulerAngles; }
set
{
if( transform.eulerAngles == value )
return;
transform.eulerAngles = value;
spline.dirtyFlags |= InternalDirtyFlags.EndPointTransformChange | InternalDirtyFlags.ControlPointPositionChange;
}
}
public Vector3 localScale
{
get { return transform.localScale; }
set
{
if( transform.localScale == value )
return;
transform.localScale = value;
spline.dirtyFlags |= InternalDirtyFlags.EndPointTransformChange | InternalDirtyFlags.ControlPointPositionChange;
}
}
[SerializeField, HideInInspector]
private Vector3 m_precedingControlPointLocalPosition = Vector3.left;
public Vector3 precedingControlPointLocalPosition
{
get { return m_precedingControlPointLocalPosition; }
set
{
if( m_precedingControlPointLocalPosition == value )
return;
m_precedingControlPointLocalPosition = value;
m_precedingControlPointPosition = transform.TransformPoint( value );
if( m_handleMode == HandleMode.Aligned )
{
m_followingControlPointLocalPosition = -m_precedingControlPointLocalPosition.normalized * m_followingControlPointLocalPosition.magnitude;
m_followingControlPointPosition = transform.TransformPoint( m_followingControlPointLocalPosition );
}
else if( m_handleMode == HandleMode.Mirrored )
{
m_followingControlPointLocalPosition = -m_precedingControlPointLocalPosition;
m_followingControlPointPosition = transform.TransformPoint( m_followingControlPointLocalPosition );
}
spline.dirtyFlags |= InternalDirtyFlags.ControlPointPositionChange;
}
}
[SerializeField, HideInInspector]
private Vector3 m_precedingControlPointPosition;
public Vector3 precedingControlPointPosition
{
get { return m_precedingControlPointPosition; }
set
{
if( m_precedingControlPointPosition == value )
return;
m_precedingControlPointPosition = value;
m_precedingControlPointLocalPosition = transform.InverseTransformPoint( value );
if( transform.hasChanged )
{
m_position = transform.position;
m_followingControlPointPosition = transform.TransformPoint( m_followingControlPointLocalPosition );
spline.dirtyFlags |= InternalDirtyFlags.EndPointTransformChange;
transform.hasChanged = false;
}
if( m_handleMode == HandleMode.Aligned )
{
m_followingControlPointPosition = m_position - ( m_precedingControlPointPosition - m_position ).normalized *
( m_followingControlPointPosition - m_position ).magnitude;
m_followingControlPointLocalPosition = transform.InverseTransformPoint( m_followingControlPointPosition );
}
else if( m_handleMode == HandleMode.Mirrored )
{
m_followingControlPointPosition = 2f * m_position - m_precedingControlPointPosition;
m_followingControlPointLocalPosition = transform.InverseTransformPoint( m_followingControlPointPosition );
}
spline.dirtyFlags |= InternalDirtyFlags.ControlPointPositionChange;
}
}
[SerializeField, HideInInspector]
private Vector3 m_followingControlPointLocalPosition = Vector3.right;
public Vector3 followingControlPointLocalPosition
{
get { return m_followingControlPointLocalPosition; }
set
{
if( m_followingControlPointLocalPosition == value )
return;
m_followingControlPointLocalPosition = value;
m_followingControlPointPosition = transform.TransformPoint( value );
if( m_handleMode == HandleMode.Aligned )
{
m_precedingControlPointLocalPosition = -m_followingControlPointLocalPosition.normalized * m_precedingControlPointLocalPosition.magnitude;
m_precedingControlPointPosition = transform.TransformPoint( m_precedingControlPointLocalPosition );
}
else if( m_handleMode == HandleMode.Mirrored )
{
m_precedingControlPointLocalPosition = -m_followingControlPointLocalPosition;
m_precedingControlPointPosition = transform.TransformPoint( m_precedingControlPointLocalPosition );
}
spline.dirtyFlags |= InternalDirtyFlags.ControlPointPositionChange;
}
}
[SerializeField, HideInInspector]
private Vector3 m_followingControlPointPosition;
public Vector3 followingControlPointPosition
{
get { return m_followingControlPointPosition; }
set
{
if( m_followingControlPointPosition == value )
return;
m_followingControlPointPosition = value;
m_followingControlPointLocalPosition = transform.InverseTransformPoint( value );
if( transform.hasChanged )
{
m_position = transform.position;
m_precedingControlPointPosition = transform.TransformPoint( m_precedingControlPointLocalPosition );
spline.dirtyFlags |= InternalDirtyFlags.EndPointTransformChange;
transform.hasChanged = false;
}
if( m_handleMode == HandleMode.Aligned )
{
m_precedingControlPointPosition = m_position - ( m_followingControlPointPosition - m_position ).normalized *
( m_precedingControlPointPosition - m_position ).magnitude;
m_precedingControlPointLocalPosition = transform.InverseTransformPoint( m_precedingControlPointPosition );
}
else if( m_handleMode == HandleMode.Mirrored )
{
m_precedingControlPointPosition = 2f * m_position - m_followingControlPointPosition;
m_precedingControlPointLocalPosition = transform.InverseTransformPoint( m_precedingControlPointPosition );
}
spline.dirtyFlags |= InternalDirtyFlags.ControlPointPositionChange;
}
}
[SerializeField, HideInInspector]
private HandleMode m_handleMode = HandleMode.Mirrored;
public HandleMode handleMode
{
get { return m_handleMode; }
set
{
if( m_handleMode == value )
return;
m_handleMode = value;
if( value == HandleMode.Aligned || value == HandleMode.Mirrored )
{
// Temporarily change the value of m_precedingControlPointLocalPosition so that it will be different from precedingControlPointLocalPosition
// and precedingControlPointLocalPosition's setter will run
Vector3 _precedingControlPointLocalPosition = m_precedingControlPointLocalPosition;
m_precedingControlPointLocalPosition -= Vector3.one;
precedingControlPointLocalPosition = _precedingControlPointLocalPosition;
}
spline.dirtyFlags |= InternalDirtyFlags.ControlPointPositionChange;
}
}
[SerializeField, HideInInspector]
[UnityEngine.Serialization.FormerlySerializedAs( "normal" )]
private Vector3 m_normal = Vector3.up;
public Vector3 normal
{
get { return m_normal; }
set
{
if( m_normal == value )
return;
m_normal = value;
spline.dirtyFlags |= InternalDirtyFlags.NormalChange;
}
}
[SerializeField, HideInInspector]
[UnityEngine.Serialization.FormerlySerializedAs( "autoCalculatedNormalAngleOffset" )]
private float m_autoCalculatedNormalAngleOffset = 0f;
public float autoCalculatedNormalAngleOffset
{
get { return m_autoCalculatedNormalAngleOffset; }
set
{
if( m_autoCalculatedNormalAngleOffset == value )
return;
m_autoCalculatedNormalAngleOffset = value;
spline.dirtyFlags |= InternalDirtyFlags.NormalOffsetChange;
}
}
[SerializeField, HideInInspector]
private Vector3[] m_intermediateNormals;
public Vector3[] intermediateNormals
{
get { return m_intermediateNormals; }
set
{
// In this special case, don't early exit if the assigned array is the same because one of its elements might have changed.
// We can safely early exit if the assigned value was null or empty, though
if( ( m_intermediateNormals == null || m_intermediateNormals.Length == 0 ) && ( value == null || value.Length == 0 ) )
return;
m_intermediateNormals = value;
spline.dirtyFlags |= InternalDirtyFlags.NormalChange;
}
}
[SerializeField, HideInInspector]
[UnityEngine.Serialization.FormerlySerializedAs( "extraData" )]
private ExtraData m_extraData;
public ExtraData extraData
{
get { return m_extraData; }
set
{
if( m_extraData == value )
return;
m_extraData = value;
spline.dirtyFlags |= InternalDirtyFlags.ExtraDataChange;
}
}
#pragma warning restore 0649
public BezierSpline spline { get; internal set; }
public int index { get; internal set; }
public BezierPoint previousPoint
{
get
{
if( spline )
{
if( index > 0 )
return spline.endPoints[index - 1];
else if( spline.loop )
return spline.endPoints[spline.endPoints.Count - 1];
}
return null;
}
}
public BezierPoint nextPoint
{
get
{
if( spline )
{
if( index < spline.endPoints.Count - 1 )
return spline.endPoints[index + 1];
else if( spline.loop )
return spline.endPoints[0];
}
return null;
}
}
private void Awake()
{
transform.hasChanged = true;
}
private void OnDestroy()
{
if( spline )
spline.dirtyFlags |= InternalDirtyFlags.All;
}
public void CopyTo( BezierPoint other )
{
other.transform.localPosition = transform.localPosition;
other.transform.localRotation = transform.localRotation;
other.transform.localScale = transform.localScale;
other.m_handleMode = m_handleMode;
other.m_precedingControlPointLocalPosition = m_precedingControlPointLocalPosition;
other.m_followingControlPointLocalPosition = m_followingControlPointLocalPosition;
other.m_normal = m_normal;
other.m_autoCalculatedNormalAngleOffset = m_autoCalculatedNormalAngleOffset;
other.m_extraData = m_extraData;
}
public void Refresh()
{
m_position = transform.position;
m_precedingControlPointPosition = transform.TransformPoint( m_precedingControlPointLocalPosition );
m_followingControlPointPosition = transform.TransformPoint( m_followingControlPointLocalPosition );
transform.hasChanged = false;
}
internal void RefreshIfChanged()
{
if( transform.hasChanged )
{
Refresh();
spline.dirtyFlags |= InternalDirtyFlags.EndPointTransformChange | InternalDirtyFlags.ControlPointPositionChange;
}
}
internal void SetNormalAndResetIntermediateNormals( Vector3 normal, string undo )
{
if( spline && spline.autoCalculateNormals )
return;
#if UNITY_EDITOR
if( !string.IsNullOrEmpty( undo ) )
UnityEditor.Undo.RecordObject( this, undo );
#endif
this.normal = normal;
intermediateNormals = null;
BezierPoint previousPoint = this.previousPoint;
if( previousPoint && previousPoint.m_intermediateNormals != null && previousPoint.m_intermediateNormals.Length > 0 )
{
#if UNITY_EDITOR
if( !string.IsNullOrEmpty( undo ) )
UnityEditor.Undo.RecordObject( previousPoint, undo );
#endif
previousPoint.intermediateNormals = null;
}
}
public void Reset()
{
localPosition = Vector3.zero;
localRotation = Quaternion.identity;
localScale = Vector3.one;
precedingControlPointLocalPosition = Vector3.left;
followingControlPointLocalPosition = Vector3.right;
m_normal = Vector3.up;
m_autoCalculatedNormalAngleOffset = 0f;
m_extraData = new ExtraData();
transform.hasChanged = true;
}
#if UNITY_EDITOR
[ContextMenu( "Invert Spline" )]
private void InvertSplineContextMenu()
{
if( spline )
spline.InvertSpline( "Invert spline" );
}
#endif
}
}