using System;
using System.Collections.Generic;
namespace UnityEngine.U2D
{
// Spline Internal Meta Data.
internal struct SplinePointMetaData
{
public float height;
public uint spriteIndex;
public int cornerMode;
};
///
/// Spline contains control points used to define curve/outline for generating SpriteShape geometry.
///
[Serializable]
public class Spline
{
private static readonly string KErrorMessage = "Internal error: Point too close to neighbor";
private static readonly float KEpsilon = 0.01f;
[SerializeField]
private bool m_IsOpenEnded;
[SerializeField]
private List m_ControlPoints = new List();
///
/// Get/Set Spline's shape to open ended or closed.
///
public bool isOpenEnded
{
get
{
if (GetPointCount() < 3)
return true;
return m_IsOpenEnded;
}
set { m_IsOpenEnded = value; }
}
private bool IsPositionValid(int index, int next, Vector3 point)
{
int pointCount = GetPointCount();
if (isOpenEnded && (index == 0 || index == pointCount))
return true;
int prev = (index == 0) ? (pointCount - 1) : (index - 1);
if (prev >= 0)
{
Vector3 diff = m_ControlPoints[prev].position - point;
if (diff.magnitude < KEpsilon)
return false;
}
next = (next >= pointCount) ? 0 : next;
if (next < pointCount)
{
Vector3 diff = m_ControlPoints[next].position - point;
if (diff.magnitude < KEpsilon)
return false;
}
return true;
}
///
/// Clear all control points.
///
public void Clear()
{
m_ControlPoints.Clear();
}
///
/// Get Spline's control point count.
///
/// Count of control points.
public int GetPointCount()
{
return m_ControlPoints.Count;
}
///
/// Insert control point at index.
///
/// Index at which a control point will be inserted.
/// Position of the control point.
///
public void InsertPointAt(int index, Vector3 point)
{
if (!IsPositionValid(index, index, point))
throw new ArgumentException(KErrorMessage);
m_ControlPoints.Insert(index, new SplineControlPoint { position = point, height = 1.0f, cornerMode = Corner.Automatic });
}
///
/// Remove a control point from the Spline at index.
///
/// Index of the control point to be removed.
public void RemovePointAt(int index)
{
if (m_ControlPoints.Count > 2)
m_ControlPoints.RemoveAt(index);
}
///
/// Get position of control point at index.
///
/// Index of control point.
///
public Vector3 GetPosition(int index)
{
return m_ControlPoints[index].position;
}
///
/// Set position of control point at index.
///
/// Index of control point.
/// Position of control point.
///
public void SetPosition(int index, Vector3 point)
{
if (!IsPositionValid(index, index + 1, point))
throw new ArgumentException(KErrorMessage);
SplineControlPoint newPoint = m_ControlPoints[index];
newPoint.position = point;
m_ControlPoints[index] = newPoint;
}
///
/// Get left tangent of control point at index.
///
/// Index of control point.
/// Left tangent of control point.
public Vector3 GetLeftTangent(int index)
{
ShapeTangentMode mode = GetTangentMode(index);
if (mode == ShapeTangentMode.Linear)
return Vector3.zero;
return m_ControlPoints[index].leftTangent;
}
///
/// Set left tangent of control point at index.
///
/// Index of control point.
/// Left tangent of control point.
public void SetLeftTangent(int index, Vector3 tangent)
{
ShapeTangentMode mode = GetTangentMode(index);
if (mode == ShapeTangentMode.Linear)
return;
SplineControlPoint newPoint = m_ControlPoints[index];
newPoint.leftTangent = tangent;
m_ControlPoints[index] = newPoint;
}
///
/// Get right tangent of control point at index,
///
/// Index of control point.
/// Right tangent of control point.
public Vector3 GetRightTangent(int index)
{
ShapeTangentMode mode = GetTangentMode(index);
if (mode == ShapeTangentMode.Linear)
return Vector3.zero;
return m_ControlPoints[index].rightTangent;
}
///
/// Set right tangent of control point at index.
///
/// Index of control point.
/// Right tangent of control point.
public void SetRightTangent(int index, Vector3 tangent)
{
ShapeTangentMode mode = GetTangentMode(index);
if (mode == ShapeTangentMode.Linear)
return;
SplineControlPoint newPoint = m_ControlPoints[index];
newPoint.rightTangent = tangent;
m_ControlPoints[index] = newPoint;
}
///
/// Get tangent mode of control point at index.
///
/// Index of control point.
/// Tangent mode of control point
public ShapeTangentMode GetTangentMode(int index)
{
return m_ControlPoints[index].mode;
}
///
/// Set the tangent mode of control point at index.
///
/// Index of control point.
/// Tangent mode.
public void SetTangentMode(int index, ShapeTangentMode mode)
{
SplineControlPoint newPoint = m_ControlPoints[index];
newPoint.mode = mode;
m_ControlPoints[index] = newPoint;
}
///
/// Get height of control point at index.
///
/// Index of control point.
/// Height.
public float GetHeight(int index)
{
return m_ControlPoints[index].height;
}
///
/// Set height of control point at index.
///
/// Index of control point.
/// Height.
public void SetHeight(int index, float value)
{
m_ControlPoints[index].height = value;
}
///
/// Get Sprite index to be used for rendering edge starting at control point.
///
/// Index of control point.
/// Sprite index.
public int GetSpriteIndex(int index)
{
return m_ControlPoints[index].spriteIndex;
}
///
/// Set Sprite index to be used for rendering edge starting at control point.
///
/// Index of control point.
/// Sprite index.
public void SetSpriteIndex(int index, int value)
{
m_ControlPoints[index].spriteIndex = value;
}
///
/// Test if a corner mode is enabled at control point.
///
/// Index of control point.
/// True if a valid corner mode is set.
public bool GetCorner(int index)
{
return GetCornerMode(index) != Corner.Disable;
}
///
/// Set corner mode to automatic or disabled.
///
/// Index of control point.
/// Enable/disable corner mode
public void SetCorner(int index, bool value)
{
m_ControlPoints[index].corner = value;
m_ControlPoints[index].cornerMode = value ? Corner.Automatic : Corner.Disable;
}
public override int GetHashCode()
{
unchecked
{
int hashCode = (int)2166136261;
for (int i = 0; i < GetPointCount(); ++i)
{
hashCode = hashCode * 16777619 ^ m_ControlPoints[i].GetHashCode();
}
hashCode = hashCode * 16777619 ^ m_IsOpenEnded.GetHashCode();
return hashCode;
}
}
internal void SetCornerMode(int index, Corner value)
{
m_ControlPoints[index].corner = (value != Corner.Disable);
m_ControlPoints[index].cornerMode = value;
}
internal Corner GetCornerMode(int index)
{
if (m_ControlPoints[index].cornerMode == Corner.Disable)
{
// For backward compatibility.
if (m_ControlPoints[index].corner)
{
m_ControlPoints[index].cornerMode = Corner.Automatic;
return Corner.Automatic;
}
}
return m_ControlPoints[index].cornerMode;
}
}
}