mirror of
https://gitgud.io/AbstractConcept/rimworld-animation-studio.git
synced 2024-08-15 00:43:27 +00:00
Initial commit
This commit is contained in:
commit
3c7cc0c973
8391 changed files with 704313 additions and 0 deletions
|
@ -0,0 +1,223 @@
|
|||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.U2D.Path
|
||||
{
|
||||
public static class BezierUtility
|
||||
{
|
||||
static Vector3[] s_TempPoints = new Vector3[3];
|
||||
|
||||
public static Vector3 BezierPoint(Vector3 startPosition, Vector3 startTangent, Vector3 endTangent, Vector3 endPosition, float t)
|
||||
{
|
||||
float s = 1.0f - t;
|
||||
return startPosition * s * s * s + startTangent * s * s * t * 3.0f + endTangent * s * t * t * 3.0f + endPosition * t * t * t;
|
||||
}
|
||||
|
||||
public static Vector3 ClosestPointOnCurve(Vector3 point, Vector3 startPosition, Vector3 endPosition, Vector3 startTangent, Vector3 endTangent, out float t)
|
||||
{
|
||||
Vector3 startToEnd = endPosition - startPosition;
|
||||
Vector3 startToTangent = (startTangent - startPosition);
|
||||
Vector3 endToTangent = (endTangent - endPosition);
|
||||
|
||||
float sqrError = 0.001f;
|
||||
|
||||
if (Colinear(startToTangent, startToEnd, sqrError) && Colinear(endToTangent, startToEnd, sqrError))
|
||||
return ClosestPointToSegment(point, startPosition, endPosition, out t);
|
||||
|
||||
Vector3 leftStartPosition;
|
||||
Vector3 leftEndPosition;
|
||||
Vector3 leftStartTangent;
|
||||
Vector3 leftEndTangent;
|
||||
|
||||
Vector3 rightStartPosition;
|
||||
Vector3 rightEndPosition;
|
||||
Vector3 rightStartTangent;
|
||||
Vector3 rightEndTangent;
|
||||
|
||||
float leftStartT = 0f;
|
||||
float leftEndT = 0.5f;
|
||||
float rightStartT = 0.5f;
|
||||
float rightEndT = 1f;
|
||||
|
||||
SplitBezier(0.5f, startPosition, endPosition, startTangent, endTangent,
|
||||
out leftStartPosition, out leftEndPosition, out leftStartTangent, out leftEndTangent,
|
||||
out rightStartPosition, out rightEndPosition, out rightStartTangent, out rightEndTangent);
|
||||
|
||||
Vector3 pointLeft = ClosestPointOnCurveIterative(point, leftStartPosition, leftEndPosition, leftStartTangent, leftEndTangent, sqrError, ref leftStartT, ref leftEndT);
|
||||
Vector3 pointRight = ClosestPointOnCurveIterative(point, rightStartPosition, rightEndPosition, rightStartTangent, rightEndTangent, sqrError, ref rightStartT, ref rightEndT);
|
||||
|
||||
if ((point - pointLeft).sqrMagnitude < (point - pointRight).sqrMagnitude)
|
||||
{
|
||||
t = leftStartT;
|
||||
return pointLeft;
|
||||
}
|
||||
|
||||
t = rightStartT;
|
||||
return pointRight;
|
||||
}
|
||||
|
||||
public static Vector3 ClosestPointOnCurveFast(Vector3 point, Vector3 startPosition, Vector3 endPosition, Vector3 startTangent, Vector3 endTangent, out float t)
|
||||
{
|
||||
float sqrError = 0.001f;
|
||||
float startT = 0f;
|
||||
float endT = 1f;
|
||||
|
||||
Vector3 closestPoint = ClosestPointOnCurveIterative(point, startPosition, endPosition, startTangent, endTangent, sqrError, ref startT, ref endT);
|
||||
|
||||
t = startT;
|
||||
|
||||
return closestPoint;
|
||||
}
|
||||
|
||||
private static Vector3 ClosestPointOnCurveIterative(Vector3 point, Vector3 startPosition, Vector3 endPosition, Vector3 startTangent, Vector3 endTangent, float sqrError, ref float startT, ref float endT)
|
||||
{
|
||||
while ((startPosition - endPosition).sqrMagnitude > sqrError)
|
||||
{
|
||||
Vector3 startToEnd = endPosition - startPosition;
|
||||
Vector3 startToTangent = (startTangent - startPosition);
|
||||
Vector3 endToTangent = (endTangent - endPosition);
|
||||
|
||||
if (Colinear(startToTangent, startToEnd, sqrError) && Colinear(endToTangent, startToEnd, sqrError))
|
||||
{
|
||||
float t;
|
||||
Vector3 closestPoint = ClosestPointToSegment(point, startPosition, endPosition, out t);
|
||||
t *= (endT - startT);
|
||||
startT += t;
|
||||
endT -= t;
|
||||
return closestPoint;
|
||||
}
|
||||
|
||||
Vector3 leftStartPosition;
|
||||
Vector3 leftEndPosition;
|
||||
Vector3 leftStartTangent;
|
||||
Vector3 leftEndTangent;
|
||||
|
||||
Vector3 rightStartPosition;
|
||||
Vector3 rightEndPosition;
|
||||
Vector3 rightStartTangent;
|
||||
Vector3 rightEndTangent;
|
||||
|
||||
SplitBezier(0.5f, startPosition, endPosition, startTangent, endTangent,
|
||||
out leftStartPosition, out leftEndPosition, out leftStartTangent, out leftEndTangent,
|
||||
out rightStartPosition, out rightEndPosition, out rightStartTangent, out rightEndTangent);
|
||||
|
||||
s_TempPoints[0] = leftStartPosition;
|
||||
s_TempPoints[1] = leftStartTangent;
|
||||
s_TempPoints[2] = leftEndTangent;
|
||||
|
||||
float sqrDistanceLeft = SqrDistanceToPolyLine(point, s_TempPoints);
|
||||
|
||||
s_TempPoints[0] = rightEndPosition;
|
||||
s_TempPoints[1] = rightEndTangent;
|
||||
s_TempPoints[2] = rightStartTangent;
|
||||
|
||||
float sqrDistanceRight = SqrDistanceToPolyLine(point, s_TempPoints);
|
||||
|
||||
if (sqrDistanceLeft < sqrDistanceRight)
|
||||
{
|
||||
startPosition = leftStartPosition;
|
||||
endPosition = leftEndPosition;
|
||||
startTangent = leftStartTangent;
|
||||
endTangent = leftEndTangent;
|
||||
|
||||
endT -= (endT - startT) * 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
startPosition = rightStartPosition;
|
||||
endPosition = rightEndPosition;
|
||||
startTangent = rightStartTangent;
|
||||
endTangent = rightEndTangent;
|
||||
|
||||
startT += (endT - startT) * 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
return endPosition;
|
||||
}
|
||||
|
||||
public static void SplitBezier(float t, Vector3 startPosition, Vector3 endPosition, Vector3 startRightTangent, Vector3 endLeftTangent,
|
||||
out Vector3 leftStartPosition, out Vector3 leftEndPosition, out Vector3 leftStartTangent, out Vector3 leftEndTangent,
|
||||
out Vector3 rightStartPosition, out Vector3 rightEndPosition, out Vector3 rightStartTangent, out Vector3 rightEndTangent)
|
||||
{
|
||||
Vector3 tangent0 = (startRightTangent - startPosition);
|
||||
Vector3 tangent1 = (endLeftTangent - endPosition);
|
||||
Vector3 tangentEdge = (endLeftTangent - startRightTangent);
|
||||
|
||||
Vector3 tangentPoint0 = startPosition + tangent0 * t;
|
||||
Vector3 tangentPoint1 = endPosition + tangent1 * (1f - t);
|
||||
Vector3 tangentEdgePoint = startRightTangent + tangentEdge * t;
|
||||
|
||||
Vector3 newTangent0 = tangentPoint0 + (tangentEdgePoint - tangentPoint0) * t;
|
||||
Vector3 newTangent1 = tangentPoint1 + (tangentEdgePoint - tangentPoint1) * (1f - t);
|
||||
Vector3 newTangentEdge = newTangent1 - newTangent0;
|
||||
|
||||
Vector3 bezierPoint = newTangent0 + newTangentEdge * t;
|
||||
|
||||
leftStartPosition = startPosition;
|
||||
leftEndPosition = bezierPoint;
|
||||
leftStartTangent = tangentPoint0;
|
||||
leftEndTangent = newTangent0;
|
||||
|
||||
rightStartPosition = bezierPoint;
|
||||
rightEndPosition = endPosition;
|
||||
rightStartTangent = newTangent1;
|
||||
rightEndTangent = tangentPoint1;
|
||||
}
|
||||
|
||||
private static Vector3 ClosestPointToSegment(Vector3 point, Vector3 segmentStart, Vector3 segmentEnd, out float t)
|
||||
{
|
||||
Vector3 relativePoint = point - segmentStart;
|
||||
Vector3 segment = (segmentEnd - segmentStart);
|
||||
Vector3 segmentDirection = segment.normalized;
|
||||
float length = segment.magnitude;
|
||||
|
||||
float dot = Vector3.Dot(relativePoint, segmentDirection);
|
||||
|
||||
if (dot <= 0f)
|
||||
dot = 0f;
|
||||
else if (dot >= length)
|
||||
dot = length;
|
||||
|
||||
t = dot / length;
|
||||
|
||||
return segmentStart + segment * t;
|
||||
}
|
||||
|
||||
private static float SqrDistanceToPolyLine(Vector3 point, Vector3[] points)
|
||||
{
|
||||
float minDistance = float.MaxValue;
|
||||
|
||||
for (int i = 0; i < points.Length - 1; ++i)
|
||||
{
|
||||
float distance = SqrDistanceToSegment(point, points[i], points[i + 1]);
|
||||
|
||||
if (distance < minDistance)
|
||||
minDistance = distance;
|
||||
}
|
||||
|
||||
return minDistance;
|
||||
}
|
||||
|
||||
private static float SqrDistanceToSegment(Vector3 point, Vector3 segmentStart, Vector3 segmentEnd)
|
||||
{
|
||||
Vector3 relativePoint = point - segmentStart;
|
||||
Vector3 segment = (segmentEnd - segmentStart);
|
||||
Vector3 segmentDirection = segment.normalized;
|
||||
float length = segment.magnitude;
|
||||
|
||||
float dot = Vector3.Dot(relativePoint, segmentDirection);
|
||||
|
||||
if (dot <= 0f)
|
||||
return (point - segmentStart).sqrMagnitude;
|
||||
else if (dot >= length)
|
||||
return (point - segmentEnd).sqrMagnitude;
|
||||
|
||||
return Vector3.Cross(relativePoint, segmentDirection).sqrMagnitude;
|
||||
}
|
||||
|
||||
private static bool Colinear(Vector3 v1, Vector3 v2, float error = 0.0001f)
|
||||
{
|
||||
return Mathf.Abs(v1.x * v2.y - v1.y * v2.x + v1.x * v2.z - v1.z * v2.x + v1.y * v2.z - v1.z * v2.y) < error;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7539b6de552451b409d8d2f8657251c6
|
||||
timeCreated: 1505799796
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,73 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.U2D.Path
|
||||
{
|
||||
public enum TangentMode
|
||||
{
|
||||
Linear = 0,
|
||||
Continuous = 1,
|
||||
Broken = 2
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct TangentCache
|
||||
{
|
||||
public Vector3 leftTangent;
|
||||
public Vector3 rightTangent;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public struct ControlPoint
|
||||
{
|
||||
public Vector3 position;
|
||||
public Vector3 localLeftTangent;
|
||||
public Vector3 localRightTangent;
|
||||
public TangentMode tangentMode;
|
||||
public TangentCache continuousCache;
|
||||
public TangentCache brokenCache;
|
||||
public bool mirrorLeft;
|
||||
|
||||
public Vector3 leftTangent
|
||||
{
|
||||
get { return localLeftTangent + position; }
|
||||
set { localLeftTangent = value - position; }
|
||||
}
|
||||
|
||||
public Vector3 rightTangent
|
||||
{
|
||||
get { return localRightTangent + position; }
|
||||
set { localRightTangent = value - position; }
|
||||
}
|
||||
|
||||
public void StoreTangents()
|
||||
{
|
||||
if (tangentMode == TangentMode.Continuous)
|
||||
{
|
||||
continuousCache.leftTangent = localLeftTangent;
|
||||
continuousCache.rightTangent = localRightTangent;
|
||||
}
|
||||
else if (tangentMode == TangentMode.Broken)
|
||||
{
|
||||
brokenCache.leftTangent = localLeftTangent;
|
||||
brokenCache.rightTangent = localRightTangent;
|
||||
}
|
||||
}
|
||||
|
||||
public void RestoreTangents()
|
||||
{
|
||||
if (tangentMode == TangentMode.Continuous)
|
||||
{
|
||||
localLeftTangent = continuousCache.leftTangent;
|
||||
localRightTangent = continuousCache.rightTangent;
|
||||
}
|
||||
else if (tangentMode == TangentMode.Broken)
|
||||
{
|
||||
localLeftTangent = brokenCache.leftTangent;
|
||||
localRightTangent = brokenCache.rightTangent;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 6e22e7e2cce9e9346a8291ccf224487a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,147 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.U2D.Path
|
||||
{
|
||||
[Serializable]
|
||||
public class EditablePath : IEditablePath
|
||||
{
|
||||
[SerializeField]
|
||||
private ShapeType m_ShapeType;
|
||||
[SerializeField]
|
||||
private IndexedSelection m_Selection = new IndexedSelection();
|
||||
[SerializeField]
|
||||
private List<ControlPoint> m_ControlPoints = new List<ControlPoint>();
|
||||
[SerializeField]
|
||||
private bool m_IsOpenEnded;
|
||||
private Matrix4x4 m_LocalToWorldMatrix = Matrix4x4.identity;
|
||||
private Matrix4x4 m_WorldToLocalMatrix = Matrix4x4.identity;
|
||||
private Vector3 m_Forward = Vector3.forward;
|
||||
private Vector3 m_Up = Vector3.up;
|
||||
private Vector3 m_Right = Vector3.right;
|
||||
|
||||
public ShapeType shapeType
|
||||
{
|
||||
get { return m_ShapeType; }
|
||||
set { m_ShapeType = value; }
|
||||
}
|
||||
|
||||
public IUndoObject undoObject { get; set; }
|
||||
|
||||
public Matrix4x4 localToWorldMatrix
|
||||
{
|
||||
get { return m_LocalToWorldMatrix; }
|
||||
set
|
||||
{
|
||||
m_LocalToWorldMatrix = value;
|
||||
m_WorldToLocalMatrix = value.inverse;
|
||||
}
|
||||
}
|
||||
|
||||
public Vector3 forward
|
||||
{
|
||||
get { return m_Forward; }
|
||||
set { m_Forward = value; }
|
||||
}
|
||||
|
||||
public Vector3 up
|
||||
{
|
||||
get { return m_Up; }
|
||||
set { m_Up = value; }
|
||||
}
|
||||
|
||||
public Vector3 right
|
||||
{
|
||||
get { return m_Right; }
|
||||
set { m_Right = value; }
|
||||
}
|
||||
|
||||
public Matrix4x4 worldToLocalMatrix
|
||||
{
|
||||
get { return m_WorldToLocalMatrix; }
|
||||
}
|
||||
|
||||
public bool isOpenEnded
|
||||
{
|
||||
get
|
||||
{
|
||||
if (pointCount < 3)
|
||||
return true;
|
||||
|
||||
return m_IsOpenEnded;
|
||||
}
|
||||
set { m_IsOpenEnded = value; }
|
||||
}
|
||||
|
||||
public ISelection<int> selection
|
||||
{
|
||||
get { return m_Selection; }
|
||||
}
|
||||
|
||||
public int pointCount
|
||||
{
|
||||
get { return m_ControlPoints.Count; }
|
||||
}
|
||||
|
||||
public ControlPoint GetPoint(int index)
|
||||
{
|
||||
return TransformPoint(localToWorldMatrix, m_ControlPoints[index]);
|
||||
}
|
||||
|
||||
public void SetPoint(int index, ControlPoint controlPoint)
|
||||
{
|
||||
m_ControlPoints[index] = TransformPoint(worldToLocalMatrix, controlPoint);
|
||||
}
|
||||
|
||||
public void AddPoint(ControlPoint controlPoint)
|
||||
{
|
||||
m_ControlPoints.Insert(pointCount, TransformPoint(worldToLocalMatrix, controlPoint));
|
||||
}
|
||||
|
||||
public void InsertPoint(int index, ControlPoint controlPoint)
|
||||
{
|
||||
m_ControlPoints.Insert(index, TransformPoint(worldToLocalMatrix, controlPoint));
|
||||
}
|
||||
|
||||
public void RemovePoint(int index)
|
||||
{
|
||||
m_ControlPoints.RemoveAt(index);
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
m_ControlPoints.Clear();
|
||||
}
|
||||
|
||||
private ControlPoint TransformPoint(Matrix4x4 transformMatrix, ControlPoint controlPoint)
|
||||
{
|
||||
if (transformMatrix == Matrix4x4.identity)
|
||||
return controlPoint;
|
||||
|
||||
var newControlPoint = new ControlPoint()
|
||||
{
|
||||
position = transformMatrix.MultiplyPoint3x4(controlPoint.position),
|
||||
tangentMode = controlPoint.tangentMode,
|
||||
continuousCache = controlPoint.continuousCache,
|
||||
brokenCache = controlPoint.brokenCache,
|
||||
mirrorLeft = controlPoint.mirrorLeft
|
||||
};
|
||||
|
||||
newControlPoint.rightTangent = transformMatrix.MultiplyPoint3x4(controlPoint.rightTangent);
|
||||
newControlPoint.leftTangent = transformMatrix.MultiplyPoint3x4(controlPoint.leftTangent);
|
||||
|
||||
return newControlPoint;
|
||||
}
|
||||
|
||||
public bool Select(ISelector<Vector3> selector)
|
||||
{
|
||||
var changed = false;
|
||||
|
||||
for (var i = 0; i < pointCount; ++i)
|
||||
changed |= selection.Select(i, selector.Select(GetPoint(i).position));
|
||||
|
||||
return changed;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: cc93dba6e70bb8044a38eeb19db22669
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,259 @@
|
|||
using System;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.U2D.Path
|
||||
{
|
||||
public class EditablePathController : IEditablePathController
|
||||
{
|
||||
private ISnapping<Vector3> m_Snapping = new Snapping();
|
||||
|
||||
public IEditablePath editablePath { get; set; }
|
||||
public IEditablePath closestEditablePath { get { return editablePath; } }
|
||||
|
||||
public ISnapping<Vector3> snapping
|
||||
{
|
||||
get { return m_Snapping; }
|
||||
set { m_Snapping = value; }
|
||||
}
|
||||
|
||||
public bool enableSnapping { get; set; }
|
||||
|
||||
public void RegisterUndo(string name)
|
||||
{
|
||||
if (editablePath.undoObject != null)
|
||||
editablePath.undoObject.RegisterUndo(name);
|
||||
}
|
||||
|
||||
public void ClearSelection()
|
||||
{
|
||||
editablePath.selection.Clear();
|
||||
}
|
||||
|
||||
public void SelectPoint(int index, bool select)
|
||||
{
|
||||
editablePath.selection.Select(index, select);
|
||||
}
|
||||
|
||||
public void CreatePoint(int index, Vector3 position)
|
||||
{
|
||||
ClearSelection();
|
||||
|
||||
if (editablePath.shapeType == ShapeType.Polygon)
|
||||
{
|
||||
editablePath.InsertPoint(index + 1, new ControlPoint() { position = position });
|
||||
}
|
||||
else if (editablePath.shapeType == ShapeType.Spline)
|
||||
{
|
||||
var nextIndex = NextIndex(index);
|
||||
var currentPoint = editablePath.GetPoint(index);
|
||||
var nextPoint = editablePath.GetPoint(nextIndex);
|
||||
|
||||
float t;
|
||||
var closestPoint = BezierUtility.ClosestPointOnCurve(
|
||||
position,
|
||||
currentPoint.position,
|
||||
nextPoint.position,
|
||||
GetRightTangentPosition(index),
|
||||
GetLeftTangentPosition(nextIndex),
|
||||
out t);
|
||||
|
||||
Vector3 leftStartPosition;
|
||||
Vector3 leftEndPosition;
|
||||
Vector3 leftStartTangent;
|
||||
Vector3 leftEndTangent;
|
||||
|
||||
Vector3 rightStartPosition;
|
||||
Vector3 rightEndPosition;
|
||||
Vector3 rightStartTangent;
|
||||
Vector3 rightEndTangent;
|
||||
|
||||
BezierUtility.SplitBezier(t, currentPoint.position, nextPoint.position, GetRightTangentPosition(index), GetLeftTangentPosition(nextIndex),
|
||||
out leftStartPosition, out leftEndPosition, out leftStartTangent, out leftEndTangent,
|
||||
out rightStartPosition, out rightEndPosition, out rightStartTangent, out rightEndTangent);
|
||||
|
||||
var newPointIndex = index + 1;
|
||||
var newPoint = new ControlPoint()
|
||||
{
|
||||
position = closestPoint,
|
||||
leftTangent = leftEndTangent,
|
||||
rightTangent = rightStartTangent,
|
||||
tangentMode = TangentMode.Continuous
|
||||
};
|
||||
|
||||
currentPoint.rightTangent = leftStartTangent;
|
||||
nextPoint.leftTangent = rightEndTangent;
|
||||
|
||||
if (currentPoint.tangentMode == TangentMode.Linear && nextPoint.tangentMode == TangentMode.Linear)
|
||||
{
|
||||
newPoint.tangentMode = TangentMode.Linear;
|
||||
newPoint.localLeftTangent = Vector3.zero;
|
||||
newPoint.localRightTangent = Vector3.zero;
|
||||
currentPoint.localRightTangent = Vector3.zero;
|
||||
nextPoint.localLeftTangent = Vector3.zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (currentPoint.tangentMode == TangentMode.Linear)
|
||||
currentPoint.tangentMode = TangentMode.Broken;
|
||||
|
||||
if (nextPoint.tangentMode == TangentMode.Linear)
|
||||
nextPoint.tangentMode = TangentMode.Broken;
|
||||
}
|
||||
|
||||
editablePath.SetPoint(index, currentPoint);
|
||||
editablePath.SetPoint(nextIndex, nextPoint);
|
||||
editablePath.InsertPoint(newPointIndex, newPoint);
|
||||
}
|
||||
}
|
||||
|
||||
public void RemoveSelectedPoints()
|
||||
{
|
||||
var minPointCount = editablePath.isOpenEnded ? 2 : 3;
|
||||
|
||||
if (editablePath.pointCount > minPointCount)
|
||||
{
|
||||
var indices = editablePath.selection.elements.OrderByDescending( i => i);
|
||||
|
||||
foreach (var index in indices)
|
||||
if (editablePath.pointCount > minPointCount)
|
||||
editablePath.RemovePoint(index);
|
||||
|
||||
ClearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
public void MoveSelectedPoints(Vector3 delta)
|
||||
{
|
||||
delta = Vector3.ProjectOnPlane(delta, editablePath.forward);
|
||||
|
||||
for (var i = 0; i < editablePath.pointCount; ++i)
|
||||
{
|
||||
if (editablePath.selection.Contains(i))
|
||||
{
|
||||
var controlPoint = editablePath.GetPoint(i);
|
||||
controlPoint.position += delta;
|
||||
editablePath.SetPoint(i, controlPoint);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void MoveEdge(int index, Vector3 delta)
|
||||
{
|
||||
if (editablePath.isOpenEnded && index == editablePath.pointCount - 1)
|
||||
return;
|
||||
|
||||
var controlPoint = editablePath.GetPoint(index);
|
||||
controlPoint.position += delta;
|
||||
editablePath.SetPoint(index, controlPoint);
|
||||
controlPoint = NextControlPoint(index);
|
||||
controlPoint.position += delta;
|
||||
editablePath.SetPoint(NextIndex(index), controlPoint);
|
||||
}
|
||||
|
||||
public void SetLeftTangent(int index, Vector3 position, bool setToLinear, bool mirror, Vector3 cachedRightTangent, TangentMode cachedTangentMode)
|
||||
{
|
||||
var controlPoint = editablePath.GetPoint(index);
|
||||
controlPoint.tangentMode = cachedTangentMode;
|
||||
controlPoint.leftTangent = position;
|
||||
controlPoint.mirrorLeft = false;
|
||||
|
||||
if (setToLinear)
|
||||
{
|
||||
controlPoint.leftTangent = controlPoint.position;
|
||||
controlPoint.rightTangent = cachedRightTangent;
|
||||
}
|
||||
else if (controlPoint.tangentMode == TangentMode.Continuous || mirror)
|
||||
{
|
||||
var magnitude = controlPoint.localRightTangent.magnitude;
|
||||
|
||||
if (mirror)
|
||||
magnitude = controlPoint.localLeftTangent.magnitude;
|
||||
|
||||
controlPoint.localRightTangent = magnitude * -controlPoint.localLeftTangent.normalized;
|
||||
}
|
||||
|
||||
editablePath.SetPoint(index, controlPoint);
|
||||
editablePath.UpdateTangentMode(index);
|
||||
}
|
||||
|
||||
public void SetRightTangent(int index, Vector3 position, bool setToLinear, bool mirror, Vector3 cachedLeftTangent, TangentMode cachedTangentMode)
|
||||
{
|
||||
var controlPoint = editablePath.GetPoint(index);
|
||||
controlPoint.tangentMode = cachedTangentMode;
|
||||
controlPoint.rightTangent = position;
|
||||
controlPoint.mirrorLeft = true;
|
||||
|
||||
if (setToLinear)
|
||||
{
|
||||
controlPoint.rightTangent = controlPoint.position;
|
||||
controlPoint.leftTangent = cachedLeftTangent;
|
||||
}
|
||||
else if (controlPoint.tangentMode == TangentMode.Continuous || mirror)
|
||||
{
|
||||
var magnitude = controlPoint.localLeftTangent.magnitude;
|
||||
|
||||
if (mirror)
|
||||
magnitude = controlPoint.localRightTangent.magnitude;
|
||||
|
||||
controlPoint.localLeftTangent = magnitude * -controlPoint.localRightTangent.normalized;
|
||||
}
|
||||
|
||||
editablePath.SetPoint(index, controlPoint);
|
||||
editablePath.UpdateTangentMode(index);
|
||||
}
|
||||
|
||||
public void ClearClosestPath() { }
|
||||
public void AddClosestPath(float distance) { }
|
||||
|
||||
private Vector3 GetLeftTangentPosition(int index)
|
||||
{
|
||||
var isLinear = Mathf.Approximately(editablePath.GetPoint(index).localLeftTangent.sqrMagnitude, 0f);
|
||||
|
||||
if (isLinear)
|
||||
{
|
||||
var position = editablePath.GetPoint(index).position;
|
||||
var prevPosition = PrevControlPoint(index).position;
|
||||
|
||||
return (1f / 3f) * (prevPosition - position) + position;
|
||||
}
|
||||
|
||||
return editablePath.GetPoint(index).leftTangent;
|
||||
}
|
||||
|
||||
private Vector3 GetRightTangentPosition(int index)
|
||||
{
|
||||
var isLinear = Mathf.Approximately(editablePath.GetPoint(index).localRightTangent.sqrMagnitude, 0f);
|
||||
|
||||
if (isLinear)
|
||||
{
|
||||
var position = editablePath.GetPoint(index).position;
|
||||
var nextPosition = NextControlPoint(index).position;
|
||||
|
||||
return (1f / 3f) * (nextPosition - position) + position;
|
||||
}
|
||||
|
||||
return editablePath.GetPoint(index).rightTangent;
|
||||
}
|
||||
|
||||
private int NextIndex(int index)
|
||||
{
|
||||
return EditablePathUtility.Mod(index + 1, editablePath.pointCount);
|
||||
}
|
||||
|
||||
private ControlPoint NextControlPoint(int index)
|
||||
{
|
||||
return editablePath.GetPoint(NextIndex(index));
|
||||
}
|
||||
|
||||
private int PrevIndex(int index)
|
||||
{
|
||||
return EditablePathUtility.Mod(index - 1, editablePath.pointCount);
|
||||
}
|
||||
|
||||
private ControlPoint PrevControlPoint(int index)
|
||||
{
|
||||
return editablePath.GetPoint(PrevIndex(index));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e097fcf51266c654f8f8ef2c431a91d0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,275 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.U2D.Path
|
||||
{
|
||||
public static class EditablePathExtensions
|
||||
{
|
||||
public static Polygon ToPolygon(this IEditablePath path)
|
||||
{
|
||||
var polygon = new Polygon()
|
||||
{
|
||||
isOpenEnded = path.isOpenEnded,
|
||||
points = new Vector3[path.pointCount]
|
||||
};
|
||||
|
||||
for (var i = 0; i < path.pointCount; ++i)
|
||||
polygon.points[i] = path.GetPoint(i).position;
|
||||
|
||||
return polygon;
|
||||
}
|
||||
|
||||
public static Spline ToSpline(this IEditablePath path)
|
||||
{
|
||||
var count = path.pointCount * 3;
|
||||
|
||||
if (path.isOpenEnded)
|
||||
count -= 2;
|
||||
|
||||
var spline = new Spline()
|
||||
{
|
||||
isOpenEnded = path.isOpenEnded,
|
||||
points = new Vector3[count]
|
||||
};
|
||||
|
||||
for (var i = 0; i < path.pointCount; ++i)
|
||||
{
|
||||
var point = path.GetPoint(i);
|
||||
|
||||
spline.points[i*3] = point.position;
|
||||
|
||||
if (i * 3 + 1 < count)
|
||||
{
|
||||
var nextIndex = EditablePathUtility.Mod(i+1, path.pointCount);
|
||||
|
||||
spline.points[i*3 + 1] = path.CalculateRightTangent(i);
|
||||
spline.points[i*3 + 2] = path.CalculateLeftTangent(nextIndex);
|
||||
}
|
||||
}
|
||||
|
||||
return spline;
|
||||
}
|
||||
|
||||
public static Vector3 CalculateLocalLeftTangent(this IEditablePath path, int index)
|
||||
{
|
||||
return path.CalculateLeftTangent(index) - path.GetPoint(index).position;
|
||||
}
|
||||
|
||||
public static Vector3 CalculateLeftTangent(this IEditablePath path, int index)
|
||||
{
|
||||
var point = path.GetPoint(index);
|
||||
var isTangentLinear = point.localLeftTangent == Vector3.zero;
|
||||
var isEndpoint = path.isOpenEnded && index == 0;
|
||||
var tangent = point.leftTangent;
|
||||
|
||||
if (isEndpoint)
|
||||
return point.position;
|
||||
|
||||
if (isTangentLinear)
|
||||
{
|
||||
var prevPoint = path.GetPrevPoint(index);
|
||||
var v = prevPoint.position - point.position;
|
||||
tangent = point.position + v.normalized * (v.magnitude / 3f);
|
||||
}
|
||||
|
||||
return tangent;
|
||||
}
|
||||
|
||||
public static Vector3 CalculateLocalRightTangent(this IEditablePath path, int index)
|
||||
{
|
||||
return path.CalculateRightTangent(index) - path.GetPoint(index).position;
|
||||
}
|
||||
|
||||
public static Vector3 CalculateRightTangent(this IEditablePath path, int index)
|
||||
{
|
||||
var point = path.GetPoint(index);
|
||||
var isTangentLinear = point.localRightTangent == Vector3.zero;
|
||||
var isEndpoint = path.isOpenEnded && index == path.pointCount - 1;
|
||||
var tangent = point.rightTangent;
|
||||
|
||||
if (isEndpoint)
|
||||
return point.position;
|
||||
|
||||
if (isTangentLinear)
|
||||
{
|
||||
var nextPoint = path.GetNextPoint(index);
|
||||
var v = nextPoint.position - point.position;
|
||||
tangent = point.position + v.normalized * (v.magnitude / 3f);
|
||||
}
|
||||
|
||||
return tangent;
|
||||
}
|
||||
|
||||
public static ControlPoint GetPrevPoint(this IEditablePath path, int index)
|
||||
{
|
||||
return path.GetPoint(EditablePathUtility.Mod(index - 1, path.pointCount));
|
||||
}
|
||||
|
||||
public static ControlPoint GetNextPoint(this IEditablePath path, int index)
|
||||
{
|
||||
return path.GetPoint(EditablePathUtility.Mod(index + 1, path.pointCount));
|
||||
}
|
||||
|
||||
public static void UpdateTangentMode(this IEditablePath path, int index)
|
||||
{
|
||||
var localToWorldMatrix = path.localToWorldMatrix;
|
||||
path.localToWorldMatrix = Matrix4x4.identity;
|
||||
|
||||
var controlPoint = path.GetPoint(index);
|
||||
var isLeftTangentLinear = controlPoint.localLeftTangent == Vector3.zero;
|
||||
var isRightTangentLinear = controlPoint.localRightTangent == Vector3.zero;
|
||||
|
||||
if (isLeftTangentLinear && isRightTangentLinear)
|
||||
controlPoint.tangentMode = TangentMode.Linear;
|
||||
else if (isLeftTangentLinear || isRightTangentLinear)
|
||||
controlPoint.tangentMode = TangentMode.Broken;
|
||||
else if (controlPoint.tangentMode != TangentMode.Continuous)
|
||||
controlPoint.tangentMode = TangentMode.Broken;
|
||||
|
||||
controlPoint.StoreTangents();
|
||||
path.SetPoint(index, controlPoint);
|
||||
path.localToWorldMatrix = localToWorldMatrix;
|
||||
}
|
||||
|
||||
public static void UpdateTangentsFromMode(this IEditablePath path)
|
||||
{
|
||||
const float kEpsilon = 0.001f;
|
||||
|
||||
var localToWorldMatrix = path.localToWorldMatrix;
|
||||
path.localToWorldMatrix = Matrix4x4.identity;
|
||||
|
||||
for (var i = 0; i < path.pointCount; ++i)
|
||||
{
|
||||
var controlPoint = path.GetPoint(i);
|
||||
|
||||
if (controlPoint.tangentMode == TangentMode.Linear)
|
||||
{
|
||||
controlPoint.localLeftTangent = Vector3.zero;
|
||||
controlPoint.localRightTangent = Vector3.zero;
|
||||
}
|
||||
else if (controlPoint.tangentMode == TangentMode.Broken)
|
||||
{
|
||||
var isLeftEndpoint = path.isOpenEnded && i == 0;
|
||||
var prevPoint = path.GetPrevPoint(i);
|
||||
var nextPoint = path.GetNextPoint(i);
|
||||
|
||||
var liniarLeftPosition = (prevPoint.position - controlPoint.position) / 3f;
|
||||
var isLeftTangentLinear = isLeftEndpoint || (controlPoint.localLeftTangent - liniarLeftPosition).sqrMagnitude < kEpsilon;
|
||||
|
||||
if (isLeftTangentLinear)
|
||||
controlPoint.localLeftTangent = Vector3.zero;
|
||||
|
||||
var isRightEndpoint = path.isOpenEnded && i == path.pointCount-1;
|
||||
var liniarRightPosition = (nextPoint.position - controlPoint.position) / 3f;
|
||||
var isRightTangentLinear = isRightEndpoint || (controlPoint.localRightTangent - liniarRightPosition).sqrMagnitude < kEpsilon;
|
||||
|
||||
if (isRightTangentLinear)
|
||||
controlPoint.localRightTangent = Vector3.zero;
|
||||
|
||||
if (isLeftTangentLinear && isRightTangentLinear)
|
||||
controlPoint.tangentMode = TangentMode.Linear;
|
||||
}
|
||||
else if (controlPoint.tangentMode == TangentMode.Continuous)
|
||||
{
|
||||
//TODO: ensure tangent continuity
|
||||
}
|
||||
|
||||
controlPoint.StoreTangents();
|
||||
path.SetPoint(i, controlPoint);
|
||||
}
|
||||
|
||||
path.localToWorldMatrix = localToWorldMatrix;
|
||||
}
|
||||
|
||||
public static void SetTangentMode(this IEditablePath path, int index, TangentMode tangentMode)
|
||||
{
|
||||
var localToWorldMatrix = path.localToWorldMatrix;
|
||||
path.localToWorldMatrix = Matrix4x4.identity;
|
||||
|
||||
var controlPoint = path.GetPoint(index);
|
||||
var isEndpoint = path.isOpenEnded && (index == 0 || index == path.pointCount - 1);
|
||||
var oldTangentMode = controlPoint.tangentMode;
|
||||
|
||||
controlPoint.tangentMode = tangentMode;
|
||||
controlPoint.RestoreTangents();
|
||||
|
||||
if (tangentMode == TangentMode.Linear)
|
||||
{
|
||||
controlPoint.localLeftTangent = Vector3.zero;
|
||||
controlPoint.localRightTangent = Vector3.zero;
|
||||
}
|
||||
else if (tangentMode == TangentMode.Continuous && !isEndpoint)
|
||||
{
|
||||
var isLeftLinear = controlPoint.localLeftTangent == Vector3.zero;
|
||||
var isRightLinear = controlPoint.localRightTangent == Vector3.zero;
|
||||
var tangentDotProduct = Vector3.Dot(controlPoint.localLeftTangent.normalized, controlPoint.localRightTangent.normalized);
|
||||
var isContinous = tangentDotProduct < 0f && (tangentDotProduct + 1) < 0.001f;
|
||||
var isLinear = isLeftLinear && isRightLinear;
|
||||
|
||||
if ((isLinear || oldTangentMode == TangentMode.Broken) && !isContinous)
|
||||
{
|
||||
var prevPoint = path.GetPrevPoint(index);
|
||||
var nextPoint = path.GetNextPoint(index);
|
||||
var vLeft = prevPoint.position - controlPoint.position;
|
||||
var vRight = nextPoint.position - controlPoint.position;
|
||||
var rightDirection = Vector3.Cross(Vector3.Cross(vLeft, vRight), vLeft.normalized + vRight.normalized).normalized;
|
||||
var scale = 1f / 3f;
|
||||
|
||||
if (isLeftLinear)
|
||||
controlPoint.localLeftTangent = vLeft.magnitude * scale * -rightDirection;
|
||||
else
|
||||
controlPoint.localLeftTangent = controlPoint.localLeftTangent.magnitude * -rightDirection;
|
||||
|
||||
if (isRightLinear)
|
||||
controlPoint.localRightTangent = vRight.magnitude * scale * rightDirection;
|
||||
else
|
||||
controlPoint.localRightTangent = controlPoint.localRightTangent.magnitude * rightDirection;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var isLeftLinear = controlPoint.localLeftTangent == Vector3.zero;
|
||||
var isRightLinear = controlPoint.localRightTangent == Vector3.zero;
|
||||
|
||||
if (isLeftLinear || isRightLinear)
|
||||
{
|
||||
if (isLeftLinear)
|
||||
controlPoint.localLeftTangent = path.CalculateLocalLeftTangent(index);
|
||||
|
||||
if (isRightLinear)
|
||||
controlPoint.localRightTangent = path.CalculateLocalRightTangent(index);
|
||||
}
|
||||
}
|
||||
|
||||
controlPoint.StoreTangents();
|
||||
path.SetPoint(index, controlPoint);
|
||||
path.localToWorldMatrix = localToWorldMatrix;
|
||||
}
|
||||
|
||||
public static void MirrorTangent(this IEditablePath path, int index)
|
||||
{
|
||||
var localToWorldMatrix = path.localToWorldMatrix;
|
||||
path.localToWorldMatrix = Matrix4x4.identity;
|
||||
|
||||
var controlPoint = path.GetPoint(index);
|
||||
|
||||
if (controlPoint.tangentMode == TangentMode.Linear)
|
||||
return;
|
||||
|
||||
if (!Mathf.Approximately((controlPoint.localLeftTangent + controlPoint.localRightTangent).sqrMagnitude, 0f))
|
||||
{
|
||||
if (controlPoint.mirrorLeft)
|
||||
controlPoint.localLeftTangent = -controlPoint.localRightTangent;
|
||||
else
|
||||
controlPoint.localRightTangent = -controlPoint.localLeftTangent;
|
||||
|
||||
controlPoint.StoreTangents();
|
||||
path.SetPoint(index, controlPoint);
|
||||
}
|
||||
|
||||
path.localToWorldMatrix = localToWorldMatrix;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 118640352bf706b49aa5ece0cf51b03c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,14 @@
|
|||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace UnityEditor.U2D.Path
|
||||
{
|
||||
public class EditablePathUtility
|
||||
{
|
||||
public static int Mod(int x, int m)
|
||||
{
|
||||
int r = x % m;
|
||||
return r < 0 ? r + m : r;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 136ca6dbbd8b9704cb676d8e400f8096
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,24 @@
|
|||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.U2D.Path
|
||||
{
|
||||
public interface IEditablePath : ISelectable<Vector3>
|
||||
{
|
||||
ShapeType shapeType { get; set; }
|
||||
IUndoObject undoObject { get; set; }
|
||||
ISelection<int> selection { get; }
|
||||
Matrix4x4 localToWorldMatrix { get; set; }
|
||||
Vector3 forward { get; set; }
|
||||
Vector3 up { get; set; }
|
||||
Vector3 right { get; set; }
|
||||
bool isOpenEnded { get; set; }
|
||||
int pointCount { get; }
|
||||
ControlPoint GetPoint(int index);
|
||||
void SetPoint(int index, ControlPoint controlPoint);
|
||||
void AddPoint(ControlPoint controlPoint);
|
||||
void InsertPoint(int index, ControlPoint controlPoint);
|
||||
void RemovePoint(int index);
|
||||
void Clear();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5db033e7b440e254688b2fcca87e6a59
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,24 @@
|
|||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.U2D.Path
|
||||
{
|
||||
public interface IEditablePathController
|
||||
{
|
||||
IEditablePath editablePath { get; set; }
|
||||
IEditablePath closestEditablePath { get; }
|
||||
ISnapping<Vector3> snapping { get; set; }
|
||||
bool enableSnapping { get; set; }
|
||||
void RegisterUndo(string name);
|
||||
void ClearSelection();
|
||||
void SelectPoint(int index, bool select);
|
||||
void CreatePoint(int index, Vector3 position);
|
||||
void RemoveSelectedPoints();
|
||||
void MoveSelectedPoints(Vector3 delta);
|
||||
void MoveEdge(int index, Vector3 delta);
|
||||
void SetLeftTangent(int index, Vector3 position, bool setToLinear, bool mirror, Vector3 cachedRightTangent, TangentMode cachedTangentMode);
|
||||
void SetRightTangent(int index, Vector3 position, bool setToLinear, bool mirror, Vector3 cachedLeftTangent, TangentMode cachedTangentMode);
|
||||
void ClearClosestPath();
|
||||
void AddClosestPath(float distance);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 2416be64a5db15c4eb742e5f086682c3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,10 @@
|
|||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace UnityEditor.U2D.Path
|
||||
{
|
||||
public interface ISnapping<T>
|
||||
{
|
||||
T Snap(T value);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: f15c4dfafb6d6d544ab56d8cfca74d07
|
||||
timeCreated: 1505113416
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.U2D.Path
|
||||
{
|
||||
public interface IUndoObject
|
||||
{
|
||||
void RegisterUndo(string name);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 55ba72d694e736b428394820f9ca8f24
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,153 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEditor.U2D.Path
|
||||
{
|
||||
public class MultipleEditablePathController : IEditablePathController
|
||||
{
|
||||
private IEditablePathController m_Controller = new EditablePathController();
|
||||
private List<IEditablePath> m_Paths = new List<IEditablePath>();
|
||||
private float m_ClosestDistance = float.MaxValue;
|
||||
private IEditablePath m_ClosestPath;
|
||||
|
||||
public IEditablePath editablePath
|
||||
{
|
||||
get { return m_Controller.editablePath; }
|
||||
set { m_Controller.editablePath = value; }
|
||||
}
|
||||
|
||||
public IEditablePath closestEditablePath { get; private set; }
|
||||
|
||||
public ISnapping<Vector3> snapping
|
||||
{
|
||||
get { return m_Controller.snapping; }
|
||||
set { m_Controller.snapping = value; }
|
||||
}
|
||||
|
||||
public bool enableSnapping
|
||||
{
|
||||
get { return m_Controller.enableSnapping; }
|
||||
set { m_Controller.enableSnapping = value; }
|
||||
}
|
||||
|
||||
public void ClearPaths()
|
||||
{
|
||||
m_Paths.Clear();
|
||||
}
|
||||
|
||||
public void AddPath(IEditablePath path)
|
||||
{
|
||||
if (!m_Paths.Contains(path))
|
||||
m_Paths.Add(path);
|
||||
}
|
||||
|
||||
public void RemovePath(IEditablePath path)
|
||||
{
|
||||
m_Paths.Remove(path);
|
||||
}
|
||||
|
||||
public void RegisterUndo(string name)
|
||||
{
|
||||
var current = editablePath;
|
||||
|
||||
ForEach((s) =>
|
||||
{
|
||||
editablePath = s;
|
||||
m_Controller.RegisterUndo(name);
|
||||
});
|
||||
|
||||
editablePath = current;
|
||||
}
|
||||
|
||||
public void ClearSelection()
|
||||
{
|
||||
var current = editablePath;
|
||||
|
||||
ForEach((s) =>
|
||||
{
|
||||
editablePath = s;
|
||||
m_Controller.ClearSelection();
|
||||
});
|
||||
|
||||
editablePath = current;
|
||||
}
|
||||
|
||||
public void SelectPoint(int index, bool select)
|
||||
{
|
||||
m_Controller.SelectPoint(index, select);
|
||||
}
|
||||
|
||||
public void CreatePoint(int index, Vector3 position)
|
||||
{
|
||||
m_Controller.CreatePoint(index, position);
|
||||
}
|
||||
|
||||
public void RemoveSelectedPoints()
|
||||
{
|
||||
var current = editablePath;
|
||||
|
||||
ForEach((s) =>
|
||||
{
|
||||
editablePath = s;
|
||||
m_Controller.RemoveSelectedPoints();
|
||||
});
|
||||
|
||||
editablePath = current;
|
||||
}
|
||||
|
||||
public void MoveSelectedPoints(Vector3 delta)
|
||||
{
|
||||
var current = editablePath;
|
||||
|
||||
ForEach((s) =>
|
||||
{
|
||||
editablePath = s;
|
||||
m_Controller.MoveSelectedPoints(delta);
|
||||
});
|
||||
|
||||
editablePath = current;
|
||||
}
|
||||
|
||||
public void MoveEdge(int index, Vector3 delta)
|
||||
{
|
||||
m_Controller.MoveEdge(index, delta);
|
||||
}
|
||||
|
||||
public void SetLeftTangent(int index, Vector3 position, bool setToLinear, bool mirror, Vector3 cachedRightTangent, TangentMode cachedTangentMode)
|
||||
{
|
||||
m_Controller.SetLeftTangent(index, position, setToLinear, mirror, cachedRightTangent, cachedTangentMode);
|
||||
}
|
||||
|
||||
public void SetRightTangent(int index, Vector3 position, bool setToLinear, bool mirror, Vector3 cachedLeftTangent, TangentMode cachedTangentMode)
|
||||
{
|
||||
m_Controller.SetRightTangent(index, position, setToLinear, mirror, cachedLeftTangent, cachedTangentMode);
|
||||
}
|
||||
|
||||
public void ClearClosestPath()
|
||||
{
|
||||
m_ClosestDistance = float.MaxValue;
|
||||
closestEditablePath = null;
|
||||
}
|
||||
|
||||
public void AddClosestPath(float distance)
|
||||
{
|
||||
if (distance <= m_ClosestDistance)
|
||||
{
|
||||
m_ClosestDistance = distance;
|
||||
closestEditablePath = editablePath;
|
||||
}
|
||||
}
|
||||
|
||||
private void ForEach(Action<IEditablePath> action)
|
||||
{
|
||||
foreach(var path in m_Paths)
|
||||
{
|
||||
if (path == null)
|
||||
continue;
|
||||
|
||||
action(path);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 4e9b894eff389bc4b914e86801e4cb25
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,21 @@
|
|||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace UnityEditor.U2D.Path
|
||||
{
|
||||
public class Snapping : ISnapping<Vector3>
|
||||
{
|
||||
public Vector3 Snap(Vector3 position)
|
||||
{
|
||||
return new Vector3(
|
||||
Snap(position.x, EditorSnapSettings.move.x),
|
||||
Snap(position.y, EditorSnapSettings.move.y),
|
||||
position.z);
|
||||
}
|
||||
|
||||
private float Snap(float value, float snap)
|
||||
{
|
||||
return Mathf.Round(value / snap) * snap;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,13 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 729f75e79f7b4da458ab89bf1f36dc90
|
||||
timeCreated: 1505113416
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue