Initial commit

This commit is contained in:
AbstractConcept 2022-09-13 00:36:34 -05:00
commit 3c7cc0c973
8391 changed files with 704313 additions and 0 deletions

View file

@ -0,0 +1,41 @@
# Changelog
## [2.1.0] - 2020-11-16
###Changed
- Minor version bump due to change in required Unity version
## [2.0.6] - 2020-07-17
### Changed
- Snapping Control Points and Tangents use Global Move Snap settings.
## [2.0.5] - 2020-05-08
### Changed
- Added return for Path tool usage change.
## [2.0.4] - 2019-10-27
### Fixed
- Added missing meta file
## [2.0.3] - 2019-10-02
### Fixed
- Removed resources
## [2.0.2] - 2019-07-24
### Added
- Add related test packages
## [2.0.1] - 2019-07-13
### Changed
- Mark package to support Unity 2019.3.0a10 onwards.
## [2.0.0] - 2019-06-19
### Changed.
- Stable Version.
## [1.0.0-preview.3] - 2019-06-14
### Fixed
- Fix undo on select point.
## [1.0.0-preview.1] - 2019-04-22
### Added
- Initial Version.

View file

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: c1b975030cb01fa4fb63b07dc5584b12
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,3 @@
# Introduction
2D Path provides a set of tools to edit polygons and b-splines in custom EditorWindow and the SceneView.

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ebb15515f9c03364089baa7120b54453
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: c69472069f4ff5e4b9db75c91210288f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

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

View file

@ -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:

View file

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

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6e22e7e2cce9e9346a8291ccf224487a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

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

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cc93dba6e70bb8044a38eeb19db22669
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

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

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e097fcf51266c654f8f8ef2c431a91d0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

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

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 118640352bf706b49aa5ece0cf51b03c
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

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

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 136ca6dbbd8b9704cb676d8e400f8096
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -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();
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5db033e7b440e254688b2fcca87e6a59
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

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

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2416be64a5db15c4eb742e5f086682c3
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,10 @@
using UnityEngine;
using UnityEditor;
namespace UnityEditor.U2D.Path
{
public interface ISnapping<T>
{
T Snap(T value);
}
}

View file

@ -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:

View file

