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; } } }