@ -0,0 +1,9 @@
using UnityEngine;
namespace UnityEditor.U2D.Path
{
public interface IUndoObject
{
void RegisterUndo(string name);
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 55ba72d694e736b428394820f9ca8f24
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

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

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4e9b894eff389bc4b914e86801e4cb25
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

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

View file

@ -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:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 47fb61e2873922c4893faa7eff277f25
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,2 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Unity.2D.SpriteShape.Editor")]

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b8de732c98460ec4ca63677f37beb1e8
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,72 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.U2D.Path
{
public class GenericScriptablePath<T> : ScriptablePath
{
[SerializeField]
private List<T> m_Data = new List<T>();
public T[] data
{
get { return m_Data.ToArray(); }
set
{
if (value.Length != pointCount)
throw new Exception("Custom data count does not match control point count");
m_Data.Clear();
m_Data.AddRange(value);
}
}
public override void Clear()
{
base.Clear();
m_Data.Clear();
}
public override void AddPoint(ControlPoint controlPoint)
{
base.AddPoint(controlPoint);
m_Data.Add(Create());
}
public override void InsertPoint(int index, ControlPoint controlPoint)
{
base.InsertPoint(index, controlPoint);
m_Data.Insert(index, Create());
}
public override void RemovePoint(int index)
{
base.RemovePoint(index);
Destroy(m_Data[index]);
m_Data.RemoveAt(index);
}
public T GetData(int index)
{
return m_Data[index];
}
public void SetData(int index, T data)
{
m_Data[index] = data;
}
protected virtual T Create()
{
return Activator.CreateInstance<T>();
}
protected virtual void Destroy(T data) { }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 91ab30a448166b74e99d488f537bfc67
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,120 @@
using System;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.EditorTools;
namespace UnityEditor.U2D.Path
{
public class GenericScriptablePathInspector<U,T> : ScriptablePathInspector where U : ScriptableData<T>
{
private List<U> m_DataObjects = new List<U>();
private List<U> m_SelectedDataObjects = new List<U>();
private Editor m_CachedEditor = null;
private void OnEnable()
{
PrepareDataObjects();
}
private void OnDestroy()
{
DestroyDataObjects();
}
public override void OnInspectorGUI()
{
base.OnInspectorGUI();
DoCustomDataInspector();
}
protected void DoCustomDataInspector()
{
PrepareDataObjects();
if (m_SelectedDataObjects.Count > 0)
{
CreateCachedEditor(m_SelectedDataObjects.ToArray(), null, ref m_CachedEditor);
EditorGUI.BeginChangeCheck();
m_CachedEditor.OnInspectorGUI();
if (EditorGUI.EndChangeCheck())
SetDataObjects();
}
}
private void PrepareDataObjects()
{
var elementCount = 0;
m_SelectedDataObjects.Clear();
foreach(var path in paths)
elementCount += path.pointCount;
while (m_DataObjects.Count < elementCount)
CreateDataObject();
var index = 0;
foreach(var path in paths)
{
var genericPath = path as GenericScriptablePath<T>;
var customDataArray = genericPath.data;
var length = customDataArray.Length;
for (var i = 0; i < length; ++i)
{
var dataObject = m_DataObjects[index + i];
dataObject.data = customDataArray[i];
if (path.selection.Contains(i))
{
dataObject.owner = path.owner;
dataObject.index = i;
m_SelectedDataObjects.Add(dataObject);
}
}
index += length;
}
}
private void SetDataObjects()
{
var index = 0;
foreach(var path in paths)
{
var genericPath = path as GenericScriptablePath<T>;
var customDataArray = genericPath.data;
var length = customDataArray.Length;
for (var i = 0; i < length; ++i)
customDataArray[i] = m_DataObjects[index + i].data;
genericPath.data = customDataArray;
index += length;
}
}
private U CreateDataObject()
{
var dataObject = ScriptableObject.CreateInstance<U>();
m_DataObjects.Add(dataObject);
return dataObject;
}
private void DestroyDataObjects()
{
foreach (var customDataObject in m_DataObjects)
DestroyImmediate(customDataObject);
m_DataObjects.Clear();
m_SelectedDataObjects.Clear();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d8d7f8780c69f9742b827ffd638225fb
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,123 @@
using System;
using System.Linq;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.EditorTools;
namespace UnityEditor.U2D.Path
{
public abstract class PathComponentEditor<T> : Editor where T : ScriptablePath
{
private static class Contents
{
public static readonly GUIContent snappingLabel = new GUIContent("Snapping", "Snap points using the snap settings");
}
private Editor m_CachedEditor = null;
// Returns true on Changed.
internal bool DoEditButtonChecked<U>(GUIContent icon, string label) where U : PathEditorTool<T>
{
const float kButtonWidth = 33;
const float kButtonHeight = 23;
const float k_SpaceBetweenLabelAndButton = 5;
var buttonStyle = new GUIStyle("EditModeSingleButton");
var rect = EditorGUILayout.GetControlRect(true, kButtonHeight, buttonStyle);
var buttonRect = new Rect(rect.xMin + EditorGUIUtility.labelWidth, rect.yMin, kButtonWidth, kButtonHeight);
var labelContent = new GUIContent(label);
var labelSize = GUI.skin.label.CalcSize(labelContent);
var labelRect = new Rect(
buttonRect.xMax + k_SpaceBetweenLabelAndButton,
rect.yMin + (rect.height - labelSize.y) * .5f,
labelSize.x,
rect.height);
bool hasChanged = false;
using (new EditorGUI.DisabledGroupScope(!EditorToolManager.IsAvailable<U>()))
{
using (var check = new EditorGUI.ChangeCheckScope())
{
var isActive = GUI.Toggle(buttonRect, EditorToolManager.IsActiveTool<U>(), icon, buttonStyle);
GUI.Label(labelRect, label);
if (check.changed)
{
if (isActive)
EditorTools.EditorTools.SetActiveTool<U>();
else
EditorTools.EditorTools.RestorePreviousTool();
hasChanged = true;
}
}
}
return hasChanged;
}
protected void DoEditButton<U>(GUIContent icon, string label) where U : PathEditorTool<T>
{
DoEditButtonChecked<U>(icon, label);
}
protected void DoPathInspector<U>() where U : PathEditorTool<T>
{
if (EditorToolManager.IsActiveTool<U>() && EditorToolManager.IsAvailable<U>())
{
var paths = EditorToolManager.GetEditorTool<U>().paths;
CreateCachedEditor(paths, null, ref m_CachedEditor);
if (m_CachedEditor == null) //Needed to avoid a nullref on exiting playmode
return;
using (var check = new EditorGUI.ChangeCheckScope())
{
m_CachedEditor.OnInspectorGUI();
if (check.changed)
EditorToolManager.GetEditorTool<U>().SetShapes();
}
}
}
protected void DoSnappingInspector<U>() where U : PathEditorTool<T>
{
if (EditorToolManager.IsActiveTool<U>() && EditorToolManager.IsAvailable<U>())
{
var tool = EditorToolManager.GetEditorTool<U>();
tool.enableSnapping = EditorGUILayout.Toggle(Contents.snappingLabel, tool.enableSnapping);
}
}
protected void DoOpenEndedInspector<U>(SerializedProperty isOpenEndedProperty) where U : PathEditorTool<T>
{
serializedObject.Update();
using (var check = new EditorGUI.ChangeCheckScope())
{
EditorGUILayout.PropertyField(isOpenEndedProperty);
if (check.changed)
{
if (EditorToolManager.IsActiveTool<U>() && EditorToolManager.IsAvailable<U>())
{
var paths = EditorToolManager.GetEditorTool<U>().paths;
foreach (var path in paths)
{
path.undoObject.RegisterUndo("Set Open Ended");
path.isOpenEnded = isOpenEndedProperty.boolValue;
}
}
}
}
serializedObject.ApplyModifiedProperties();
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 79c3c0b6ebc836f438b76a34f04dd076
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,494 @@
using System;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.EditorTools;
using UnityEditor.U2D.Path.GUIFramework;
using UnityObject = UnityEngine.Object;
namespace UnityEditor.U2D.Path
{
public static class PathEditorToolContents
{
internal static readonly GUIContent shapeToolIcon = IconContent("ShapeTool", "Start editing the Shape in the Scene View.");
internal static readonly GUIContent shapeToolPro = IconContent("ShapeToolPro", "Start editing the Shape in the Scene View.");
internal static GUIContent IconContent(string name, string tooltip = null)
{
return new GUIContent(AssetDatabase.LoadAssetAtPath<Texture2D>("Packages/com.unity.2d.path/Editor/Handles/" + name + ".png"), tooltip);
}
public static GUIContent icon
{
get
{
if (EditorGUIUtility.isProSkin)
return shapeToolPro;
return shapeToolIcon;
}
}
}
internal interface IDuringSceneGuiTool
{
void DuringSceneGui(SceneView sceneView);
bool IsAvailable();
}
[InitializeOnLoad]
internal class EditorToolManager
{
private static List<IDuringSceneGuiTool> m_Tools = new List<IDuringSceneGuiTool>();
static EditorToolManager()
{
SceneView.duringSceneGui += DuringSceneGui;
}
internal static void Add(IDuringSceneGuiTool tool)
{
if (!m_Tools.Contains(tool) && tool is EditorTool)
m_Tools.Add(tool);
}
internal static void Remove(IDuringSceneGuiTool tool)
{
if (m_Tools.Contains(tool))
m_Tools.Remove(tool);
}
internal static bool IsActiveTool<T>() where T : EditorTool
{
return EditorTools.EditorTools.activeToolType.Equals(typeof(T));
}
internal static bool IsAvailable<T>() where T : EditorTool
{
var tool = GetEditorTool<T>();
if (tool != null)
return tool.IsAvailable();
return false;
}
internal static T GetEditorTool<T>() where T : EditorTool
{
foreach(var tool in m_Tools)
{
if (tool.GetType().Equals(typeof(T)))
return tool as T;
}
return null;
}
private static void DuringSceneGui(SceneView sceneView)
{
foreach (var tool in m_Tools)
{
if (tool.IsAvailable() && EditorTools.EditorTools.IsActiveTool(tool as EditorTool))
tool.DuringSceneGui(sceneView);
}
}
}
public abstract class PathEditorTool<T> : EditorTool, IDuringSceneGuiTool where T : ScriptablePath
{
private Dictionary<UnityObject, T> m_Paths = new Dictionary<UnityObject, T>();
private IGUIState m_GUIState = new GUIState();
private Dictionary<UnityObject, PathEditor> m_PathEditors = new Dictionary<UnityObject, PathEditor>();
private Dictionary<UnityObject, SerializedObject> m_SerializedObjects = new Dictionary<UnityObject, SerializedObject>();
private MultipleEditablePathController m_Controller = new MultipleEditablePathController();
private PointRectSelector m_RectSelector = new PointRectSelector();
private bool m_IsActive = false;
internal T[] paths
{
get { return m_Paths.Values.ToArray(); }
}
public bool enableSnapping
{
get { return m_Controller.enableSnapping; }
set { m_Controller.enableSnapping = value; }
}
public override GUIContent toolbarIcon
{
get { return PathEditorToolContents.icon; }
}
public override bool IsAvailable()
{
return targets.Count() > 0;
}
public T GetPath(UnityObject targetObject)
{
var path = default(T);
m_Paths.TryGetValue(targetObject, out path);
return path;
}
public void SetPath(UnityObject target)
{
var path = GetPath(target);
path.localToWorldMatrix = Matrix4x4.identity;
var undoName = Undo.GetCurrentGroupName();
var serializedObject = GetSerializedObject(target);
serializedObject.UpdateIfRequiredOrScript();
SetShape(path, serializedObject);
Undo.SetCurrentGroupName(undoName);
}
private void RepaintInspectors()
{
var editorWindows = Resources.FindObjectsOfTypeAll<EditorWindow>();
foreach (var editorWindow in editorWindows)
{
if (editorWindow.titleContent.text == "Inspector")
editorWindow.Repaint();
}
}
private void OnEnable()
{
m_IsActive = false;
EditorToolManager.Add(this);
SetupRectSelector();
HandleActivation();
EditorTools.EditorTools.activeToolChanged += HandleActivation;
}
private void OnDestroy()
{
EditorToolManager.Remove(this);
EditorTools.EditorTools.activeToolChanged -= HandleActivation;
UnregisterCallbacks();
}
private void HandleActivation()
{
if (m_IsActive == false && EditorTools.EditorTools.IsActiveTool(this))
Activate();
else if (m_IsActive)
Deactivate();
}
private void Activate()
{
m_IsActive = true;
RegisterCallbacks();
InitializeCache();
OnActivate();
}
private void Deactivate()
{
OnDeactivate();
DestroyCache();
UnregisterCallbacks();
m_IsActive = false;
}
private void RegisterCallbacks()
{
UnregisterCallbacks();
Selection.selectionChanged += SelectionChanged;
EditorApplication.playModeStateChanged += PlayModeStateChanged;
Undo.undoRedoPerformed += UndoRedoPerformed;
}
private void UnregisterCallbacks()
{
Selection.selectionChanged -= SelectionChanged;
EditorApplication.playModeStateChanged -= PlayModeStateChanged;
Undo.undoRedoPerformed -= UndoRedoPerformed;
}
private void DestroyCache()
{
foreach (var pair in m_Paths)
{
var path = pair.Value;
if (path != null)
{
Undo.ClearUndo(path);
UnityObject.DestroyImmediate(path);
}
}
m_Paths.Clear();
m_Controller.ClearPaths();
m_PathEditors.Clear();
m_SerializedObjects.Clear();
}
private void UndoRedoPerformed()
{
ForEachTarget((target) =>
{
var path = GetPath(target);
if (!path.modified)
InitializePath(target);
});
}
private void SelectionChanged()
{
InitializeCache();
}
private void PlayModeStateChanged(PlayModeStateChange stateChange)
{
if (stateChange == PlayModeStateChange.EnteredEditMode)
EditorApplication.delayCall += () => { InitializeCache(); }; //HACK: At this point target is null. Let's wait to next frame to refresh.
}
private void SetupRectSelector()
{
m_RectSelector.onSelectionBegin = BeginSelection;
m_RectSelector.onSelectionChanged = UpdateSelection;
m_RectSelector.onSelectionEnd = EndSelection;
}
private void ForEachTarget(Action<UnityObject> action)
{
foreach(var target in targets)
{
if (target == null)
continue;
action(target);
}
}
private void InitializeCache()
{
m_Controller.ClearPaths();
ForEachTarget((target) =>
{
var path = GetOrCreatePath(target);
var pointCount = path.pointCount;
InitializePath(target);
if (pointCount != path.pointCount)
path.selection.Clear();
CreatePathEditor(target);
m_Controller.AddPath(path);
});
}
private void InitializePath(UnityObject target)
{
IShape shape = null;
ControlPoint[] controlPoints = null;
try
{
shape = GetShape(target);
controlPoints = shape.ToControlPoints();
}
catch (Exception e)
{
Debug.LogError(e.Message);
}
var path = GetPath(target);
path.Clear();
if (shape != null && controlPoints != null)
{
path.localToWorldMatrix = Matrix4x4.identity;
path.shapeType = shape.type;
path.isOpenEnded = shape.isOpenEnded;
foreach (var controlPoint in controlPoints)
path.AddPoint(controlPoint);
}
Initialize(path, GetSerializedObject(target));
}
private T GetOrCreatePath(UnityObject targetObject)
{
var path = GetPath(targetObject);
if (path == null)
{
path = ScriptableObject.CreateInstance<T>();
path.owner = targetObject;
m_Paths[targetObject] = path;
}
return path;
}
private PathEditor GetPathEditor(UnityObject target)
{
PathEditor pathEditor;
m_PathEditors.TryGetValue(target, out pathEditor);
return pathEditor;
}
private void CreatePathEditor(UnityObject target)
{
var pathEditor = new PathEditor();
pathEditor.controller = m_Controller;
pathEditor.drawerOverride = GetCustomDrawer(target);
m_PathEditors[target] = pathEditor;
}
private SerializedObject GetSerializedObject(UnityObject target)
{
var serializedObject = default(SerializedObject);
if (!m_SerializedObjects.TryGetValue(target, out serializedObject))
{
serializedObject = new SerializedObject(target);
m_SerializedObjects[target] = serializedObject;
}
return serializedObject;
}
void IDuringSceneGuiTool.DuringSceneGui(SceneView sceneView)
{
if (m_GUIState.eventType == EventType.Layout)
m_Controller.ClearClosestPath();
m_RectSelector.OnGUI();
bool changed = false;
ForEachTarget((target) =>
{
var path = GetPath(target);
if (path != null)
{
path.localToWorldMatrix = GetLocalToWorldMatrix(target);
path.forward = GetForward(target);
path.up = GetUp(target);
path.right = GetRight(target);
m_Controller.editablePath = path;
using (var check = new EditorGUI.ChangeCheckScope())
{
var pathEditor = GetPathEditor(target);
pathEditor.linearTangentIsZero = GetLinearTangentIsZero(target);
pathEditor.OnGUI();
OnCustomGUI(path);
changed |= check.changed;
}
}
});
if (changed)
{
SetShapes();
RepaintInspectors();
}
}
private void BeginSelection(ISelector<Vector3> selector, bool isAdditive)
{
m_Controller.RegisterUndo("Selection");
if (isAdditive)
{
ForEachTarget((target) =>
{
var path = GetPath(target);
path.selection.BeginSelection();
});
}
else
{
UpdateSelection(selector);
}
}
private void UpdateSelection(ISelector<Vector3> selector)
{
var repaintInspectors = false;
ForEachTarget((target) =>
{
var path = GetPath(target);
repaintInspectors |= path.Select(selector);
});
if (repaintInspectors)
RepaintInspectors();
}
private void EndSelection(ISelector<Vector3> selector)
{
ForEachTarget((target) =>
{
var path = GetPath(target);
path.selection.EndSelection(true);
});
}
internal void SetShapes()
{
ForEachTarget((target) =>
{
SetPath(target);
});
}
private Transform GetTransform(UnityObject target)
{
return (target as Component).transform;
}
private Matrix4x4 GetLocalToWorldMatrix(UnityObject target)
{
return GetTransform(target).localToWorldMatrix;
}
private Vector3 GetForward(UnityObject target)
{
return GetTransform(target).forward;
}
private Vector3 GetUp(UnityObject target)
{
return GetTransform(target).up;
}
private Vector3 GetRight(UnityObject target)
{
return GetTransform(target).right;
}
protected abstract IShape GetShape(UnityObject target);
protected virtual void Initialize(T path, SerializedObject serializedObject) { }
protected abstract void SetShape(T path, SerializedObject serializedObject);
protected virtual void OnActivate() { }
protected virtual void OnDeactivate() { }
protected virtual void OnCustomGUI(T path) { }
protected virtual bool GetLinearTangentIsZero(UnityObject target) { return false; }
protected virtual IDrawer GetCustomDrawer(UnityObject target) { return null; }
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 320732be5a65ff84ea451c5bf9700876
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,108 @@
using System;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.EditorTools;
using UnityEditor.U2D.Path.GUIFramework;
using UnityObject = UnityEngine.Object;
namespace UnityEditor.U2D.Path
{
public static class PathEditorToolExtensions
{
public static void CycleTangentMode<T>(this PathEditorTool<T> pathEditorTool) where T : ScriptablePath
{
var first = true;
var mixed = false;
var tangentMode = TangentMode.Linear;
var targets = pathEditorTool.targets;
foreach(var target in targets)
{
var path = pathEditorTool.GetPath(target);
if (path.selection.Count == 0)
continue;
for (var i = 0; i < path.pointCount; ++i)
{
if (!path.selection.Contains(i))
continue;
var point = path.GetPoint(i);
if (first)
{
first = false;
tangentMode = point.tangentMode;
}
else if (point.tangentMode != tangentMode)
{
mixed = true;
break;
}
}
if (mixed)
break;
}
if (mixed)
tangentMode = TangentMode.Linear;
else
tangentMode = GetNextTangentMode(tangentMode);
foreach(var target in targets)
{
var path = pathEditorTool.GetPath(target);
if (path.selection.Count == 0)
continue;
path.undoObject.RegisterUndo("Cycle Tangent Mode");
for (var i = 0; i < path.pointCount; ++i)
{
if (!path.selection.Contains(i))
continue;
path.SetTangentMode(i, tangentMode);
}
pathEditorTool.SetPath(target);
}
}
public static void MirrorTangent<T>(this PathEditorTool<T> pathEditorTool) where T : ScriptablePath
{
var targets = pathEditorTool.targets;
foreach(var target in targets)
{
var path = pathEditorTool.GetPath(target);
if (path.selection.Count == 0)
continue;
path.undoObject.RegisterUndo("Mirror Tangents");
for (var i = 0; i < path.pointCount; ++i)
{
if (!path.selection.Contains(i))
continue;
path.MirrorTangent(i);
}
pathEditorTool.SetPath(target);
}
}
private static TangentMode GetNextTangentMode(TangentMode tangentMode)
{
return (TangentMode)((((int)tangentMode) + 1) % Enum.GetValues(typeof(TangentMode)).Length);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 94a1e3e609709aa4f9106a9aeea179f7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
using UnityEngine;
using UnityObject = UnityEngine.Object;
namespace UnityEditor.U2D.Path
{
public class ScriptableData<T> : ScriptableObject
{
[SerializeField]
private T m_Data;
public UnityObject owner { get; set; }
public int index { get; set; }
public T data
{
get { return m_Data; }
set { m_Data = value; }
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ae511f1b2818bc54f87b84a327b16f71
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,118 @@
using System;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.EditorTools;
using UnityObject = UnityEngine.Object;
namespace UnityEditor.U2D.Path
{
public class ScriptablePath : ScriptableObject, IEditablePath, IUndoObject
{
[SerializeField]
private EditablePath m_EditablePath = new EditablePath();
[SerializeField]
private bool m_Modified = false;
internal bool modified
{
get { return m_Modified; }
}
internal UnityObject owner { get; set; }
public ShapeType shapeType
{
get { return m_EditablePath.shapeType; }
set { m_EditablePath.shapeType = value; }
}
public IUndoObject undoObject
{
get { return this; }
set { }
}
public ISelection<int> selection
{
get { return m_EditablePath.selection; }
}
public Matrix4x4 localToWorldMatrix
{
get { return m_EditablePath.localToWorldMatrix; }
set { m_EditablePath.localToWorldMatrix = value; }
}
public Vector3 forward
{
get { return m_EditablePath.forward; }
set { m_EditablePath.forward = value; }
}
public Vector3 up
{
get { return m_EditablePath.up; }
set { m_EditablePath.up = value; }
}
public Vector3 right
{
get { return m_EditablePath.right; }
set { m_EditablePath.right = value; }
}
public bool isOpenEnded
{
get { return m_EditablePath.isOpenEnded; }
set { m_EditablePath.isOpenEnded = value; }
}
public int pointCount
{
get { return m_EditablePath.pointCount; }
}
public bool Select(ISelector<Vector3> selector)
{
return m_EditablePath.Select(selector);
}
public virtual void Clear()
{
m_EditablePath.Clear();
}
public virtual ControlPoint GetPoint(int index)
{
return m_EditablePath.GetPoint(index);
}
public virtual void SetPoint(int index, ControlPoint controlPoint)
{
m_EditablePath.SetPoint(index, controlPoint);
}
public virtual void AddPoint(ControlPoint controlPoint)
{
m_EditablePath.AddPoint(controlPoint);
}
public virtual void InsertPoint(int index, ControlPoint controlPoint)
{
m_EditablePath.InsertPoint(index, controlPoint);
}
public virtual void RemovePoint(int index)
{
m_EditablePath.RemovePoint(index);
}
void IUndoObject.RegisterUndo(string name)
{
Undo.RegisterCompleteObjectUndo(this, name);
m_Modified = true;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: c208d96210d896247a45095d5fa9bf09
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,233 @@
using System;
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
namespace UnityEditor.U2D.Path
{
[CanEditMultipleObjects]
[CustomEditor(typeof(ScriptablePath), true)]
public class ScriptablePathInspector : Editor
{
private static class Contents
{
public static readonly GUIContent linearIcon = IconContent("TangentLinear", "TangentLinearPro", "Linear");
public static readonly GUIContent continuousIcon = IconContent("TangentContinuous", "TangentContinuousPro", "Continuous");
public static readonly GUIContent brokenIcon = IconContent("TangentBroken", "TangentBrokenPro", "Broken");
public static readonly GUIContent positionLabel = new GUIContent("Position", "Position of the Control Point");
public static readonly GUIContent enableSnapLabel = new GUIContent("Snapping", "Snap points using the snap settings");
public static readonly GUIContent tangentModeLabel = new GUIContent("Tangent Mode");
public static readonly GUIContent pointLabel = new GUIContent("Point");
private static GUIContent IconContent(string name, string tooltip = null)
{
return new GUIContent(AssetDatabase.LoadAssetAtPath<Texture2D>("Packages/com.unity.2d.path/Editor/Handles/" + name + ".png"), tooltip);
}
private static GUIContent IconContent(string personal, string pro, string tooltip)
{
if (EditorGUIUtility.isProSkin)
return IconContent(pro, tooltip);
return IconContent(personal, tooltip);
}
}
private List<ScriptablePath> m_Paths = null;
private bool m_Dragged = false;
protected List<ScriptablePath> paths
{
get
{
if (m_Paths == null)
m_Paths = targets.Select( t => t as ScriptablePath).ToList();
return m_Paths;
}
}
public override void OnInspectorGUI()
{
DoTangentModeInspector();
DoPositionInspector();
}
protected void DoTangentModeInspector()
{
if (!IsAnyShapeType(ShapeType.Spline))
return;
EditorGUILayout.BeginHorizontal();
EditorGUILayout.PrefixLabel(Contents.tangentModeLabel);
using (new EditorGUI.DisabledGroupScope(!IsAnyPointSelected()))
{
if (DoToggle(GetToggleStateFromTangentMode(TangentMode.Linear), Contents.linearIcon))
SetMixedTangentMode(TangentMode.Linear);
if (DoToggle(GetToggleStateFromTangentMode(TangentMode.Continuous), Contents.continuousIcon))
SetMixedTangentMode(TangentMode.Continuous);
if (DoToggle(GetToggleStateFromTangentMode(TangentMode.Broken), Contents.brokenIcon))
SetMixedTangentMode(TangentMode.Broken);
}
EditorGUILayout.EndHorizontal();
}
protected void DoPositionInspector()
{
var showMixedValue = EditorGUI.showMixedValue;
var wideMode = EditorGUIUtility.wideMode;
var position = Vector3.zero;
var isMixed = GetMixedPosition(out position);
EditorGUI.showMixedValue = isMixed;
EditorGUIUtility.wideMode = true;
using (new EditorGUI.DisabledGroupScope(!IsAnyPointSelected()))
{
if (GUIUtility.hotControl == 0)
m_Dragged = false;
EditorGUI.BeginChangeCheck();
var delta = EditorGUILayout.Vector2Field(Contents.positionLabel, position) - (Vector2)position;
if (EditorGUI.EndChangeCheck())
{
if (m_Dragged == false)
{
foreach(var path in paths)
path.undoObject.RegisterUndo("Point Position");
m_Dragged = true;
}
SetMixedDeltaPosition(delta);
}
}
EditorGUI.showMixedValue = showMixedValue;
EditorGUIUtility.wideMode = wideMode;
}
private bool DoToggle(bool value, GUIContent icon)
{
const float kButtonWidth = 33f;
const float kButtonHeight = 23f;
var buttonStyle = new GUIStyle("EditModeSingleButton");
var changed = false;
using (var check = new EditorGUI.ChangeCheckScope())
{
value = GUILayout.Toggle(value, icon, buttonStyle, GUILayout.Width(kButtonWidth), GUILayout.Height(kButtonHeight));
changed = check.changed;
}
return value && changed;
}
private bool GetToggleStateFromTangentMode(TangentMode mode)
{
foreach(var path in paths)
{
var selection = path.selection;
foreach (var index in selection.elements)
if (path.GetPoint(index).tangentMode != mode)
return false;
}
return true;
}
private void SetMixedTangentMode(TangentMode tangentMode)
{
foreach(var path in paths)
{
path.undoObject.RegisterUndo("Tangent Mode");
foreach (var index in path.selection.elements)
path.SetTangentMode(index, tangentMode);
}
SceneView.RepaintAll();
}
private bool GetMixedPosition(out Vector3 position)
{
var first = true;
position = Vector3.zero;
foreach(var path in paths)
{
var selection = path.selection;
var matrix = path.localToWorldMatrix;
path.localToWorldMatrix = Matrix4x4.identity;
foreach (var index in selection.elements)
{
var controlPoint = path.GetPoint(index);
if (first)
{
position = controlPoint.position;
first = false;
}
else if (position != controlPoint.position)
{
return true;
}
}
path.localToWorldMatrix = matrix;
}
return false;
}
private void SetMixedDeltaPosition(Vector3 delta)
{
foreach(var path in paths)
{
var selection = path.selection;
var matrix = path.localToWorldMatrix;
path.localToWorldMatrix = Matrix4x4.identity;
foreach (var index in selection.elements)
{
var controlPoint = path.GetPoint(index);
controlPoint.position += delta;
path.SetPoint(index, controlPoint);
}
path.localToWorldMatrix = matrix;
}
}
private bool IsAnyShapeType(ShapeType shapeType)
{
foreach(var path in paths)
if (path.shapeType == shapeType)
return true;
return false;
}
protected bool IsAnyPointSelected()
{
foreach(var path in paths)
if (path.selection.Count > 0)
return true;
return false;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 6c5abda88d831f347a177bb63ff287b0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ef3a2c79978afd74ebaa435c12615c7c
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: cbe8f28ead47977409438cd59447d211
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 390 B

View file

@ -0,0 +1,112 @@
fileFormatVersion: 2
guid: eaa90b7bb801a1144b58c4926d95ad6a
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 9
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: iPhone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 357346b6d26030047a52ccb34ccb2886
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 444 B

View file

@ -0,0 +1,112 @@
fileFormatVersion: 2
guid: 514bcbaba91a4704599b5b170200682a
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 9
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: iPhone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 36cdba5fd2caa914892902a32774cdb8
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 507 B

View file

@ -0,0 +1,112 @@
fileFormatVersion: 2
guid: 1d3a30b709ec7b94ab8997b21eae5849
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 9
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: iPhone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 52d8d99422b17e64bb6ba5d2dadd70b8
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 474 B

View file

@ -0,0 +1,112 @@
fileFormatVersion: 2
guid: 9becc394fda44db46ad1fbff4a9cfdcb
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 9
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: iPhone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 91172ab64c40f144eb1defedd68e7218
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 403 B

View file

@ -0,0 +1,123 @@
fileFormatVersion: 2
guid: 0ece669b27aea44439cadb539418c627
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 9
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 0
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 2
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: Standalone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: iPhone
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
- serializedVersion: 2
buildTarget: tvOS
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 0
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: eff7069ffebc20e47b1b8409488587d1
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 B

View file

@ -0,0 +1,91 @@
fileFormatVersion: 2
guid: 0601759dc49769849996e4dae10a2204
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 10
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 1
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 7d56a60e2671206419ca3f0fd4afcc25
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 B

View file

@ -0,0 +1,91 @@
fileFormatVersion: 2
guid: 20ac412813dce2241a95fcf2dad05436
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 10
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 1
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 3ec3e0affb347e74d962381e838269f3
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 B

View file

@ -0,0 +1,91 @@
fileFormatVersion: 2
guid: b370d25fdf6f8914287e27c0c3dede6a
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 10
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 1
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 11161a62eb582114f995922f83b5d391
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 366 B

View file

@ -0,0 +1,91 @@
fileFormatVersion: 2
guid: 3f0215e89d05b544d907d3a7d34fab63
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 10
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 1
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: cbd45795318e3a543936d9b2e6e50606
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 322 B

View file

@ -0,0 +1,91 @@
fileFormatVersion: 2
guid: 229e750703f3e824ca71ddd16a5e36be
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 10
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 1
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 89b1ca0030b965c4f82777d37f1e12bc
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 325 B

View file

@ -0,0 +1,91 @@
fileFormatVersion: 2
guid: 8d4a2ded892e27742bb6d4d263639dff
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 10
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 1
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 65e01b4dd520e304083281f74ebff12e
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 351 B

View file

@ -0,0 +1,91 @@
fileFormatVersion: 2
guid: a728d9332cba5f448a36350199dc573b
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 10
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 1
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 62f46dae558c8a74da5ce1603e2ef2a8
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

After

Width:  |  Height:  |  Size: 381 B

View file

@ -0,0 +1,91 @@
fileFormatVersion: 2
guid: cafc16189f045f445bad6f5eb9e13541
TextureImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 10
mipmaps:
mipMapMode: 0
enableMipMap: 0
sRGBTexture: 1
linearTexture: 0
fadeOut: 0
borderMipMap: 0
mipMapsPreserveCoverage: 0
alphaTestReferenceValue: 0.5
mipMapFadeDistanceStart: 1
mipMapFadeDistanceEnd: 3
bumpmap:
convertToNormalMap: 0
externalNormalMap: 0
heightScale: 0.25
normalMapFilter: 0
isReadable: 0
streamingMipmaps: 0
streamingMipmapsPriority: 0
grayScaleToAlpha: 0
generateCubemap: 6
cubemapConvolution: 0
seamlessCubemap: 0
textureFormat: 1
maxTextureSize: 2048
textureSettings:
serializedVersion: 2
filterMode: -1
aniso: -1
mipBias: -100
wrapU: 1
wrapV: 1
wrapW: 1
nPOTScale: 0
lightmap: 0
compressionQuality: 50
spriteMode: 1
spriteExtrude: 1
spriteMeshType: 1
alignment: 0
spritePivot: {x: 0.5, y: 0.5}
spritePixelsToUnits: 100
spriteBorder: {x: 0, y: 0, z: 0, w: 0}
spriteGenerateFallbackPhysicsShape: 1
alphaUsage: 1
alphaIsTransparency: 1
spriteTessellationDetail: -1
textureType: 8
textureShape: 1
singleChannelComponent: 0
maxTextureSizeSet: 0
compressionQualitySet: 0
textureFormatSet: 0
platformSettings:
- serializedVersion: 3
buildTarget: DefaultTexturePlatform
maxTextureSize: 2048
resizeAlgorithm: 0
textureFormat: -1
textureCompression: 1
compressionQuality: 50
crunchedCompression: 0
allowsAlphaSplitting: 0
overridden: 0
androidETC2FallbackOverride: 0
forceMaximumCompressionQuality_BC6H_BC7: 1
spriteSheet:
serializedVersion: 2
sprites: []
outline: []
physicsShape: []
bones: []
spriteID: 8426c25057e87a249bbaaea6173778ab
internalID: 0
vertices: []
indices:
edges: []
weights: []
secondaryTextures: []
spritePackingTag:
pSDRemoveMatte: 0
pSDShowRemoveMatteOption: 0
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 66ae7362289f12c4d8da3f9f04cf4984
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,48 @@
using System;
using UnityEngine;
using UnityEditor.U2D.Path.GUIFramework;
namespace UnityEditor.U2D.Path
{
public class CreatePointAction : ClickAction
{
private Control m_PointControl;
public Func<IGUIState, Vector2, Vector3> guiToWorld;
public Action<int, Vector3> onCreatePoint;
public CreatePointAction(Control pointControl, Control edgeControl) : base(edgeControl, 0, false)
{
m_PointControl = pointControl;
}
protected override void OnTrigger(IGUIState guiState)
{
base.OnTrigger(guiState);
var index = hoveredControl.layoutData.index;
var position = GetMousePositionWorld(guiState);
if (onCreatePoint != null)
onCreatePoint(index, position);
guiState.nearestControl = m_PointControl.ID;
var data = m_PointControl.layoutData;
data.index = index + 1;
data.position = position;
data.distance = 0f;
m_PointControl.layoutData = data;
guiState.changed = true;
}
private Vector3 GetMousePositionWorld(IGUIState guiState)
{
if (guiToWorld != null)
return guiToWorld(guiState, guiState.mousePosition);
return guiState.GUIToWorld(guiState.mousePosition, hoveredControl.layoutData.forward, hoveredControl.layoutData.position);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: ed2cb354a5d670f4881c41d7d2fc6a45
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,118 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;
using UnityEditor.U2D.Path.GUIFramework;
namespace UnityEditor.U2D.Path
{
public class Drawer : IDrawer
{
internal class Styles
{
public readonly GUIStyle pointNormalStyle;
public readonly GUIStyle pointHoveredStyle;
public readonly GUIStyle pointSelectedStyle;
public readonly GUIStyle pointPreviewStyle;
public readonly GUIStyle tangentNormalStyle;
public readonly GUIStyle tangentHoveredStyle;
public Styles()
{
var pointNormal = AssetDatabase.LoadAssetAtPath<Texture2D>("Packages/com.unity.2d.path/Editor/Handles/Path/pointNormal.png");
var pointHovered = AssetDatabase.LoadAssetAtPath<Texture2D>("Packages/com.unity.2d.path/Editor/Handles/Path/pointHovered.png");
var pointSelected = AssetDatabase.LoadAssetAtPath<Texture2D>("Packages/com.unity.2d.path/Editor/Handles/Path/pointSelected.png");
var pointPreview = AssetDatabase.LoadAssetAtPath<Texture2D>("Packages/com.unity.2d.path/Editor/Handles/Path/pointPreview.png");
var tangentNormal = AssetDatabase.LoadAssetAtPath<Texture2D>("Packages/com.unity.2d.path/Editor/Handles/Path/tangentNormal.png");
pointNormalStyle = CreateStyle(AssetDatabase.LoadAssetAtPath<Texture2D>("Packages/com.unity.2d.path/Editor/Handles/Path/pointNormal.png"), Vector2.one * 12f);
pointHoveredStyle = CreateStyle(AssetDatabase.LoadAssetAtPath<Texture2D>("Packages/com.unity.2d.path/Editor/Handles/Path/pointHovered.png"), Vector2.one * 12f);
pointSelectedStyle = CreateStyle(AssetDatabase.LoadAssetAtPath<Texture2D>("Packages/com.unity.2d.path/Editor/Handles/Path/pointSelected.png"), Vector2.one * 12f);
pointPreviewStyle = CreateStyle(AssetDatabase.LoadAssetAtPath<Texture2D>("Packages/com.unity.2d.path/Editor/Handles/Path/pointPreview.png"), Vector2.one * 12f);
tangentNormalStyle = CreateStyle(AssetDatabase.LoadAssetAtPath<Texture2D>("Packages/com.unity.2d.path/Editor/Handles/Path/tangentNormal.png"), Vector2.one * 8f);
tangentHoveredStyle = CreateStyle(AssetDatabase.LoadAssetAtPath<Texture2D>("Packages/com.unity.2d.path/Editor/Handles/Path/pointHovered.png"), Vector2.one * 10f);
}
private GUIStyle CreateStyle(Texture2D texture, Vector2 size)
{
var guiStyle = new GUIStyle();
guiStyle.normal.background = texture;
guiStyle.fixedWidth = size.x;
guiStyle.fixedHeight = size.y;
return guiStyle;
}
}
private IGUIState m_GUIState = new GUIState();
private Styles m_Styles;
private Styles styles
{
get
{
if (m_Styles == null)
m_Styles = new Styles();
return m_Styles;
}
}
public void DrawCreatePointPreview(Vector3 position)
{
DrawGUIStyleCap(0, position, Quaternion.identity, m_GUIState.GetHandleSize(position), styles.pointPreviewStyle);
}
public void DrawPoint(Vector3 position)
{
DrawGUIStyleCap(0, position, Quaternion.identity, m_GUIState.GetHandleSize(position), styles.pointNormalStyle);
}
public void DrawPointHovered(Vector3 position)
{
DrawGUIStyleCap(0, position, Quaternion.identity, m_GUIState.GetHandleSize(position), styles.pointHoveredStyle);
}
public void DrawPointSelected(Vector3 position)
{
DrawGUIStyleCap(0, position, Quaternion.identity, m_GUIState.GetHandleSize(position), styles.pointSelectedStyle);
}
public void DrawLine(Vector3 p1, Vector3 p2, float width, Color color)
{
Handles.color = color;
Handles.DrawAAPolyLine(width, new Vector3[] { p1, p2 });
}
public void DrawBezier(Vector3 p1, Vector3 p2, Vector3 p3, Vector3 p4, float width, Color color)
{
Handles.color = color;
Handles.DrawBezier(p1, p4, p2, p3, color, null, width);
}
public void DrawTangent(Vector3 position, Vector3 tangent)
{
DrawLine(position, tangent, 3f, Color.yellow);
DrawGUIStyleCap(0, tangent, Quaternion.identity, m_GUIState.GetHandleSize(tangent), styles.tangentNormalStyle);
}
private void DrawGUIStyleCap(int controlID, Vector3 position, Quaternion rotation, float size, GUIStyle guiStyle)
{
if (Camera.current && Vector3.Dot(position - Camera.current.transform.position, Camera.current.transform.forward) < 0f)
return;
Handles.BeginGUI();
guiStyle.Draw(GetGUIStyleRect(guiStyle, position), GUIContent.none, controlID);
Handles.EndGUI();
}
private Rect GetGUIStyleRect(GUIStyle style, Vector3 position)
{
Vector2 vector = HandleUtility.WorldToGUIPoint(position);
float fixedWidth = style.fixedWidth;
float fixedHeight = style.fixedHeight;
return new Rect(vector.x - fixedWidth / 2f, vector.y - fixedHeight / 2f, fixedWidth, fixedHeight);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1b31573f9ab124c47b5e877a88088db1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 33e44f9d4edce8344a708573c37ebe4a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,52 @@
using System;
using UnityEngine;
namespace UnityEditor.U2D.Path.GUIFramework
{
public class ClickAction : HoveredControlAction
{
private int m_Button;
private bool m_UseEvent;
public int clickCount = 1;
public Action<IGUIState, Control> onClick;
private int m_ClickCounter = 0;
public ClickAction(Control control, int button, bool useEvent = true) : base(control)
{
m_Button = button;
m_UseEvent = useEvent;
}
protected override bool GetTriggerContidtion(IGUIState guiState)
{
if (guiState.mouseButton == m_Button && guiState.eventType == EventType.MouseDown)
{
if (guiState.clickCount == 1)
m_ClickCounter = 0;
++m_ClickCounter;
if (m_ClickCounter == clickCount)
return true;
}
return false;
}
protected override void OnTrigger(IGUIState guiState)
{
base.OnTrigger(guiState);
if (onClick != null)
onClick(guiState, hoveredControl);
if (m_UseEvent)
guiState.UseEvent();
}
protected override bool GetFinishContidtion(IGUIState guiState)
{
return true;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 175bf12750eca384fa2ece4cd8f67cd4
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,46 @@
using System;
using UnityEngine;
namespace UnityEditor.U2D.Path.GUIFramework
{
public class CommandAction : GUIAction
{
private string m_CommandName;
public Action<IGUIState> onCommand;
public CommandAction(string commandName)
{
m_CommandName = commandName;
}
protected override bool GetTriggerContidtion(IGUIState guiState)
{
if (guiState.eventType == EventType.ValidateCommand && guiState.commandName == m_CommandName)
{
guiState.UseEvent();
return true;
}
return false;
}
protected override bool GetFinishContidtion(IGUIState guiState)
{
if (guiState.eventType == EventType.ExecuteCommand && guiState.commandName == m_CommandName)
{
guiState.UseEvent();
return true;
}
return false;
}
protected override void OnFinish(IGUIState guiState)
{
if (onCommand != null)
onCommand(guiState);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d8d8b17ba93dfad489ee2c2ff2546fb0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,152 @@
using System;
using UnityEngine;
namespace UnityEditor.U2D.Path.GUIFramework
{
public abstract class Control
{
private string m_Name;
private int m_NameHashCode;
private int m_ID;
private LayoutData m_LayoutData;
private int m_ActionID = -1;
private LayoutData m_HotLayoutData;
public string name
{
get { return m_Name; }
}
public int ID
{
get { return m_ID; }
}
public int actionID
{
get { return m_ActionID; }
}
public LayoutData layoutData
{
get { return m_LayoutData; }
set { m_LayoutData = value; }
}
public LayoutData hotLayoutData
{
get { return m_HotLayoutData; }
}
public Control(string name)
{
m_Name = name;
m_NameHashCode = name.GetHashCode();
}
public void GetControl(IGUIState guiState)
{
m_ID = guiState.GetControlID(m_NameHashCode, FocusType.Passive);
}
internal void SetActionID(int actionID)
{
m_ActionID = actionID;
m_HotLayoutData = m_LayoutData;
}
public void BeginLayout(IGUIState guiState)
{
Debug.Assert(guiState.eventType == EventType.Layout);
m_LayoutData = OnBeginLayout(LayoutData.zero, guiState);
}
public void Layout(IGUIState guiState)
{
Debug.Assert(guiState.eventType == EventType.Layout);
for (var i = 0; i < GetCount(); ++i)
{
if (guiState.hotControl == actionID && hotLayoutData.index == i)
continue;
var layoutData = new LayoutData()
{
index = i,
position = GetPosition(guiState, i),
distance = GetDistance(guiState, i),
forward = GetForward(guiState, i),
up = GetUp(guiState, i),
right = GetRight(guiState, i),
userData = GetUserData(guiState, i)
};
m_LayoutData = LayoutData.Nearest(m_LayoutData, layoutData);
}
}
public void EndLayout(IGUIState guiState)
{
Debug.Assert(guiState.eventType == EventType.Layout);
OnEndLayout(guiState);
}
public void Repaint(IGUIState guiState)
{
for (var i = 0; i < GetCount(); ++i)
OnRepaint(guiState, i);
}
protected virtual LayoutData OnBeginLayout(LayoutData data, IGUIState guiState)
{
return data;
}
protected virtual void OnEndLayout(IGUIState guiState)
{
}
protected virtual void OnRepaint(IGUIState guiState, int index)
{
}
protected virtual int GetCount()
{
return 1;
}
protected virtual Vector3 GetPosition(IGUIState guiState, int index)
{
return Vector3.zero;
}
protected virtual Vector3 GetForward(IGUIState guiState, int index)
{
return Vector3.forward;
}
protected virtual Vector3 GetUp(IGUIState guiState, int index)
{
return Vector3.up;
}
protected virtual Vector3 GetRight(IGUIState guiState, int index)
{
return Vector3.right;
}
protected virtual float GetDistance(IGUIState guiState, int index)
{
return layoutData.distance;
}
protected virtual object GetUserData(IGUIState guiState, int index)
{
return null;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 1ab9c1eea0b4cc74bbee507825f10d5a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,20 @@
using System;
using UnityEngine;
namespace UnityEditor.U2D.Path.GUIFramework
{
public abstract class DefaultControl : Control
{
public static readonly float kPickDistance = 5f;
public DefaultControl(string name) : base(name)
{
}
protected override LayoutData OnBeginLayout(LayoutData data, IGUIState guiState)
{
data.distance = kPickDistance;
return data;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4dc9a9d2bfd656d4cb3ccb675fe0a426
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,112 @@
using System;
using UnityEngine;
namespace UnityEditor.U2D.Path.GUIFramework
{
public abstract class GUIAction
{
private int m_ID = -1;
public Func<IGUIState, GUIAction, bool> enable;
public Func<IGUIState, GUIAction, bool> enableRepaint;
public Func<IGUIState, GUIAction, bool> repaintOnMouseMove;
public Action<IGUIState, GUIAction> onPreRepaint;
public Action<IGUIState, GUIAction> onRepaint;
public int ID
{
get { return m_ID; }
}
public void OnGUI(IGUIState guiState)
{
m_ID = guiState.GetControlID(GetType().GetHashCode(), FocusType.Passive);
if (guiState.hotControl == 0 && IsEnabled(guiState) && CanTrigger(guiState) && GetTriggerContidtion(guiState))
{
guiState.hotControl = ID;
OnTrigger(guiState);
}
if (guiState.hotControl == ID)
{
if (GetFinishContidtion(guiState))
{
OnFinish(guiState);
guiState.hotControl = 0;
}
else
{
OnPerform(guiState);
}
}
if (guiState.eventType == EventType.Repaint && IsRepaintEnabled(guiState))
Repaint(guiState);
}
public bool IsEnabled(IGUIState guiState)
{
if (enable != null)
return enable(guiState, this);
return true;
}
public bool IsRepaintEnabled(IGUIState guiState)
{
if (!IsEnabled(guiState))
return false;
if (enableRepaint != null)
return enableRepaint(guiState, this);
return true;
}
public void PreRepaint(IGUIState guiState)
{
Debug.Assert(guiState.eventType == EventType.Repaint);
if (IsEnabled(guiState) && onPreRepaint != null)
onPreRepaint(guiState, this);
}
private void Repaint(IGUIState guiState)
{
Debug.Assert(guiState.eventType == EventType.Repaint);
if (onRepaint != null)
onRepaint(guiState, this);
}
internal bool IsRepaintOnMouseMoveEnabled(IGUIState guiState)
{
if (!IsEnabled(guiState) || !IsRepaintEnabled(guiState))
return false;
if (repaintOnMouseMove != null)
return repaintOnMouseMove(guiState, this);
return false;
}
protected abstract bool GetFinishContidtion(IGUIState guiState);
protected abstract bool GetTriggerContidtion(IGUIState guiState);
protected virtual bool CanTrigger(IGUIState guiState) { return true; }
protected virtual void OnTrigger(IGUIState guiState)
{
}
protected virtual void OnPerform(IGUIState guiState)
{
}
protected virtual void OnFinish(IGUIState guiState)
{
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2f11e220b90636b42bf596fb50ccdb6a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,156 @@
using UnityEngine;
using UnityEditor;
namespace UnityEditor.U2D.Path.GUIFramework
{
public class GUIState : IGUIState
{
private Handles.CapFunction nullCap = (int c, Vector3 p , Quaternion r, float s, EventType ev) => {};
public Vector2 mousePosition
{
get { return Event.current.mousePosition; }
}
public int mouseButton
{
get { return Event.current.button; }
}
public int clickCount
{
get { return Event.current.clickCount; }
set { Event.current.clickCount = Mathf.Max(0, value); }
}
public bool isShiftDown
{
get { return Event.current.shift; }
}
public bool isAltDown
{
get { return Event.current.alt; }
}
public bool isActionKeyDown
{
get { return EditorGUI.actionKey; }
}
public KeyCode keyCode
{
get { return Event.current.keyCode; }
}
public EventType eventType
{
get { return Event.current.type; }
}
public string commandName
{
get { return Event.current.commandName; }
}
public int nearestControl
{
get { return HandleUtility.nearestControl; }
set { HandleUtility.nearestControl = value; }
}
public int hotControl
{
get { return GUIUtility.hotControl; }
set { GUIUtility.hotControl = value; }
}
public bool changed
{
get { return GUI.changed; }
set { GUI.changed = value; }
}
public int GetControlID(int hint, FocusType focusType)
{
return GUIUtility.GetControlID(hint, focusType);
}
public void AddControl(int controlID, float distance)
{
HandleUtility.AddControl(controlID, distance);
}
public bool Slider(int id, SliderData sliderData, out Vector3 newPosition)
{
if (mouseButton == 0 && eventType == EventType.MouseDown)
{
hotControl = 0;
nearestControl = id;
}
EditorGUI.BeginChangeCheck();
newPosition = Handles.Slider2D(id, sliderData.position, sliderData.forward, sliderData.right, sliderData.up, 1f, nullCap, Vector2.zero);
return EditorGUI.EndChangeCheck();
}
public void UseEvent()
{
Event.current.Use();
}
public void Repaint()
{
HandleUtility.Repaint();
}
public bool HasCurrentCamera()
{
return Camera.current != null;
}
public float GetHandleSize(Vector3 position)
{
var scale = HasCurrentCamera() ? 0.01f : 0.05f;
return HandleUtility.GetHandleSize(position) * scale;
}
public float DistanceToSegment(Vector3 p1, Vector3 p2)
{
p1 = HandleUtility.WorldToGUIPoint(p1);
p2 = HandleUtility.WorldToGUIPoint(p2);
return HandleUtility.DistancePointToLineSegment(Event.current.mousePosition, p1, p2);
}
public float DistanceToCircle(Vector3 center, float radius)
{
return HandleUtility.DistanceToCircle(center, radius);
}
public Vector3 GUIToWorld(Vector2 guiPosition, Vector3 planeNormal, Vector3 planePos)
{
Vector3 worldPos = Handles.inverseMatrix.MultiplyPoint(guiPosition);
if (Camera.current)
{
Ray ray = HandleUtility.GUIPointToWorldRay(guiPosition);
planeNormal = Handles.matrix.MultiplyVector(planeNormal);
planePos = Handles.matrix.MultiplyPoint(planePos);
Plane plane = new Plane(planeNormal, planePos);
float distance = 0f;
if (plane.Raycast(ray, out distance))
{
worldPos = Handles.inverseMatrix.MultiplyPoint(ray.GetPoint(distance));
}
}
return worldPos;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a6ffe588dbbb4714695514536c29df95
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,124 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.U2D.Path.GUIFramework
{
public class GUISystem
{
private readonly int kControlIDCheckHashCode = "ControlIDCheckHashCode".GetHashCode();
private List<Control> m_Controls = new List<Control>();
private List<GUIAction> m_Actions = new List<GUIAction>();
private IGUIState m_GUIState;
private int m_PrevNearestControl = -1;
private LayoutData m_PrevNearestLayoutData = LayoutData.zero;
private int m_ControlIDCheck = -1;
public GUISystem(IGUIState guiState)
{
m_GUIState = guiState;
}
public void AddControl(Control control)
{
if (control == null)
throw new NullReferenceException("Control is null");
m_Controls.Add(control);
}
public void RemoveControl(Control control)
{
m_Controls.Remove(control);
}
public void AddAction(GUIAction action)
{
if (action == null)
throw new NullReferenceException("Action is null");
m_Actions.Add(action);
}
public void RemoveAction(GUIAction action)
{
m_Actions.Remove(action);
}
public void OnGUI()
{
var controlIDCheck = m_GUIState.GetControlID(kControlIDCheckHashCode, FocusType.Passive);
if (m_GUIState.eventType == EventType.Layout)
m_ControlIDCheck = controlIDCheck;
else if (m_GUIState.eventType != EventType.Used && m_ControlIDCheck != controlIDCheck)
Debug.LogWarning("GetControlID at event " + m_GUIState.eventType + " returns a controlID different from the one in Layout event");
var nearestLayoutData = LayoutData.zero;
foreach (var control in m_Controls)
control.GetControl(m_GUIState);
if (m_GUIState.eventType == EventType.Layout)
{
foreach (var control in m_Controls)
control.BeginLayout(m_GUIState);
foreach (var control in m_Controls)
{
control.Layout(m_GUIState);
nearestLayoutData = LayoutData.Nearest(nearestLayoutData, control.layoutData);
}
foreach (var control in m_Controls)
m_GUIState.AddControl(control.ID, control.layoutData.distance);
foreach (var control in m_Controls)
control.EndLayout(m_GUIState);
if (m_PrevNearestControl == m_GUIState.nearestControl)
{
if (nearestLayoutData.index != m_PrevNearestLayoutData.index)
m_GUIState.Repaint();
}
else
{
m_PrevNearestControl = m_GUIState.nearestControl;
m_GUIState.Repaint();
}
m_PrevNearestLayoutData = nearestLayoutData;
}
if (m_GUIState.eventType == EventType.Repaint)
{
foreach (var action in m_Actions)
if (action.IsRepaintEnabled(m_GUIState))
action.PreRepaint(m_GUIState);
foreach (var control in m_Controls)
control.Repaint(m_GUIState);
}
var repaintOnMouseMove = false;
foreach (var action in m_Actions)
{
if (IsMouseMoveEvent())
repaintOnMouseMove |= action.IsRepaintOnMouseMoveEnabled(m_GUIState);
action.OnGUI(m_GUIState);
}
if (repaintOnMouseMove)
m_GUIState.Repaint();
}
private bool IsMouseMoveEvent()
{
return m_GUIState.eventType == EventType.MouseMove || m_GUIState.eventType == EventType.MouseDrag;
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: be957506ccdeb4a4789fd53667da3649
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,99 @@
using System;
using UnityEngine;
namespace UnityEditor.U2D.Path.GUIFramework
{
public class GenericControl : Control
{
public Func<IGUIState, LayoutData> onBeginLayout;
public Action<IGUIState> onEndLayout;
public Action<IGUIState, Control, int> onRepaint;
public Func<int> count;
public Func<int, Vector3> position;
public Func<IGUIState, int, float> distance;
public Func<int, Vector3> forward;
public Func<int, Vector3> up;
public Func<int, Vector3> right;
public Func<int, object> userData;
public GenericControl(string name) : base(name)
{
}
protected override int GetCount()
{
if (count != null)
return count();
return base.GetCount();
}
protected override void OnEndLayout(IGUIState guiState)
{
if (onEndLayout != null)
onEndLayout(guiState);
}
protected override void OnRepaint(IGUIState guiState, int index)
{
if (onRepaint != null)
onRepaint(guiState, this, index);
}
protected override LayoutData OnBeginLayout(LayoutData data, IGUIState guiState)
{
if (onBeginLayout != null)
return onBeginLayout(guiState);
return data;
}
protected override Vector3 GetPosition(IGUIState guiState, int index)
{
if (position != null)
return position(index);
return base.GetPosition(guiState,index);
}
protected override float GetDistance(IGUIState guiState, int index)
{
if (distance != null)
return distance(guiState, index);
return base.GetDistance(guiState, index);
}
protected override Vector3 GetForward(IGUIState guiState, int index)
{
if (forward != null)
return forward(index);
return base.GetForward(guiState,index);
}
protected override Vector3 GetUp(IGUIState guiState, int index)
{
if (up != null)
return up(index);
return base.GetUp(guiState,index);
}
protected override Vector3 GetRight(IGUIState guiState, int index)
{
if (right != null)
return right(index);
return base.GetRight(guiState,index);
}
protected override object GetUserData(IGUIState guiState, int index)
{
if (userData != null)
return userData(index);
return base.GetUserData(guiState,index);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 42c4e70b47496ce448cebce5780a4a58
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,58 @@
using System;
using UnityEngine;
namespace UnityEditor.U2D.Path.GUIFramework
{
public class GenericDefaultControl : DefaultControl
{
public Func<IGUIState, Vector3> position;
public Func<IGUIState, Vector3> forward;
public Func<IGUIState, Vector3> up;
public Func<IGUIState, Vector3> right;
public Func<IGUIState, object> userData;
public GenericDefaultControl(string name) : base(name)
{
}
protected override Vector3 GetPosition(IGUIState guiState, int index)
{
if (position != null)
return position(guiState);
return base.GetPosition(guiState, index);
}
protected override Vector3 GetForward(IGUIState guiState, int index)
{
if (forward != null)
return forward(guiState);
return base.GetForward(guiState, index);
}
protected override Vector3 GetUp(IGUIState guiState, int index)
{
if (up != null)
return up(guiState);
return base.GetUp(guiState, index);
}
protected override Vector3 GetRight(IGUIState guiState, int index)
{
if (right != null)
return right(guiState);
return base.GetRight(guiState, index);
}
protected override object GetUserData(IGUIState guiState, int index)
{
if (userData != null)
return userData(guiState);
return base.GetUserData(guiState, index);
}
}
}

View file

@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 95695db3b2c152a4699bcb541136dc49
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

Some files were not shown because too many files have changed in this diff Show more