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,2 @@
using System.Runtime.CompilerServices;
[assembly: InternalsVisibleTo("Unity.2D.SpriteShape.Editor")]

View file

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

View file

@ -0,0 +1,267 @@

using Unity.Collections;
using Unity.Mathematics;
namespace UnityEngine.U2D
{
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 s * s * s * startPosition + 3.0f * s * s * t * startTangent + 3.0f * s * t * t * endTangent + t * t * t * endPosition;
}
internal static float GetSpritePixelWidth(Sprite sprite)
{
float4 meta = new float4(sprite.pixelsPerUnit, sprite.pivot.y / sprite.textureRect.height, sprite.rect.width, sprite.rect.height);
float4 border = new float4(sprite.border.x, sprite.border.y, sprite.border.z, sprite.border.w);
float rpunits = 1.0f / meta.x;
float2 whsize = new float2(meta.z, meta.w) * rpunits;
border = border * rpunits;
float stPixelU = border.x;
float enPixelU = whsize.x - border.z;
float pxlWidth = enPixelU - stPixelU;
return pxlWidth;
}
internal static float BezierLength(NativeArray<ShapeControlPoint> shapePoints, int splineDetail)
{
// Expand the Bezier.
int controlPointContour = shapePoints.Length - 1;
float spd = 0;
float fmax = (float)(splineDetail - 1);
for (int i = 0; i < controlPointContour; ++i)
{
int j = i + 1;
ShapeControlPoint cp = shapePoints[i];
ShapeControlPoint pp = shapePoints[j];
Vector3 p0 = cp.position;
Vector3 p1 = pp.position;
Vector3 sp = p0;
Vector3 rt = p0 + cp.rightTangent;
Vector3 lt = p1 + pp.leftTangent;
for (int n = 0; n < splineDetail; ++n)
{
float t = (float)n / fmax;
Vector3 bp = BezierPoint(rt, p0, p1, lt, t);
spd += math.distance(bp, sp);
sp = bp;
}
}
return spd;
}
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: e49f082c717ea884dae7404b70a08c56
timeCreated: 1505799796
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

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

View file

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

View file

@ -0,0 +1,107 @@
/*
** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
** Copyright (C) 2011 Silicon Graphics, Inc.
** All Rights Reserved.
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
** of the Software, and to permit persons to whom the Software is furnished to do so,
** subject to the following conditions:
**
** The above copyright notice including the dates of first publication and either this
** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be
** included in all copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC.
** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
** OR OTHER DEALINGS IN THE SOFTWARE.
**
** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not
** be used in advertising or otherwise to promote the sale, use or other dealings in
** this Software without prior written authorization from Silicon Graphics, Inc.
*/
/*
** Original Author: Eric Veach, July 1994.
** libtess2: Mikko Mononen, http://code.google.com/p/libtess2/.
** LibTessDotNet: Remi Gillig, https://github.com/speps/LibTessDotNet
*/
namespace Unity.SpriteShape.External
{
namespace LibTessDotNet
{
internal class Dict<TValue> where TValue : class
{
public class Node
{
internal TValue _key;
internal Node _prev, _next;
public TValue Key { get { return _key; } }
public Node Prev { get { return _prev; } }
public Node Next { get { return _next; } }
}
public delegate bool LessOrEqual(TValue lhs, TValue rhs);
private LessOrEqual _leq;
Node _head;
public Dict(LessOrEqual leq)
{
_leq = leq;
_head = new Node { _key = null };
_head._prev = _head;
_head._next = _head;
}
public Node Insert(TValue key)
{
return InsertBefore(_head, key);
}
public Node InsertBefore(Node node, TValue key)
{
do {
node = node._prev;
} while (node._key != null && !_leq(node._key, key));
var newNode = new Node { _key = key };
newNode._next = node._next;
node._next._prev = newNode;
newNode._prev = node;
node._next = newNode;
return newNode;
}
public Node Find(TValue key)
{
var node = _head;
do {
node = node._next;
} while (node._key != null && !_leq(key, node._key));
return node;
}
public Node Min()
{
return _head._next;
}
public void Remove(Node node)
{
node._next._prev = node._prev;
node._prev._next = node._next;
}
}
}
} // namespace Unity.VectorGraphics.External

View file

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

View file

@ -0,0 +1,301 @@
/*
** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
** Copyright (C) 2011 Silicon Graphics, Inc.
** All Rights Reserved.
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
** of the Software, and to permit persons to whom the Software is furnished to do so,
** subject to the following conditions:
**
** The above copyright notice including the dates of first publication and either this
** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be
** included in all copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC.
** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
** OR OTHER DEALINGS IN THE SOFTWARE.
**
** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not
** be used in advertising or otherwise to promote the sale, use or other dealings in
** this Software without prior written authorization from Silicon Graphics, Inc.
*/
/*
** Original Author: Eric Veach, July 1994.
** libtess2: Mikko Mononen, http://code.google.com/p/libtess2/.
** LibTessDotNet: Remi Gillig, https://github.com/speps/LibTessDotNet
*/
using System;
using System.Diagnostics;
namespace Unity.SpriteShape.External
{
using Real = System.Single;
namespace LibTessDotNet
{
internal static class Geom
{
public static bool IsWindingInside(WindingRule rule, int n)
{
switch (rule)
{
case WindingRule.EvenOdd:
return (n & 1) == 1;
case WindingRule.NonZero:
return n != 0;
case WindingRule.Positive:
return n > 0;
case WindingRule.Negative:
return n < 0;
case WindingRule.AbsGeqTwo:
return n >= 2 || n <= -2;
}
throw new Exception("Wrong winding rule");
}
public static bool VertCCW(MeshUtils.Vertex u, MeshUtils.Vertex v, MeshUtils.Vertex w)
{
return (u._s * (v._t - w._t) + v._s * (w._t - u._t) + w._s * (u._t - v._t)) >= 0.0f;
}
public static bool VertEq(MeshUtils.Vertex lhs, MeshUtils.Vertex rhs)
{
return lhs._s == rhs._s && lhs._t == rhs._t;
}
public static bool VertLeq(MeshUtils.Vertex lhs, MeshUtils.Vertex rhs)
{
return (lhs._s < rhs._s) || (lhs._s == rhs._s && lhs._t <= rhs._t);
}
/// <summary>
/// Given three vertices u,v,w such that VertLeq(u,v) && VertLeq(v,w),
/// evaluates the t-coord of the edge uw at the s-coord of the vertex v.
/// Returns v->t - (uw)(v->s), ie. the signed distance from uw to v.
/// If uw is vertical (and thus passes thru v), the result is zero.
///
/// The calculation is extremely accurate and stable, even when v
/// is very close to u or w. In particular if we set v->t = 0 and
/// let r be the negated result (this evaluates (uw)(v->s)), then
/// r is guaranteed to satisfy MIN(u->t,w->t) <= r <= MAX(u->t,w->t).
/// </summary>
public static Real EdgeEval(MeshUtils.Vertex u, MeshUtils.Vertex v, MeshUtils.Vertex w)
{
Debug.Assert(VertLeq(u, v) && VertLeq(v, w));
var gapL = v._s - u._s;
var gapR = w._s - v._s;
if (gapL + gapR > 0.0f)
{
if (gapL < gapR)
{
return (v._t - u._t) + (u._t - w._t) * (gapL / (gapL + gapR));
}
else
{
return (v._t - w._t) + (w._t - u._t) * (gapR / (gapL + gapR));
}
}
/* vertical line */
return 0;
}
/// <summary>
/// Returns a number whose sign matches EdgeEval(u,v,w) but which
/// is cheaper to evaluate. Returns > 0, == 0 , or < 0
/// as v is above, on, or below the edge uw.
/// </summary>
public static Real EdgeSign(MeshUtils.Vertex u, MeshUtils.Vertex v, MeshUtils.Vertex w)
{
Debug.Assert(VertLeq(u, v) && VertLeq(v, w));
var gapL = v._s - u._s;
var gapR = w._s - v._s;
if (gapL + gapR > 0.0f)
{
return (v._t - w._t) * gapL + (v._t - u._t) * gapR;
}
/* vertical line */
return 0;
}
public static bool TransLeq(MeshUtils.Vertex lhs, MeshUtils.Vertex rhs)
{
return (lhs._t < rhs._t) || (lhs._t == rhs._t && lhs._s <= rhs._s);
}
public static Real TransEval(MeshUtils.Vertex u, MeshUtils.Vertex v, MeshUtils.Vertex w)
{
Debug.Assert(TransLeq(u, v) && TransLeq(v, w));
var gapL = v._t - u._t;
var gapR = w._t - v._t;
if (gapL + gapR > 0.0f)
{
if (gapL < gapR)
{
return (v._s - u._s) + (u._s - w._s) * (gapL / (gapL + gapR));
}
else
{
return (v._s - w._s) + (w._s - u._s) * (gapR / (gapL + gapR));
}
}
/* vertical line */
return 0;
}
public static Real TransSign(MeshUtils.Vertex u, MeshUtils.Vertex v, MeshUtils.Vertex w)
{
Debug.Assert(TransLeq(u, v) && TransLeq(v, w));
var gapL = v._t - u._t;
var gapR = w._t - v._t;
if (gapL + gapR > 0.0f)
{
return (v._s - w._s) * gapL + (v._s - u._s) * gapR;
}
/* vertical line */
return 0;
}
public static bool EdgeGoesLeft(MeshUtils.Edge e)
{
return VertLeq(e._Dst, e._Org);
}
public static bool EdgeGoesRight(MeshUtils.Edge e)
{
return VertLeq(e._Org, e._Dst);
}
public static Real VertL1dist(MeshUtils.Vertex u, MeshUtils.Vertex v)
{
return Math.Abs(u._s - v._s) + Math.Abs(u._t - v._t);
}
public static void AddWinding(MeshUtils.Edge eDst, MeshUtils.Edge eSrc)
{
eDst._winding += eSrc._winding;
eDst._Sym._winding += eSrc._Sym._winding;
}
public static Real Interpolate(Real a, Real x, Real b, Real y)
{
if (a < 0.0f)
{
a = 0.0f;
}
if (b < 0.0f)
{
b = 0.0f;
}
return ((a <= b) ? ((b == 0.0f) ? ((x+y) / 2.0f)
: (x + (y-x) * (a/(a+b))))
: (y + (x-y) * (b/(a+b))));
}
static void Swap(ref MeshUtils.Vertex a, ref MeshUtils.Vertex b)
{
var tmp = a;
a = b;
b = tmp;
}
/// <summary>
/// Given edges (o1,d1) and (o2,d2), compute their point of intersection.
/// The computed point is guaranteed to lie in the intersection of the
/// bounding rectangles defined by each edge.
/// </summary>
public static void EdgeIntersect(MeshUtils.Vertex o1, MeshUtils.Vertex d1, MeshUtils.Vertex o2, MeshUtils.Vertex d2, MeshUtils.Vertex v)
{
// This is certainly not the most efficient way to find the intersection
// of two line segments, but it is very numerically stable.
//
// Strategy: find the two middle vertices in the VertLeq ordering,
// and interpolate the intersection s-value from these. Then repeat
// using the TransLeq ordering to find the intersection t-value.
if (!VertLeq(o1, d1)) { Swap(ref o1, ref d1); }
if (!VertLeq(o2, d2)) { Swap(ref o2, ref d2); }
if (!VertLeq(o1, o2)) { Swap(ref o1, ref o2); Swap(ref d1, ref d2); }
if (!VertLeq(o2, d1))
{
// Technically, no intersection -- do our best
v._s = (o2._s + d1._s) / 2.0f;
}
else if (VertLeq(d1, d2))
{
// Interpolate between o2 and d1
var z1 = EdgeEval(o1, o2, d1);
var z2 = EdgeEval(o2, d1, d2);
if (z1 + z2 < 0.0f)
{
z1 = -z1;
z2 = -z2;
}
v._s = Interpolate(z1, o2._s, z2, d1._s);
}
else
{
// Interpolate between o2 and d2
var z1 = EdgeSign(o1, o2, d1);
var z2 = -EdgeSign(o1, d2, d1);
if (z1 + z2 < 0.0f)
{
z1 = -z1;
z2 = -z2;
}
v._s = Interpolate(z1, o2._s, z2, d2._s);
}
// Now repeat the process for t
if (!TransLeq(o1, d1)) { Swap(ref o1, ref d1); }
if (!TransLeq(o2, d2)) { Swap(ref o2, ref d2); }
if (!TransLeq(o1, o2)) { Swap(ref o1, ref o2); Swap(ref d1, ref d2); }
if (!TransLeq(o2, d1))
{
// Technically, no intersection -- do our best
v._t = (o2._t + d1._t) / 2.0f;
}
else if (TransLeq(d1, d2))
{
// Interpolate between o2 and d1
var z1 = TransEval(o1, o2, d1);
var z2 = TransEval(o2, d1, d2);
if (z1 + z2 < 0.0f)
{
z1 = -z1;
z2 = -z2;
}
v._t = Interpolate(z1, o2._t, z2, d1._t);
}
else
{
// Interpolate between o2 and d2
var z1 = TransSign(o1, o2, d1);
var z2 = -TransSign(o1, d2, d1);
if (z1 + z2 < 0.0f)
{
z1 = -z1;
z2 = -z2;
}
v._t = Interpolate(z1, o2._t, z2, d2._t);
}
}
}
}
} // namespace Unity.VectorGraphics.External

View file

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

View file

@ -0,0 +1,25 @@
** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
** Copyright (C) 2011 Silicon Graphics, Inc.
** All Rights Reserved.
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
** of the Software, and to permit persons to whom the Software is furnished to do so,
** subject to the following conditions:
**
** The above copyright notice including the dates of first publication and either this
** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be
** included in all copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC.
** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
** OR OTHER DEALINGS IN THE SOFTWARE.
**
** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not
** be used in advertising or otherwise to promote the sale, use or other dealings in
** this Software without prior written authorization from Silicon Graphics, Inc.

View file

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

View file

@ -0,0 +1,500 @@
/*
** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
** Copyright (C) 2011 Silicon Graphics, Inc.
** All Rights Reserved.
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
** of the Software, and to permit persons to whom the Software is furnished to do so,
** subject to the following conditions:
**
** The above copyright notice including the dates of first publication and either this
** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be
** included in all copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC.
** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
** OR OTHER DEALINGS IN THE SOFTWARE.
**
** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not
** be used in advertising or otherwise to promote the sale, use or other dealings in
** this Software without prior written authorization from Silicon Graphics, Inc.
*/
/*
** Original Author: Eric Veach, July 1994.
** libtess2: Mikko Mononen, http://code.google.com/p/libtess2/.
** LibTessDotNet: Remi Gillig, https://github.com/speps/LibTessDotNet
*/
using System;
using System.Diagnostics;
namespace Unity.SpriteShape.External
{
namespace LibTessDotNet
{
internal class Mesh : MeshUtils.Pooled<Mesh>
{
internal MeshUtils.Vertex _vHead;
internal MeshUtils.Face _fHead;
internal MeshUtils.Edge _eHead, _eHeadSym;
public Mesh()
{
var v = _vHead = MeshUtils.Vertex.Create();
var f = _fHead = MeshUtils.Face.Create();
var pair = MeshUtils.EdgePair.Create();
var e = _eHead = pair._e;
var eSym = _eHeadSym = pair._eSym;
v._next = v._prev = v;
v._anEdge = null;
f._next = f._prev = f;
f._anEdge = null;
f._trail = null;
f._marked = false;
f._inside = false;
e._next = e;
e._Sym = eSym;
e._Onext = null;
e._Lnext = null;
e._Org = null;
e._Lface = null;
e._winding = 0;
e._activeRegion = null;
eSym._next = eSym;
eSym._Sym = e;
eSym._Onext = null;
eSym._Lnext = null;
eSym._Org = null;
eSym._Lface = null;
eSym._winding = 0;
eSym._activeRegion = null;
}
public override void Reset()
{
_vHead = null;
_fHead = null;
_eHead = _eHeadSym = null;
}
public override void OnFree()
{
for (MeshUtils.Face f = _fHead._next, fNext = _fHead; f != _fHead; f = fNext)
{
fNext = f._next;
f.Free();
}
for (MeshUtils.Vertex v = _vHead._next, vNext = _vHead; v != _vHead; v = vNext)
{
vNext = v._next;
v.Free();
}
for (MeshUtils.Edge e = _eHead._next, eNext = _eHead; e != _eHead; e = eNext)
{
eNext = e._next;
e.Free();
}
}
/// <summary>
/// Creates one edge, two vertices and a loop (face).
/// The loop consists of the two new half-edges.
/// </summary>
public MeshUtils.Edge MakeEdge()
{
var e = MeshUtils.MakeEdge(_eHead);
MeshUtils.MakeVertex(e, _vHead);
MeshUtils.MakeVertex(e._Sym, _vHead);
MeshUtils.MakeFace(e, _fHead);
return e;
}
/// <summary>
/// Splice is the basic operation for changing the
/// mesh connectivity and topology. It changes the mesh so that
/// eOrg->Onext = OLD( eDst->Onext )
/// eDst->Onext = OLD( eOrg->Onext )
/// where OLD(...) means the value before the meshSplice operation.
///
/// This can have two effects on the vertex structure:
/// - if eOrg->Org != eDst->Org, the two vertices are merged together
/// - if eOrg->Org == eDst->Org, the origin is split into two vertices
/// In both cases, eDst->Org is changed and eOrg->Org is untouched.
///
/// Similarly (and independently) for the face structure,
/// - if eOrg->Lface == eDst->Lface, one loop is split into two
/// - if eOrg->Lface != eDst->Lface, two distinct loops are joined into one
/// In both cases, eDst->Lface is changed and eOrg->Lface is unaffected.
///
/// Some special cases:
/// If eDst == eOrg, the operation has no effect.
/// If eDst == eOrg->Lnext, the new face will have a single edge.
/// If eDst == eOrg->Lprev, the old face will have a single edge.
/// If eDst == eOrg->Onext, the new vertex will have a single edge.
/// If eDst == eOrg->Oprev, the old vertex will have a single edge.
/// </summary>
public void Splice(MeshUtils.Edge eOrg, MeshUtils.Edge eDst)
{
if (eOrg == eDst)
{
return;
}
bool joiningVertices = false;
if (eDst._Org != eOrg._Org)
{
// We are merging two disjoint vertices -- destroy eDst->Org
joiningVertices = true;
MeshUtils.KillVertex(eDst._Org, eOrg._Org);
}
bool joiningLoops = false;
if (eDst._Lface != eOrg._Lface)
{
// We are connecting two disjoint loops -- destroy eDst->Lface
joiningLoops = true;
MeshUtils.KillFace(eDst._Lface, eOrg._Lface);
}
// Change the edge structure
MeshUtils.Splice(eDst, eOrg);
if (!joiningVertices)
{
// We split one vertex into two -- the new vertex is eDst->Org.
// Make sure the old vertex points to a valid half-edge.
MeshUtils.MakeVertex(eDst, eOrg._Org);
eOrg._Org._anEdge = eOrg;
}
if (!joiningLoops)
{
// We split one loop into two -- the new loop is eDst->Lface.
// Make sure the old face points to a valid half-edge.
MeshUtils.MakeFace(eDst, eOrg._Lface);
eOrg._Lface._anEdge = eOrg;
}
}
/// <summary>
/// Removes the edge eDel. There are several cases:
/// if (eDel->Lface != eDel->Rface), we join two loops into one; the loop
/// eDel->Lface is deleted. Otherwise, we are splitting one loop into two;
/// the newly created loop will contain eDel->Dst. If the deletion of eDel
/// would create isolated vertices, those are deleted as well.
/// </summary>
public void Delete(MeshUtils.Edge eDel)
{
var eDelSym = eDel._Sym;
// First step: disconnect the origin vertex eDel->Org. We make all
// changes to get a consistent mesh in this "intermediate" state.
bool joiningLoops = false;
if (eDel._Lface != eDel._Rface)
{
// We are joining two loops into one -- remove the left face
joiningLoops = true;
MeshUtils.KillFace(eDel._Lface, eDel._Rface);
}
if (eDel._Onext == eDel)
{
MeshUtils.KillVertex(eDel._Org, null);
}
else
{
// Make sure that eDel->Org and eDel->Rface point to valid half-edges
eDel._Rface._anEdge = eDel._Oprev;
eDel._Org._anEdge = eDel._Onext;
MeshUtils.Splice(eDel, eDel._Oprev);
if (!joiningLoops)
{
// We are splitting one loop into two -- create a new loop for eDel.
MeshUtils.MakeFace(eDel, eDel._Lface);
}
}
// Claim: the mesh is now in a consistent state, except that eDel->Org
// may have been deleted. Now we disconnect eDel->Dst.
if (eDelSym._Onext == eDelSym)
{
MeshUtils.KillVertex(eDelSym._Org, null);
MeshUtils.KillFace(eDelSym._Lface, null);
}
else
{
// Make sure that eDel->Dst and eDel->Lface point to valid half-edges
eDel._Lface._anEdge = eDelSym._Oprev;
eDelSym._Org._anEdge = eDelSym._Onext;
MeshUtils.Splice(eDelSym, eDelSym._Oprev);
}
// Any isolated vertices or faces have already been freed.
MeshUtils.KillEdge(eDel);
}
/// <summary>
/// Creates a new edge such that eNew == eOrg.Lnext and eNew.Dst is a newly created vertex.
/// eOrg and eNew will have the same left face.
/// </summary>
public MeshUtils.Edge AddEdgeVertex(MeshUtils.Edge eOrg)
{
var eNew = MeshUtils.MakeEdge(eOrg);
var eNewSym = eNew._Sym;
// Connect the new edge appropriately
MeshUtils.Splice(eNew, eOrg._Lnext);
// Set vertex and face information
eNew._Org = eOrg._Dst;
MeshUtils.MakeVertex(eNewSym, eNew._Org);
eNew._Lface = eNewSym._Lface = eOrg._Lface;
return eNew;
}
/// <summary>
/// Splits eOrg into two edges eOrg and eNew such that eNew == eOrg.Lnext.
/// The new vertex is eOrg.Dst == eNew.Org.
/// eOrg and eNew will have the same left face.
/// </summary>
public MeshUtils.Edge SplitEdge(MeshUtils.Edge eOrg)
{
var eTmp = AddEdgeVertex(eOrg);
var eNew = eTmp._Sym;
// Disconnect eOrg from eOrg->Dst and connect it to eNew->Org
MeshUtils.Splice(eOrg._Sym, eOrg._Sym._Oprev);
MeshUtils.Splice(eOrg._Sym, eNew);
// Set the vertex and face information
eOrg._Dst = eNew._Org;
eNew._Dst._anEdge = eNew._Sym; // may have pointed to eOrg->Sym
eNew._Rface = eOrg._Rface;
eNew._winding = eOrg._winding; // copy old winding information
eNew._Sym._winding = eOrg._Sym._winding;
return eNew;
}
/// <summary>
/// Creates a new edge from eOrg->Dst to eDst->Org, and returns the corresponding half-edge eNew.
/// If eOrg->Lface == eDst->Lface, this splits one loop into two,
/// and the newly created loop is eNew->Lface. Otherwise, two disjoint
/// loops are merged into one, and the loop eDst->Lface is destroyed.
///
/// If (eOrg == eDst), the new face will have only two edges.
/// If (eOrg->Lnext == eDst), the old face is reduced to a single edge.
/// If (eOrg->Lnext->Lnext == eDst), the old face is reduced to two edges.
/// </summary>
public MeshUtils.Edge Connect(MeshUtils.Edge eOrg, MeshUtils.Edge eDst)
{
var eNew = MeshUtils.MakeEdge(eOrg);
var eNewSym = eNew._Sym;
bool joiningLoops = false;
if (eDst._Lface != eOrg._Lface)
{
// We are connecting two disjoint loops -- destroy eDst->Lface
joiningLoops = true;
MeshUtils.KillFace(eDst._Lface, eOrg._Lface);
}
// Connect the new edge appropriately
MeshUtils.Splice(eNew, eOrg._Lnext);
MeshUtils.Splice(eNewSym, eDst);
// Set the vertex and face information
eNew._Org = eOrg._Dst;
eNewSym._Org = eDst._Org;
eNew._Lface = eNewSym._Lface = eOrg._Lface;
// Make sure the old face points to a valid half-edge
eOrg._Lface._anEdge = eNewSym;
if (!joiningLoops)
{
MeshUtils.MakeFace(eNew, eOrg._Lface);
}
return eNew;
}
/// <summary>
/// Destroys a face and removes it from the global face list. All edges of
/// fZap will have a NULL pointer as their left face. Any edges which
/// also have a NULL pointer as their right face are deleted entirely
/// (along with any isolated vertices this produces).
/// An entire mesh can be deleted by zapping its faces, one at a time,
/// in any order. Zapped faces cannot be used in further mesh operations!
/// </summary>
public void ZapFace(MeshUtils.Face fZap)
{
var eStart = fZap._anEdge;
// walk around face, deleting edges whose right face is also NULL
var eNext = eStart._Lnext;
MeshUtils.Edge e, eSym;
do {
e = eNext;
eNext = e._Lnext;
e._Lface = null;
if (e._Rface == null)
{
// delete the edge -- see TESSmeshDelete above
if (e._Onext == e)
{
MeshUtils.KillVertex(e._Org, null);
}
else
{
// Make sure that e._Org points to a valid half-edge
e._Org._anEdge = e._Onext;
MeshUtils.Splice(e, e._Oprev);
}
eSym = e._Sym;
if (eSym._Onext == eSym)
{
MeshUtils.KillVertex(eSym._Org, null);
}
else
{
// Make sure that eSym._Org points to a valid half-edge
eSym._Org._anEdge = eSym._Onext;
MeshUtils.Splice(eSym, eSym._Oprev);
}
MeshUtils.KillEdge(e);
}
} while (e != eStart);
/* delete from circular doubly-linked list */
var fPrev = fZap._prev;
var fNext = fZap._next;
fNext._prev = fPrev;
fPrev._next = fNext;
fZap.Free();
}
public void MergeConvexFaces(int maxVertsPerFace)
{
for (var f = _fHead._next; f != _fHead; f = f._next)
{
// Skip faces which are outside the result
if (!f._inside)
{
continue;
}
var eCur = f._anEdge;
var vStart = eCur._Org;
while (true)
{
var eNext = eCur._Lnext;
var eSym = eCur._Sym;
if (eSym != null && eSym._Lface != null && eSym._Lface._inside)
{
// Try to merge the neighbour faces if the resulting polygons
// does not exceed maximum number of vertices.
int curNv = f.VertsCount;
int symNv = eSym._Lface.VertsCount;
if ((curNv + symNv - 2) <= maxVertsPerFace)
{
// Merge if the resulting poly is convex.
if (Geom.VertCCW(eCur._Lprev._Org, eCur._Org, eSym._Lnext._Lnext._Org) &&
Geom.VertCCW(eSym._Lprev._Org, eSym._Org, eCur._Lnext._Lnext._Org))
{
eNext = eSym._Lnext;
Delete(eSym);
eCur = null;
}
}
}
if (eCur != null && eCur._Lnext._Org == vStart)
break;
// Continue to next edge.
eCur = eNext;
}
}
}
[Conditional("DEBUG")]
public void Check()
{
MeshUtils.Edge e;
MeshUtils.Face fPrev = _fHead, f;
for (fPrev = _fHead; (f = fPrev._next) != _fHead; fPrev = f)
{
e = f._anEdge;
do {
Debug.Assert(e._Sym != e);
Debug.Assert(e._Sym._Sym == e);
Debug.Assert(e._Lnext._Onext._Sym == e);
Debug.Assert(e._Onext._Sym._Lnext == e);
Debug.Assert(e._Lface == f);
e = e._Lnext;
} while (e != f._anEdge);
}
Debug.Assert(f._prev == fPrev && f._anEdge == null);
MeshUtils.Vertex vPrev = _vHead, v;
for (vPrev = _vHead; (v = vPrev._next) != _vHead; vPrev = v)
{
Debug.Assert(v._prev == vPrev);
e = v._anEdge;
do
{
Debug.Assert(e._Sym != e);
Debug.Assert(e._Sym._Sym == e);
Debug.Assert(e._Lnext._Onext._Sym == e);
Debug.Assert(e._Onext._Sym._Lnext == e);
Debug.Assert(e._Org == v);
e = e._Onext;
} while (e != v._anEdge);
}
Debug.Assert(v._prev == vPrev && v._anEdge == null);
MeshUtils.Edge ePrev = _eHead;
for (ePrev = _eHead; (e = ePrev._next) != _eHead; ePrev = e)
{
Debug.Assert(e._Sym._next == ePrev._Sym);
Debug.Assert(e._Sym != e);
Debug.Assert(e._Sym._Sym == e);
Debug.Assert(e._Org != null);
Debug.Assert(e._Dst != null);
Debug.Assert(e._Lnext._Onext._Sym == e);
Debug.Assert(e._Onext._Sym._Lnext == e);
}
Debug.Assert(e._Sym._next == ePrev._Sym
&& e._Sym == _eHeadSym
&& e._Sym._Sym == e
&& e._Org == null && e._Dst == null
&& e._Lface == null && e._Rface == null);
}
}
}
} // namespace Unity.VectorGraphics.External

View file

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

View file

@ -0,0 +1,465 @@
/*
** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
** Copyright (C) 2011 Silicon Graphics, Inc.
** All Rights Reserved.
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
** of the Software, and to permit persons to whom the Software is furnished to do so,
** subject to the following conditions:
**
** The above copyright notice including the dates of first publication and either this
** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be
** included in all copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC.
** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
** OR OTHER DEALINGS IN THE SOFTWARE.
**
** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not
** be used in advertising or otherwise to promote the sale, use or other dealings in
** this Software without prior written authorization from Silicon Graphics, Inc.
*/
/*
** Original Author: Eric Veach, July 1994.
** libtess2: Mikko Mononen, http://code.google.com/p/libtess2/.
** LibTessDotNet: Remi Gillig, https://github.com/speps/LibTessDotNet
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace Unity.SpriteShape.External
{
using Real = System.Single;
namespace LibTessDotNet
{
internal struct Vec3
{
public readonly static Vec3 Zero = new Vec3();
public Real X, Y, Z;
public Real this[int index]
{
get
{
if (index == 0) return X;
if (index == 1) return Y;
if (index == 2) return Z;
throw new IndexOutOfRangeException();
}
set
{
if (index == 0) X = value;
else if (index == 1) Y = value;
else if (index == 2) Z = value;
else throw new IndexOutOfRangeException();
}
}
public static void Sub(ref Vec3 lhs, ref Vec3 rhs, out Vec3 result)
{
result.X = lhs.X - rhs.X;
result.Y = lhs.Y - rhs.Y;
result.Z = lhs.Z - rhs.Z;
}
public static void Neg(ref Vec3 v)
{
v.X = -v.X;
v.Y = -v.Y;
v.Z = -v.Z;
}
public static void Dot(ref Vec3 u, ref Vec3 v, out Real dot)
{
dot = u.X * v.X + u.Y * v.Y + u.Z * v.Z;
}
public static void Normalize(ref Vec3 v)
{
var len = v.X * v.X + v.Y * v.Y + v.Z * v.Z;
Debug.Assert(len >= 0.0f);
len = 1.0f / (Real)Math.Sqrt(len);
v.X *= len;
v.Y *= len;
v.Z *= len;
}
public static int LongAxis(ref Vec3 v)
{
int i = 0;
if (Math.Abs(v.Y) > Math.Abs(v.X)) i = 1;
if (Math.Abs(v.Z) > Math.Abs(i == 0 ? v.X : v.Y)) i = 2;
return i;
}
public override string ToString()
{
return string.Format("{0}, {1}, {2}", X, Y, Z);
}
}
internal static class MeshUtils
{
public const int Undef = ~0;
public abstract class Pooled<T> where T : Pooled<T>, new()
{
private static Stack<T> _stack;
public abstract void Reset();
public virtual void OnFree() { }
public static T Create()
{
if (_stack != null && _stack.Count > 0)
{
return _stack.Pop();
}
return new T();
}
public void Free()
{
OnFree();
Reset();
if (_stack == null)
{
_stack = new Stack<T>();
}
_stack.Push((T)this);
}
}
public class Vertex : Pooled<Vertex>
{
internal Vertex _prev, _next;
internal Edge _anEdge;
internal Vec3 _coords;
internal Real _s, _t;
internal PQHandle _pqHandle;
internal int _n;
internal object _data;
public override void Reset()
{
_prev = _next = null;
_anEdge = null;
_coords = Vec3.Zero;
_s = 0;
_t = 0;
_pqHandle = new PQHandle();
_n = 0;
_data = null;
}
}
public class Face : Pooled<Face>
{
internal Face _prev, _next;
internal Edge _anEdge;
internal Face _trail;
internal int _n;
internal bool _marked, _inside;
internal int VertsCount
{
get
{
int n = 0;
var eCur = _anEdge;
do {
n++;
eCur = eCur._Lnext;
} while (eCur != _anEdge);
return n;
}
}
public override void Reset()
{
_prev = _next = null;
_anEdge = null;
_trail = null;
_n = 0;
_marked = false;
_inside = false;
}
}
public struct EdgePair
{
internal Edge _e, _eSym;
public static EdgePair Create()
{
var pair = new MeshUtils.EdgePair();
pair._e = MeshUtils.Edge.Create();
pair._e._pair = pair;
pair._eSym = MeshUtils.Edge.Create();
pair._eSym._pair = pair;
return pair;
}
public void Reset()
{
_e = _eSym = null;
}
}
public class Edge : Pooled<Edge>
{
internal EdgePair _pair;
internal Edge _next, _Sym, _Onext, _Lnext;
internal Vertex _Org;
internal Face _Lface;
internal Tess.ActiveRegion _activeRegion;
internal int _winding;
internal Face _Rface { get { return _Sym._Lface; } set { _Sym._Lface = value; } }
internal Vertex _Dst { get { return _Sym._Org; } set { _Sym._Org = value; } }
internal Edge _Oprev { get { return _Sym._Lnext; } set { _Sym._Lnext = value; } }
internal Edge _Lprev { get { return _Onext._Sym; } set { _Onext._Sym = value; } }
internal Edge _Dprev { get { return _Lnext._Sym; } set { _Lnext._Sym = value; } }
internal Edge _Rprev { get { return _Sym._Onext; } set { _Sym._Onext = value; } }
internal Edge _Dnext { get { return _Rprev._Sym; } set { _Rprev._Sym = value; } }
internal Edge _Rnext { get { return _Oprev._Sym; } set { _Oprev._Sym = value; } }
internal static void EnsureFirst(ref Edge e)
{
if (e == e._pair._eSym)
{
e = e._Sym;
}
}
public override void Reset()
{
_pair.Reset();
_next = _Sym = _Onext = _Lnext = null;
_Org = null;
_Lface = null;
_activeRegion = null;
_winding = 0;
}
}
/// <summary>
/// MakeEdge creates a new pair of half-edges which form their own loop.
/// No vertex or face structures are allocated, but these must be assigned
/// before the current edge operation is completed.
/// </summary>
public static Edge MakeEdge(Edge eNext)
{
Debug.Assert(eNext != null);
var pair = EdgePair.Create();
var e = pair._e;
var eSym = pair._eSym;
// Make sure eNext points to the first edge of the edge pair
Edge.EnsureFirst(ref eNext);
// Insert in circular doubly-linked list before eNext.
// Note that the prev pointer is stored in Sym->next.
var ePrev = eNext._Sym._next;
eSym._next = ePrev;
ePrev._Sym._next = e;
e._next = eNext;
eNext._Sym._next = eSym;
e._Sym = eSym;
e._Onext = e;
e._Lnext = eSym;
e._Org = null;
e._Lface = null;
e._winding = 0;
e._activeRegion = null;
eSym._Sym = e;
eSym._Onext = eSym;
eSym._Lnext = e;
eSym._Org = null;
eSym._Lface = null;
eSym._winding = 0;
eSym._activeRegion = null;
return e;
}
/// <summary>
/// Splice( a, b ) is best described by the Guibas/Stolfi paper or the
/// CS348a notes (see Mesh.cs). Basically it modifies the mesh so that
/// a->Onext and b->Onext are exchanged. This can have various effects
/// depending on whether a and b belong to different face or vertex rings.
/// For more explanation see Mesh.Splice().
/// </summary>
public static void Splice(Edge a, Edge b)
{
var aOnext = a._Onext;
var bOnext = b._Onext;
aOnext._Sym._Lnext = b;
bOnext._Sym._Lnext = a;
a._Onext = bOnext;
b._Onext = aOnext;
}
/// <summary>
/// MakeVertex( eOrig, vNext ) attaches a new vertex and makes it the
/// origin of all edges in the vertex loop to which eOrig belongs. "vNext" gives
/// a place to insert the new vertex in the global vertex list. We insert
/// the new vertex *before* vNext so that algorithms which walk the vertex
/// list will not see the newly created vertices.
/// </summary>
public static void MakeVertex(Edge eOrig, Vertex vNext)
{
var vNew = MeshUtils.Vertex.Create();
// insert in circular doubly-linked list before vNext
var vPrev = vNext._prev;
vNew._prev = vPrev;
vPrev._next = vNew;
vNew._next = vNext;
vNext._prev = vNew;
vNew._anEdge = eOrig;
// leave coords, s, t undefined
// fix other edges on this vertex loop
var e = eOrig;
do {
e._Org = vNew;
e = e._Onext;
} while (e != eOrig);
}
/// <summary>
/// MakeFace( eOrig, fNext ) attaches a new face and makes it the left
/// face of all edges in the face loop to which eOrig belongs. "fNext" gives
/// a place to insert the new face in the global face list. We insert
/// the new face *before* fNext so that algorithms which walk the face
/// list will not see the newly created faces.
/// </summary>
public static void MakeFace(Edge eOrig, Face fNext)
{
var fNew = MeshUtils.Face.Create();
// insert in circular doubly-linked list before fNext
var fPrev = fNext._prev;
fNew._prev = fPrev;
fPrev._next = fNew;
fNew._next = fNext;
fNext._prev = fNew;
fNew._anEdge = eOrig;
fNew._trail = null;
fNew._marked = false;
// The new face is marked "inside" if the old one was. This is a
// convenience for the common case where a face has been split in two.
fNew._inside = fNext._inside;
// fix other edges on this face loop
var e = eOrig;
do {
e._Lface = fNew;
e = e._Lnext;
} while (e != eOrig);
}
/// <summary>
/// KillEdge( eDel ) destroys an edge (the half-edges eDel and eDel->Sym),
/// and removes from the global edge list.
/// </summary>
public static void KillEdge(Edge eDel)
{
// Half-edges are allocated in pairs, see EdgePair above
Edge.EnsureFirst(ref eDel);
// delete from circular doubly-linked list
var eNext = eDel._next;
var ePrev = eDel._Sym._next;
eNext._Sym._next = ePrev;
ePrev._Sym._next = eNext;
eDel.Free();
}
/// <summary>
/// KillVertex( vDel ) destroys a vertex and removes it from the global
/// vertex list. It updates the vertex loop to point to a given new vertex.
/// </summary>
public static void KillVertex(Vertex vDel, Vertex newOrg)
{
var eStart = vDel._anEdge;
// change the origin of all affected edges
var e = eStart;
do {
e._Org = newOrg;
e = e._Onext;
} while (e != eStart);
// delete from circular doubly-linked list
var vPrev = vDel._prev;
var vNext = vDel._next;
vNext._prev = vPrev;
vPrev._next = vNext;
vDel.Free();
}
/// <summary>
/// KillFace( fDel ) destroys a face and removes it from the global face
/// list. It updates the face loop to point to a given new face.
/// </summary>
public static void KillFace(Face fDel, Face newLFace)
{
var eStart = fDel._anEdge;
// change the left face of all affected edges
var e = eStart;
do {
e._Lface = newLFace;
e = e._Lnext;
} while (e != eStart);
// delete from circular doubly-linked list
var fPrev = fDel._prev;
var fNext = fDel._next;
fNext._prev = fPrev;
fPrev._next = fNext;
fDel.Free();
}
/// <summary>
/// Return signed area of face.
/// </summary>
public static Real FaceArea(Face f)
{
Real area = 0;
var e = f._anEdge;
do
{
area += (e._Org._s - e._Dst._s) * (e._Org._t + e._Dst._t);
e = e._Lnext;
} while (e != f._anEdge);
return area;
}
}
}
} // namespace Unity.VectorGraphics.External

View file

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

View file

@ -0,0 +1,246 @@
/*
** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
** Copyright (C) 2011 Silicon Graphics, Inc.
** All Rights Reserved.
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
** of the Software, and to permit persons to whom the Software is furnished to do so,
** subject to the following conditions:
**
** The above copyright notice including the dates of first publication and either this
** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be
** included in all copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC.
** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
** OR OTHER DEALINGS IN THE SOFTWARE.
**
** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not
** be used in advertising or otherwise to promote the sale, use or other dealings in
** this Software without prior written authorization from Silicon Graphics, Inc.
*/
/*
** Original Author: Eric Veach, July 1994.
** libtess2: Mikko Mononen, http://code.google.com/p/libtess2/.
** LibTessDotNet: Remi Gillig, https://github.com/speps/LibTessDotNet
*/
using System;
using System.Diagnostics;
namespace Unity.SpriteShape.External
{
namespace LibTessDotNet
{
internal struct PQHandle
{
public static readonly int Invalid = 0x0fffffff;
internal int _handle;
}
internal class PriorityHeap<TValue> where TValue : class
{
public delegate bool LessOrEqual(TValue lhs, TValue rhs);
protected class HandleElem
{
internal TValue _key;
internal int _node;
}
private LessOrEqual _leq;
private int[] _nodes;
private HandleElem[] _handles;
private int _size, _max;
private int _freeList;
private bool _initialized;
public bool Empty { get { return _size == 0; } }
public PriorityHeap(int initialSize, LessOrEqual leq)
{
_leq = leq;
_nodes = new int[initialSize + 1];
_handles = new HandleElem[initialSize + 1];
_size = 0;
_max = initialSize;
_freeList = 0;
_initialized = false;
_nodes[1] = 1;
_handles[1] = new HandleElem { _key = null };
}
private void FloatDown(int curr)
{
int child;
int hCurr, hChild;
hCurr = _nodes[curr];
while (true)
{
child = curr << 1;
if (child < _size && _leq(_handles[_nodes[child + 1]]._key, _handles[_nodes[child]]._key))
{
++child;
}
Debug.Assert(child <= _max);
hChild = _nodes[child];
if (child > _size || _leq(_handles[hCurr]._key, _handles[hChild]._key))
{
_nodes[curr] = hCurr;
_handles[hCurr]._node = curr;
break;
}
_nodes[curr] = hChild;
_handles[hChild]._node = curr;
curr = child;
}
}
private void FloatUp(int curr)
{
int parent;
int hCurr, hParent;
hCurr = _nodes[curr];
while (true)
{
parent = curr >> 1;
hParent = _nodes[parent];
if (parent == 0 || _leq(_handles[hParent]._key, _handles[hCurr]._key))
{
_nodes[curr] = hCurr;
_handles[hCurr]._node = curr;
break;
}
_nodes[curr] = hParent;
_handles[hParent]._node = curr;
curr = parent;
}
}
public void Init()
{
for (int i = _size; i >= 1; --i)
{
FloatDown(i);
}
_initialized = true;
}
public PQHandle Insert(TValue value)
{
int curr = ++_size;
if ((curr * 2) > _max)
{
_max <<= 1;
Array.Resize(ref _nodes, _max + 1);
Array.Resize(ref _handles, _max + 1);
}
int free;
if (_freeList == 0)
{
free = curr;
}
else
{
free = _freeList;
_freeList = _handles[free]._node;
}
_nodes[curr] = free;
if (_handles[free] == null)
{
_handles[free] = new HandleElem { _key = value, _node = curr };
}
else
{
_handles[free]._node = curr;
_handles[free]._key = value;
}
if (_initialized)
{
FloatUp(curr);
}
Debug.Assert(free != PQHandle.Invalid);
return new PQHandle { _handle = free };
}
public TValue ExtractMin()
{
Debug.Assert(_initialized);
int hMin = _nodes[1];
TValue min = _handles[hMin]._key;
if (_size > 0)
{
_nodes[1] = _nodes[_size];
_handles[_nodes[1]]._node = 1;
_handles[hMin]._key = null;
_handles[hMin]._node = _freeList;
_freeList = hMin;
if (--_size > 0)
{
FloatDown(1);
}
}
return min;
}
public TValue Minimum()
{
Debug.Assert(_initialized);
return _handles[_nodes[1]]._key;
}
public void Remove(PQHandle handle)
{
Debug.Assert(_initialized);
int hCurr = handle._handle;
Debug.Assert(hCurr >= 1 && hCurr <= _max && _handles[hCurr]._key != null);
int curr = _handles[hCurr]._node;
_nodes[curr] = _nodes[_size];
_handles[_nodes[curr]]._node = curr;
if (curr <= --_size)
{
if (curr <= 1 || _leq(_handles[_nodes[curr >> 1]]._key, _handles[_nodes[curr]]._key))
{
FloatDown(curr);
}
else
{
FloatUp(curr);
}
}
_handles[hCurr]._key = null;
_handles[hCurr]._node = _freeList;
_freeList = hCurr;
}
}
}
} // namespace Unity.VectorGraphics.External

View file

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

View file

@ -0,0 +1,231 @@
/*
** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
** Copyright (C) 2011 Silicon Graphics, Inc.
** All Rights Reserved.
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
** of the Software, and to permit persons to whom the Software is furnished to do so,
** subject to the following conditions:
**
** The above copyright notice including the dates of first publication and either this
** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be
** included in all copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC.
** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
** OR OTHER DEALINGS IN THE SOFTWARE.
**
** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not
** be used in advertising or otherwise to promote the sale, use or other dealings in
** this Software without prior written authorization from Silicon Graphics, Inc.
*/
/*
** Original Author: Eric Veach, July 1994.
** libtess2: Mikko Mononen, http://code.google.com/p/libtess2/.
** LibTessDotNet: Remi Gillig, https://github.com/speps/LibTessDotNet
*/
using System;
using System.Collections.Generic;
using System.Diagnostics;
namespace Unity.SpriteShape.External
{
namespace LibTessDotNet
{
internal class PriorityQueue<TValue> where TValue : class
{
private PriorityHeap<TValue>.LessOrEqual _leq;
private PriorityHeap<TValue> _heap;
private TValue[] _keys;
private int[] _order;
private int _size, _max;
private bool _initialized;
public bool Empty { get { return _size == 0 && _heap.Empty; } }
public PriorityQueue(int initialSize, PriorityHeap<TValue>.LessOrEqual leq)
{
_leq = leq;
_heap = new PriorityHeap<TValue>(initialSize, leq);
_keys = new TValue[initialSize];
_size = 0;
_max = initialSize;
_initialized = false;
}
class StackItem
{
internal int p, r;
};
static void Swap(ref int a, ref int b)
{
int tmp = a;
a = b;
b = tmp;
}
public void Init()
{
var stack = new Stack<StackItem>();
int p, r, i, j, piv;
uint seed = 2016473283;
p = 0;
r = _size - 1;
_order = new int[_size + 1];
for (piv = 0, i = p; i <= r; ++piv, ++i)
{
_order[i] = piv;
}
stack.Push(new StackItem { p = p, r = r });
while (stack.Count > 0)
{
var top = stack.Pop();
p = top.p;
r = top.r;
while (r > p + 10)
{
seed = seed * 1539415821 + 1;
i = p + (int)(seed % (r - p + 1));
piv = _order[i];
_order[i] = _order[p];
_order[p] = piv;
i = p - 1;
j = r + 1;
do {
do { ++i; } while (!_leq(_keys[_order[i]], _keys[piv]));
do { --j; } while (!_leq(_keys[piv], _keys[_order[j]]));
Swap(ref _order[i], ref _order[j]);
} while (i < j);
Swap(ref _order[i], ref _order[j]);
if (i - p < r - j)
{
stack.Push(new StackItem { p = j + 1, r = r });
r = i - 1;
}
else
{
stack.Push(new StackItem { p = p, r = i - 1 });
p = j + 1;
}
}
for (i = p + 1; i <= r; ++i)
{
piv = _order[i];
for (j = i; j > p && !_leq(_keys[piv], _keys[_order[j - 1]]); --j)
{
_order[j] = _order[j - 1];
}
_order[j] = piv;
}
}
#if DEBUG
p = 0;
r = _size - 1;
for (i = p; i < r; ++i)
{
Debug.Assert(_leq(_keys[_order[i + 1]], _keys[_order[i]]), "Wrong sort");
}
#endif
_max = _size;
_initialized = true;
_heap.Init();
}
public PQHandle Insert(TValue value)
{
if (_initialized)
{
return _heap.Insert(value);
}
int curr = _size;
if (++_size >= _max)
{
_max <<= 1;
Array.Resize(ref _keys, _max);
}
_keys[curr] = value;
return new PQHandle { _handle = -(curr + 1) };
}
public TValue ExtractMin()
{
Debug.Assert(_initialized);
if (_size == 0)
{
return _heap.ExtractMin();
}
TValue sortMin = _keys[_order[_size - 1]];
if (!_heap.Empty)
{
TValue heapMin = _heap.Minimum();
if (_leq(heapMin, sortMin))
return _heap.ExtractMin();
}
do {
--_size;
} while (_size > 0 && _keys[_order[_size - 1]] == null);
return sortMin;
}
public TValue Minimum()
{
Debug.Assert(_initialized);
if (_size == 0)
{
return _heap.Minimum();
}
TValue sortMin = _keys[_order[_size - 1]];
if (!_heap.Empty)
{
TValue heapMin = _heap.Minimum();
if (_leq(heapMin, sortMin))
return heapMin;
}
return sortMin;
}
public void Remove(PQHandle handle)
{
Debug.Assert(_initialized);
int curr = handle._handle;
if (curr >= 0)
{
_heap.Remove(handle);
return;
}
curr = -(curr + 1);
Debug.Assert(curr < _max && _keys[curr] != null);
_keys[curr] = null;
while (_size > 0 && _keys[_order[_size - 1]] == null)
{
--_size;
}
}
}
}
} // namespace Unity.VectorGraphics.External

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

@ -0,0 +1,746 @@
/*
** SGI FREE SOFTWARE LICENSE B (Version 2.0, Sept. 18, 2008)
** Copyright (C) 2011 Silicon Graphics, Inc.
** All Rights Reserved.
**
** Permission is hereby granted, free of charge, to any person obtaining a copy
** of this software and associated documentation files (the "Software"), to deal
** in the Software without restriction, including without limitation the rights
** to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
** of the Software, and to permit persons to whom the Software is furnished to do so,
** subject to the following conditions:
**
** The above copyright notice including the dates of first publication and either this
** permission notice or a reference to http://oss.sgi.com/projects/FreeB/ shall be
** included in all copies or substantial portions of the Software.
**
** THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
** INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
** PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL SILICON GRAPHICS, INC.
** BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
** TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE
** OR OTHER DEALINGS IN THE SOFTWARE.
**
** Except as contained in this notice, the name of Silicon Graphics, Inc. shall not
** be used in advertising or otherwise to promote the sale, use or other dealings in
** this Software without prior written authorization from Silicon Graphics, Inc.
*/
/*
** Original Author: Eric Veach, July 1994.
** libtess2: Mikko Mononen, http://code.google.com/p/libtess2/.
** LibTessDotNet: Remi Gillig, https://github.com/speps/LibTessDotNet
*/
using System;
using System.Diagnostics;
namespace Unity.SpriteShape.External
{
using Real = System.Single;
namespace LibTessDotNet
{
internal enum WindingRule
{
EvenOdd,
NonZero,
Positive,
Negative,
AbsGeqTwo
}
internal enum ElementType
{
Polygons,
ConnectedPolygons,
BoundaryContours
}
internal enum ContourOrientation
{
Original,
Clockwise,
CounterClockwise
}
internal struct ContourVertex
{
public Vec3 Position;
public object Data;
public override string ToString()
{
return string.Format("{0}, {1}", Position, Data);
}
}
internal delegate object CombineCallback(Vec3 position, object[] data, Real[] weights);
internal partial class Tess
{
private Mesh _mesh;
private Vec3 _normal;
private Vec3 _sUnit;
private Vec3 _tUnit;
private Real _bminX, _bminY, _bmaxX, _bmaxY;
private WindingRule _windingRule;
private Dict<ActiveRegion> _dict;
private PriorityQueue<MeshUtils.Vertex> _pq;
private MeshUtils.Vertex _event;
private CombineCallback _combineCallback;
private ContourVertex[] _vertices;
private int _vertexCount;
private int[] _elements;
private int _elementCount;
public Vec3 Normal { get { return _normal; } set { _normal = value; } }
public Real SUnitX = 1;
public Real SUnitY = 0;
public Real SentinelCoord = 4e30f;
/// <summary>
/// If true, will remove empty (zero area) polygons.
/// </summary>
public bool NoEmptyPolygons = false;
/// <summary>
/// If true, will use pooling to reduce GC (compare performance with/without, can vary wildly).
/// </summary>
public bool UsePooling = false;
public ContourVertex[] Vertices { get { return _vertices; } }
public int VertexCount { get { return _vertexCount; } }
public int[] Elements { get { return _elements; } }
public int ElementCount { get { return _elementCount; } }
public Tess()
{
_normal = Vec3.Zero;
_bminX = _bminY = _bmaxX = _bmaxY = 0;
_windingRule = WindingRule.EvenOdd;
_mesh = null;
_vertices = null;
_vertexCount = 0;
_elements = null;
_elementCount = 0;
}
private void ComputeNormal(ref Vec3 norm)
{
var v = _mesh._vHead._next;
var minVal = new Real[3] { v._coords.X, v._coords.Y, v._coords.Z };
var minVert = new MeshUtils.Vertex[3] { v, v, v };
var maxVal = new Real[3] { v._coords.X, v._coords.Y, v._coords.Z };
var maxVert = new MeshUtils.Vertex[3] { v, v, v };
for (; v != _mesh._vHead; v = v._next)
{
if (v._coords.X < minVal[0]) { minVal[0] = v._coords.X; minVert[0] = v; }
if (v._coords.Y < minVal[1]) { minVal[1] = v._coords.Y; minVert[1] = v; }
if (v._coords.Z < minVal[2]) { minVal[2] = v._coords.Z; minVert[2] = v; }
if (v._coords.X > maxVal[0]) { maxVal[0] = v._coords.X; maxVert[0] = v; }
if (v._coords.Y > maxVal[1]) { maxVal[1] = v._coords.Y; maxVert[1] = v; }
if (v._coords.Z > maxVal[2]) { maxVal[2] = v._coords.Z; maxVert[2] = v; }
}
// Find two vertices separated by at least 1/sqrt(3) of the maximum
// distance between any two vertices
int i = 0;
if (maxVal[1] - minVal[1] > maxVal[0] - minVal[0]) { i = 1; }
if (maxVal[2] - minVal[2] > maxVal[i] - minVal[i]) { i = 2; }
if (minVal[i] >= maxVal[i])
{
// All vertices are the same -- normal doesn't matter
norm = new Vec3 { X = 0, Y = 0, Z = 1 };
return;
}
// Look for a third vertex which forms the triangle with maximum area
// (Length of normal == twice the triangle area)
Real maxLen2 = 0, tLen2;
var v1 = minVert[i];
var v2 = maxVert[i];
Vec3 d1, d2, tNorm;
Vec3.Sub(ref v1._coords, ref v2._coords, out d1);
for (v = _mesh._vHead._next; v != _mesh._vHead; v = v._next)
{
Vec3.Sub(ref v._coords, ref v2._coords, out d2);
tNorm.X = d1.Y * d2.Z - d1.Z * d2.Y;
tNorm.Y = d1.Z * d2.X - d1.X * d2.Z;
tNorm.Z = d1.X * d2.Y - d1.Y * d2.X;
tLen2 = tNorm.X*tNorm.X + tNorm.Y*tNorm.Y + tNorm.Z*tNorm.Z;
if (tLen2 > maxLen2)
{
maxLen2 = tLen2;
norm = tNorm;
}
}
if (maxLen2 <= 0.0f)
{
// All points lie on a single line -- any decent normal will do
norm = Vec3.Zero;
i = Vec3.LongAxis(ref d1);
norm[i] = 1;
}
}
private void CheckOrientation()
{
// When we compute the normal automatically, we choose the orientation
// so that the the sum of the signed areas of all contours is non-negative.
Real area = 0.0f;
for (var f = _mesh._fHead._next; f != _mesh._fHead; f = f._next)
{
if (f._anEdge._winding <= 0)
{
continue;
}
area += MeshUtils.FaceArea(f);
}
if (area < 0.0f)
{
// Reverse the orientation by flipping all the t-coordinates
for (var v = _mesh._vHead._next; v != _mesh._vHead; v = v._next)
{
v._t = -v._t;
}
Vec3.Neg(ref _tUnit);
}
}
private void ProjectPolygon()
{
var norm = _normal;
bool computedNormal = false;
if (norm.X == 0.0f && norm.Y == 0.0f && norm.Z == 0.0f)
{
ComputeNormal(ref norm);
_normal = norm;
computedNormal = true;
}
int i = Vec3.LongAxis(ref norm);
_sUnit[i] = 0;
_sUnit[(i + 1) % 3] = SUnitX;
_sUnit[(i + 2) % 3] = SUnitY;
_tUnit[i] = 0;
_tUnit[(i + 1) % 3] = norm[i] > 0.0f ? -SUnitY : SUnitY;
_tUnit[(i + 2) % 3] = norm[i] > 0.0f ? SUnitX : -SUnitX;
// Project the vertices onto the sweep plane
for (var v = _mesh._vHead._next; v != _mesh._vHead; v = v._next)
{
Vec3.Dot(ref v._coords, ref _sUnit, out v._s);
Vec3.Dot(ref v._coords, ref _tUnit, out v._t);
}
if (computedNormal)
{
CheckOrientation();
}
// Compute ST bounds.
bool first = true;
for (var v = _mesh._vHead._next; v != _mesh._vHead; v = v._next)
{
if (first)
{
_bminX = _bmaxX = v._s;
_bminY = _bmaxY = v._t;
first = false;
}
else
{
if (v._s < _bminX) _bminX = v._s;
if (v._s > _bmaxX) _bmaxX = v._s;
if (v._t < _bminY) _bminY = v._t;
if (v._t > _bmaxY) _bmaxY = v._t;
}
}
}
/// <summary>
/// TessellateMonoRegion( face ) tessellates a monotone region
/// (what else would it do??) The region must consist of a single
/// loop of half-edges (see mesh.h) oriented CCW. "Monotone" in this
/// case means that any vertical line intersects the interior of the
/// region in a single interval.
///
/// Tessellation consists of adding interior edges (actually pairs of
/// half-edges), to split the region into non-overlapping triangles.
///
/// The basic idea is explained in Preparata and Shamos (which I don't
/// have handy right now), although their implementation is more
/// complicated than this one. The are two edge chains, an upper chain
/// and a lower chain. We process all vertices from both chains in order,
/// from right to left.
///
/// The algorithm ensures that the following invariant holds after each
/// vertex is processed: the untessellated region consists of two
/// chains, where one chain (say the upper) is a single edge, and
/// the other chain is concave. The left vertex of the single edge
/// is always to the left of all vertices in the concave chain.
///
/// Each step consists of adding the rightmost unprocessed vertex to one
/// of the two chains, and forming a fan of triangles from the rightmost
/// of two chain endpoints. Determining whether we can add each triangle
/// to the fan is a simple orientation test. By making the fan as large
/// as possible, we restore the invariant (check it yourself).
/// </summary>
private void TessellateMonoRegion(MeshUtils.Face face)
{
// All edges are oriented CCW around the boundary of the region.
// First, find the half-edge whose origin vertex is rightmost.
// Since the sweep goes from left to right, face->anEdge should
// be close to the edge we want.
var up = face._anEdge;
Debug.Assert(up._Lnext != up && up._Lnext._Lnext != up);
while (Geom.VertLeq(up._Dst, up._Org)) up = up._Lprev;
while (Geom.VertLeq(up._Org, up._Dst)) up = up._Lnext;
var lo = up._Lprev;
while (up._Lnext != lo)
{
if (Geom.VertLeq(up._Dst, lo._Org))
{
// up.Dst is on the left. It is safe to form triangles from lo.Org.
// The EdgeGoesLeft test guarantees progress even when some triangles
// are CW, given that the upper and lower chains are truly monotone.
while (lo._Lnext != up && (Geom.EdgeGoesLeft(lo._Lnext)
|| Geom.EdgeSign(lo._Org, lo._Dst, lo._Lnext._Dst) <= 0.0f))
{
lo = _mesh.Connect(lo._Lnext, lo)._Sym;
}
lo = lo._Lprev;
}
else
{
// lo.Org is on the left. We can make CCW triangles from up.Dst.
while (lo._Lnext != up && (Geom.EdgeGoesRight(up._Lprev)
|| Geom.EdgeSign(up._Dst, up._Org, up._Lprev._Org) >= 0.0f))
{
up = _mesh.Connect(up, up._Lprev)._Sym;
}
up = up._Lnext;
}
}
// Now lo.Org == up.Dst == the leftmost vertex. The remaining region
// can be tessellated in a fan from this leftmost vertex.
Debug.Assert(lo._Lnext != up);
while (lo._Lnext._Lnext != up)
{
lo = _mesh.Connect(lo._Lnext, lo)._Sym;
}
}
/// <summary>
/// TessellateInterior( mesh ) tessellates each region of
/// the mesh which is marked "inside" the polygon. Each such region
/// must be monotone.
/// </summary>
private void TessellateInterior()
{
MeshUtils.Face f, next;
for (f = _mesh._fHead._next; f != _mesh._fHead; f = next)
{
// Make sure we don't try to tessellate the new triangles.
next = f._next;
if (f._inside)
{
TessellateMonoRegion(f);
}
}
}
/// <summary>
/// DiscardExterior zaps (ie. sets to null) all faces
/// which are not marked "inside" the polygon. Since further mesh operations
/// on NULL faces are not allowed, the main purpose is to clean up the
/// mesh so that exterior loops are not represented in the data structure.
/// </summary>
private void DiscardExterior()
{
MeshUtils.Face f, next;
for (f = _mesh._fHead._next; f != _mesh._fHead; f = next)
{
// Since f will be destroyed, save its next pointer.
next = f._next;
if( ! f._inside ) {
_mesh.ZapFace(f);
}
}
}
/// <summary>
/// SetWindingNumber( value, keepOnlyBoundary ) resets the
/// winding numbers on all edges so that regions marked "inside" the
/// polygon have a winding number of "value", and regions outside
/// have a winding number of 0.
///
/// If keepOnlyBoundary is TRUE, it also deletes all edges which do not
/// separate an interior region from an exterior one.
/// </summary>
private void SetWindingNumber(int value, bool keepOnlyBoundary)
{
MeshUtils.Edge e, eNext;
for (e = _mesh._eHead._next; e != _mesh._eHead; e = eNext)
{
eNext = e._next;
if (e._Rface._inside != e._Lface._inside)
{
/* This is a boundary edge (one side is interior, one is exterior). */
e._winding = (e._Lface._inside) ? value : -value;
}
else
{
/* Both regions are interior, or both are exterior. */
if (!keepOnlyBoundary)
{
e._winding = 0;
}
else
{
_mesh.Delete(e);
}
}
}
}
private int GetNeighbourFace(MeshUtils.Edge edge)
{
if (edge._Rface == null)
return MeshUtils.Undef;
if (!edge._Rface._inside)
return MeshUtils.Undef;
return edge._Rface._n;
}
private void OutputPolymesh(ElementType elementType, int polySize)
{
MeshUtils.Vertex v;
MeshUtils.Face f;
MeshUtils.Edge edge;
int maxFaceCount = 0;
int maxVertexCount = 0;
int faceVerts, i;
if (polySize < 3)
{
polySize = 3;
}
// Assume that the input data is triangles now.
// Try to merge as many polygons as possible
if (polySize > 3)
{
_mesh.MergeConvexFaces(polySize);
}
// Mark unused
for (v = _mesh._vHead._next; v != _mesh._vHead; v = v._next)
v._n = MeshUtils.Undef;
// Create unique IDs for all vertices and faces.
for (f = _mesh._fHead._next; f != _mesh._fHead; f = f._next)
{
f._n = MeshUtils.Undef;
if (!f._inside) continue;
if (NoEmptyPolygons)
{
var area = MeshUtils.FaceArea(f);
if (Math.Abs(area) < Real.Epsilon)
{
continue;
}
}
edge = f._anEdge;
faceVerts = 0;
do {
v = edge._Org;
if (v._n == MeshUtils.Undef)
{
v._n = maxVertexCount;
maxVertexCount++;
}
faceVerts++;
edge = edge._Lnext;
}
while (edge != f._anEdge);
Debug.Assert(faceVerts <= polySize);
f._n = maxFaceCount;
++maxFaceCount;
}
_elementCount = maxFaceCount;
if (elementType == ElementType.ConnectedPolygons)
maxFaceCount *= 2;
_elements = new int[maxFaceCount * polySize];
_vertexCount = maxVertexCount;
_vertices = new ContourVertex[_vertexCount];
// Output vertices.
for (v = _mesh._vHead._next; v != _mesh._vHead; v = v._next)
{
if (v._n != MeshUtils.Undef)
{
// Store coordinate
_vertices[v._n].Position = v._coords;
_vertices[v._n].Data = v._data;
}
}
// Output indices.
int elementIndex = 0;
for (f = _mesh._fHead._next; f != _mesh._fHead; f = f._next)
{
if (!f._inside) continue;
if (NoEmptyPolygons)
{
var area = MeshUtils.FaceArea(f);
if (Math.Abs(area) < Real.Epsilon)
{
continue;
}
}
// Store polygon
edge = f._anEdge;
faceVerts = 0;
do {
v = edge._Org;
_elements[elementIndex++] = v._n;
faceVerts++;
edge = edge._Lnext;
} while (edge != f._anEdge);
// Fill unused.
for (i = faceVerts; i < polySize; ++i)
{
_elements[elementIndex++] = MeshUtils.Undef;
}
// Store polygon connectivity
if (elementType == ElementType.ConnectedPolygons)
{
edge = f._anEdge;
do
{
_elements[elementIndex++] = GetNeighbourFace(edge);
edge = edge._Lnext;
} while (edge != f._anEdge);
// Fill unused.
for (i = faceVerts; i < polySize; ++i)
{
_elements[elementIndex++] = MeshUtils.Undef;
}
}
}
}
private void OutputContours()
{
MeshUtils.Face f;
MeshUtils.Edge edge, start;
int startVert = 0;
int vertCount = 0;
_vertexCount = 0;
_elementCount = 0;
for (f = _mesh._fHead._next; f != _mesh._fHead; f = f._next)
{
if (!f._inside) continue;
start = edge = f._anEdge;
do
{
++_vertexCount;
edge = edge._Lnext;
}
while (edge != start);
++_elementCount;
}
_elements = new int[_elementCount * 2];
_vertices = new ContourVertex[_vertexCount];
int vertIndex = 0;
int elementIndex = 0;
startVert = 0;
for (f = _mesh._fHead._next; f != _mesh._fHead; f = f._next)
{
if (!f._inside) continue;
vertCount = 0;
start = edge = f._anEdge;
do {
_vertices[vertIndex].Position = edge._Org._coords;
_vertices[vertIndex].Data = edge._Org._data;
++vertIndex;
++vertCount;
edge = edge._Lnext;
} while (edge != start);
_elements[elementIndex++] = startVert;
_elements[elementIndex++] = vertCount;
startVert += vertCount;
}
}
private Real SignedArea(ContourVertex[] vertices)
{
Real area = 0.0f;
for (int i = 0; i < vertices.Length; i++)
{
var v0 = vertices[i];
var v1 = vertices[(i + 1) % vertices.Length];
area += v0.Position.X * v1.Position.Y;
area -= v0.Position.Y * v1.Position.X;
}
return 0.5f * area;
}
public void AddContour(ContourVertex[] vertices)
{
AddContour(vertices, ContourOrientation.Original);
}
public void AddContour(ContourVertex[] vertices, ContourOrientation forceOrientation)
{
if (_mesh == null)
{
_mesh = new Mesh();
}
bool reverse = false;
if (forceOrientation != ContourOrientation.Original)
{
var area = SignedArea(vertices);
reverse = (forceOrientation == ContourOrientation.Clockwise && area < 0.0f) || (forceOrientation == ContourOrientation.CounterClockwise && area > 0.0f);
}
MeshUtils.Edge e = null;
for (int i = 0; i < vertices.Length; ++i)
{
if (e == null)
{
e = _mesh.MakeEdge();
_mesh.Splice(e, e._Sym);
}
else
{
// Create a new vertex and edge which immediately follow e
// in the ordering around the left face.
_mesh.SplitEdge(e);
e = e._Lnext;
}
int index = reverse ? vertices.Length - 1 - i : i;
// The new vertex is now e._Org.
e._Org._coords = vertices[index].Position;
e._Org._data = vertices[index].Data;
// The winding of an edge says how the winding number changes as we
// cross from the edge's right face to its left face. We add the
// vertices in such an order that a CCW contour will add +1 to
// the winding number of the region inside the contour.
e._winding = 1;
e._Sym._winding = -1;
}
}
public void Tessellate(WindingRule windingRule, ElementType elementType, int polySize)
{
Tessellate(windingRule, elementType, polySize, null);
}
public void Tessellate(WindingRule windingRule, ElementType elementType, int polySize, CombineCallback combineCallback)
{
_normal = Vec3.Zero;
_vertices = null;
_elements = null;
_windingRule = windingRule;
_combineCallback = combineCallback;
if (_mesh == null)
{
return;
}
// Determine the polygon normal and project vertices onto the plane
// of the polygon.
ProjectPolygon();
// ComputeInterior computes the planar arrangement specified
// by the given contours, and further subdivides this arrangement
// into regions. Each region is marked "inside" if it belongs
// to the polygon, according to the rule given by windingRule.
// Each interior region is guaranteed be monotone.
ComputeInterior();
// If the user wants only the boundary contours, we throw away all edges
// except those which separate the interior from the exterior.
// Otherwise we tessellate all the regions marked "inside".
if (elementType == ElementType.BoundaryContours)
{
SetWindingNumber(1, true);
}
else
{
TessellateInterior();
}
_mesh.Check();
if (elementType == ElementType.BoundaryContours)
{
OutputContours();
}
else
{
OutputPolymesh(elementType, polySize);
}
if (UsePooling)
{
_mesh.Free();
}
_mesh = null;
}
}
}
} // namespace Unity.VectorGraphics.External

View file

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

View file

@ -0,0 +1,187 @@
using System;
using System.Collections.Generic;
namespace UnityEngine.U2D
{
[Serializable]
public class Spline
{
private static readonly string KErrorMessage = "Internal error: Point too close to neighbor";
private static readonly float KEpsilon = 0.01f;
[SerializeField]
private bool m_IsOpenEnded;
[SerializeField]
private List<SplineControlPoint> m_ControlPoints = new List<SplineControlPoint>();
public bool isOpenEnded
{
get
{
if (GetPointCount() < 3)
return true;
return m_IsOpenEnded;
}
set { m_IsOpenEnded = value; }
}
private bool IsPositionValid(int index, int next, Vector3 point)
{
int prev = (index == 0) ? (m_ControlPoints.Count - 1) : (index - 1);
next = (next >= m_ControlPoints.Count) ? 0 : next;
if (prev >= 0)
{
Vector3 diff = m_ControlPoints[prev].position - point;
if (diff.magnitude < KEpsilon)
return false;
}
if (next < m_ControlPoints.Count)
{
Vector3 diff = m_ControlPoints[next].position - point;
if (diff.magnitude < KEpsilon)
return false;
}
return true;
}
public void Clear()
{
m_ControlPoints.Clear();
}
public int GetPointCount()
{
return m_ControlPoints.Count;
}
public void InsertPointAt(int index, Vector3 point)
{
if (!IsPositionValid(index, index, point))
throw new ArgumentException(KErrorMessage);
m_ControlPoints.Insert(index, new SplineControlPoint { position = point, height = 1.0f, corner = true });
}
public void RemovePointAt(int index)
{
if (m_ControlPoints.Count > 2)
m_ControlPoints.RemoveAt(index);
}
public Vector3 GetPosition(int index)
{
return m_ControlPoints[index].position;
}
public void SetPosition(int index, Vector3 point)
{
if (!IsPositionValid(index, index + 1, point))
throw new ArgumentException(KErrorMessage);
SplineControlPoint newPoint = m_ControlPoints[index];
newPoint.position = point;
m_ControlPoints[index] = newPoint;
}
public Vector3 GetLeftTangent(int index)
{
ShapeTangentMode mode = GetTangentMode(index);
if (mode == ShapeTangentMode.Linear)
return Vector3.zero;
return m_ControlPoints[index].leftTangent;
}
public void SetLeftTangent(int index, Vector3 tangent)
{
ShapeTangentMode mode = GetTangentMode(index);
if (mode == ShapeTangentMode.Linear)
return;
SplineControlPoint newPoint = m_ControlPoints[index];
newPoint.leftTangent = tangent;
m_ControlPoints[index] = newPoint;
}
public Vector3 GetRightTangent(int index)
{
ShapeTangentMode mode = GetTangentMode(index);
if (mode == ShapeTangentMode.Linear)
return Vector3.zero;
return m_ControlPoints[index].rightTangent;
}
public void SetRightTangent(int index, Vector3 tangent)
{
ShapeTangentMode mode = GetTangentMode(index);
if (mode == ShapeTangentMode.Linear)
return;
SplineControlPoint newPoint = m_ControlPoints[index];
newPoint.rightTangent = tangent;
m_ControlPoints[index] = newPoint;
}
public ShapeTangentMode GetTangentMode(int index)
{
return m_ControlPoints[index].mode;
}
public void SetTangentMode(int index, ShapeTangentMode mode)
{
SplineControlPoint newPoint = m_ControlPoints[index];
newPoint.mode = mode;
m_ControlPoints[index] = newPoint;
}
public float GetHeight(int index)
{
return m_ControlPoints[index].height;
}
public void SetHeight(int index, float value)
{
m_ControlPoints[index].height = value;
}
public int GetSpriteIndex(int index)
{
return m_ControlPoints[index].spriteIndex;
}
public void SetSpriteIndex(int index, int value)
{
m_ControlPoints[index].spriteIndex = value;
}
public bool GetCorner(int index)
{
return m_ControlPoints[index].corner;
}
public void SetCorner(int index, bool value)
{
m_ControlPoints[index].corner = value;
}
public override int GetHashCode()
{
unchecked
{
int hashCode = (int)2166136261;
for (int i = 0; i < GetPointCount(); ++i)
{
hashCode = hashCode * 16777619 ^ m_ControlPoints[i].GetHashCode();
}
hashCode = hashCode * 16777619 ^ m_IsOpenEnded.GetHashCode();
return hashCode;
}
}
}
}

View file

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 42a84d2aa763148d78347ed13f78591c
timeCreated: 1503764436
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,85 @@
using System;
using Unity.Collections;
using System.Runtime.InteropServices;
using Unity.Collections.LowLevel.Unsafe;
namespace UnityEngine.U2D
{
public class SplineUtility
{
public static float SlopeAngle(Vector2 start, Vector2 end)
{
Vector2 dir = start - end;
dir.Normalize();
Vector2 dvup = new Vector2(0, 1f);
Vector2 dvrt = new Vector2(1f, 0);
float dr = Vector2.Dot(dir, dvrt);
float du = Vector2.Dot(dir, dvup);
float cu = Mathf.Acos(du);
float sn = dr >= 0 ? 1.0f : -1.0f;
float an = cu * Mathf.Rad2Deg * sn;
// Adjust angles when direction is parallel to Up Axis.
an = (du != 1f) ? an : 0;
an = (du != -1f) ? an : -180f;
return an;
}
public static void CalculateTangents(Vector3 point, Vector3 prevPoint, Vector3 nextPoint, Vector3 forward, float scale, out Vector3 rightTangent, out Vector3 leftTangent)
{
Vector3 v1 = (prevPoint - point).normalized;
Vector3 v2 = (nextPoint - point).normalized;
Vector3 v3 = v1 + v2;
Vector3 cross = forward;
if (prevPoint != nextPoint)
{
bool colinear = 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) < 0.01f;
if (colinear)
{
rightTangent = v2 * scale;
leftTangent = v1 * scale;
return;
}
cross = Vector3.Cross(v1, v2);
}
rightTangent = Vector3.Cross(cross, v3).normalized * scale;
leftTangent = -rightTangent;
}
public static int NextIndex(int index, int pointCount)
{
return Mod(index + 1, pointCount);
}
public static int PreviousIndex(int index, int pointCount)
{
return Mod(index - 1, pointCount);
}
private static int Mod(int x, int m)
{
int r = x % m;
return r < 0 ? r + m : r;
}
}
// Copy utility.
internal class SpriteShapeCopyUtility<T> where T : struct
{
internal static void Copy(NativeSlice<T> dst, T[] src, int length)
{
NativeSlice<T> dstSet = new NativeSlice<T>(dst, 0, length);
dstSet.CopyFrom(src);
}
internal static void Copy(T[] dst, NativeSlice<T> src, int length)
{
NativeSlice<T> dstSet = new NativeSlice<T>(src, 0, length);
dstSet.CopyTo(dst);
}
}
}

View file

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 97cd8ab4fa1413646be1291760a3bddd
timeCreated: 1505804231
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,310 @@
using System;
using System.Collections.Generic;
namespace UnityEngine.U2D
{
public enum ShapeTangentMode
{
Linear = 0,
Continuous = 1,
Broken = 2,
};
public enum CornerType
{
OuterTopLeft,
OuterTopRight,
OuterBottomLeft,
OuterBottomRight,
InnerTopLeft,
InnerTopRight,
InnerBottomLeft,
InnerBottomRight,
};
public enum QualityDetail
{
High = 16,
Mid = 8,
Low = 4
}
[System.Serializable]
public class SplineControlPoint
{
public Vector3 position;
public Vector3 leftTangent;
public Vector3 rightTangent;
public ShapeTangentMode mode;
public float height = 1f;
public float bevelCutoff;
public float bevelSize;
public int spriteIndex;
public bool corner;
public override int GetHashCode()
{
return ((int)position.x).GetHashCode() ^ ((int)position.y).GetHashCode() ^ position.GetHashCode() ^
(leftTangent.GetHashCode() << 2) ^ (rightTangent.GetHashCode() >> 2) ^ ((int)mode).GetHashCode() ^
height.GetHashCode() ^ spriteIndex.GetHashCode() ^ corner.GetHashCode();
}
}
[System.Serializable]
public class AngleRange : ICloneable
{
public float start
{
get { return m_Start; }
set { m_Start = value; }
}
public float end
{
get { return m_End; }
set { m_End = value; }
}
public int order
{
get { return m_Order; }
set { m_Order = value; }
}
public List<Sprite> sprites
{
get { return m_Sprites; }
set { m_Sprites = value; }
}
[SerializeField]
float m_Start;
[SerializeField]
float m_End;
[SerializeField]
int m_Order;
[SerializeField]
List<Sprite> m_Sprites = new List<Sprite>();
public object Clone()
{
AngleRange clone = this.MemberwiseClone() as AngleRange;
clone.sprites = new List<Sprite>(clone.sprites);
return clone;
}
public override bool Equals(object obj)
{
var other = obj as AngleRange;
if (other == null)
return false;
bool equals = start.Equals(other.start) && end.Equals(other.end) && order.Equals(other.order);
if (!equals)
return false;
if (sprites.Count != other.sprites.Count)
return false;
for (int i = 0; i < sprites.Count; ++i)
if (sprites[i] != other.sprites[i])
return false;
return true;
}
public override int GetHashCode()
{
int hashCode = start.GetHashCode() ^ end.GetHashCode() ^ order.GetHashCode();
if (sprites != null)
{
for (int i = 0; i < sprites.Count; i++)
{
Sprite sprite = sprites[i];
if (sprite)
hashCode = hashCode * 16777619 ^ (sprite.GetHashCode() + i);
}
}
return hashCode;
}
}
[System.Serializable]
public class CornerSprite : ICloneable
{
public CornerType cornerType
{
get { return m_CornerType; }
set { m_CornerType = value; }
}
public List<Sprite> sprites
{
get { return m_Sprites; }
set { m_Sprites = value; }
}
[SerializeField]
CornerType m_CornerType; ///< Set Corner type. enum { OuterTopLeft = 0, OuterTopRight = 1, OuterBottomLeft = 2, OuterBottomRight = 3, InnerTopLeft = 4, InnerTopRight = 5, InnerBottomLeft = 6, InnerBottomRight = 7 }
[SerializeField]
List<Sprite> m_Sprites;
public object Clone()
{
CornerSprite clone = this.MemberwiseClone() as CornerSprite;
clone.sprites = new List<Sprite>(clone.sprites);
return clone;
}
public override bool Equals(object obj)
{
var other = obj as CornerSprite;
if (other == null)
return false;
if (!cornerType.Equals(other.cornerType))
return false;
if (sprites.Count != other.sprites.Count)
return false;
for (int i = 0; i < sprites.Count; ++i)
if (sprites[i] != other.sprites[i])
return false;
return true;
}
public override int GetHashCode()
{
int hashCode = cornerType.GetHashCode();
if (sprites != null)
{
for (int i = 0; i < sprites.Count; i++)
{
Sprite sprite = sprites[i];
if (sprite)
{
hashCode ^= (i + 1);
hashCode ^= sprite.GetHashCode();
}
}
}
return hashCode;
}
}
[HelpURLAttribute("https://docs.unity3d.com/Packages/com.unity.2d.spriteshape@latest/index.html?subfolder=/manual/SSProfile.html")]
public class SpriteShape : ScriptableObject
{
public List<AngleRange> angleRanges
{
get { return m_Angles; }
set { m_Angles = value; }
}
public Texture2D fillTexture
{
get { return m_FillTexture; }
set { m_FillTexture = value; }
}
public List<CornerSprite> cornerSprites
{
get { return m_CornerSprites; }
set { m_CornerSprites = value; }
}
public float fillOffset
{
get { return m_FillOffset; }
set { m_FillOffset = value; }
}
public bool useSpriteBorders
{
get { return m_UseSpriteBorders; }
set { m_UseSpriteBorders = value; }
}
[SerializeField]
List<AngleRange> m_Angles = new List<AngleRange>();
[SerializeField]
Texture2D m_FillTexture;
[SerializeField]
List<CornerSprite> m_CornerSprites = new List<CornerSprite>();
[SerializeField]
float m_FillOffset;
[SerializeField]
bool m_UseSpriteBorders = true;
private CornerSprite GetCornerSprite(CornerType cornerType)
{
var cornerSprite = new CornerSprite();
cornerSprite.cornerType = cornerType;
cornerSprite.sprites = new List<Sprite>();
cornerSprite.sprites.Insert(0, null);
return cornerSprite;
}
void ResetCornerList()
{
m_CornerSprites.Insert(0, GetCornerSprite(CornerType.OuterTopLeft));
m_CornerSprites.Insert(1, GetCornerSprite(CornerType.OuterTopRight));
m_CornerSprites.Insert(2, GetCornerSprite(CornerType.OuterBottomLeft));
m_CornerSprites.Insert(3, GetCornerSprite(CornerType.OuterBottomRight));
m_CornerSprites.Insert(4, GetCornerSprite(CornerType.InnerTopLeft));
m_CornerSprites.Insert(5, GetCornerSprite(CornerType.InnerTopRight));
m_CornerSprites.Insert(6, GetCornerSprite(CornerType.InnerBottomLeft));
m_CornerSprites.Insert(7, GetCornerSprite(CornerType.InnerBottomRight));
}
void OnValidate()
{
if (m_CornerSprites.Count != 8)
ResetCornerList();
}
void Reset()
{
ResetCornerList();
}
internal static int GetSpriteShapeHashCode(SpriteShape spriteShape)
{
// useSpriteBorders, fillOffset and fillTexture are hashChecked elsewhere.
unchecked
{
int hashCode = (int)2166136261;
hashCode = hashCode * 16777619 ^ spriteShape.angleRanges.Count;
for (int i = 0; i < spriteShape.angleRanges.Count; ++i)
{
hashCode = hashCode * 16777619 ^ (spriteShape.angleRanges[i].GetHashCode() + i);
}
hashCode = hashCode * 16777619 ^ spriteShape.cornerSprites.Count;
for (int i = 0; i < spriteShape.cornerSprites.Count; ++i)
{
hashCode = hashCode * 16777619 ^ (spriteShape.cornerSprites[i].GetHashCode() + i);
}
return hashCode;
}
}
}
}

View file

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: af7181f404f1447c0a7a17b3070b952b
timeCreated: 1505457510
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: 0a9a0f36a52ce7f4d813fbf5d8f76a1c, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -0,0 +1,801 @@
using System.Collections.Generic;
using Unity.Jobs;
using Unity.Collections;
using Unity.Mathematics;
using Unity.Collections.LowLevel.Unsafe;
#if UNITY_EDITOR
using UnityEditor.U2D;
#endif
namespace UnityEngine.U2D
{
[ExecuteInEditMode]
[RequireComponent(typeof(SpriteShapeRenderer))]
[DisallowMultipleComponent]
[HelpURLAttribute("https://docs.unity3d.com/Packages/com.unity.2d.spriteshape@latest/index.html?subfolder=/manual/SSController.html")]
public class SpriteShapeController : MonoBehaviour
{
// Internal Dataset.
const float s_DistanceTolerance = 0.001f;
// Cached Objects.
SpriteShape m_ActiveSpriteShape;
EdgeCollider2D m_EdgeCollider2D;
PolygonCollider2D m_PolygonCollider2D;
SpriteShapeRenderer m_SpriteShapeRenderer;
SpriteShapeGeometryCache m_SpriteShapeGeometryCache;
Sprite[] m_SpriteArray = new Sprite[0];
Sprite[] m_EdgeSpriteArray = new Sprite[0];
Sprite[] m_CornerSpriteArray = new Sprite[0];
AngleRangeInfo[] m_AngleRangeInfoArray = new AngleRangeInfo[0];
// Required for Generation.
NativeArray<float2> m_ColliderData;
NativeArray<Vector4> m_TangentData;
// Renderer Stuff.
bool m_DynamicOcclusionLocal;
bool m_DynamicOcclusionOverriden;
// Hash Check.
int m_ActiveSplineHash = 0;
int m_ActiveSpriteShapeHash = 0;
SpriteShapeParameters m_ActiveShapeParameters;
// Serialized Data.
[SerializeField]
Spline m_Spline = new Spline();
[SerializeField]
SpriteShape m_SpriteShape;
[SerializeField]
float m_FillPixelPerUnit = 100.0f;
[SerializeField]
float m_StretchTiling = 1.0f;
[SerializeField]
int m_SplineDetail;
[SerializeField]
bool m_AdaptiveUV;
[SerializeField]
bool m_StretchUV;
[SerializeField]
bool m_WorldSpaceUV;
[SerializeField]
float m_CornerAngleThreshold = 30.0f;
[SerializeField]
int m_ColliderDetail;
[SerializeField, Range(-0.5f, 0.5f)]
float m_ColliderOffset;
[SerializeField]
bool m_UpdateCollider = true;
[SerializeField]
bool m_OptimizeCollider = true;
[SerializeField]
bool m_OptimizeGeometry = true;
[SerializeField]
bool m_EnableTangents = false;
[SerializeField]
[HideInInspector]
bool m_GeometryCached = false;
#region GetSet
internal bool geometryCached
{
get { return m_GeometryCached; }
}
internal int splineHashCode
{
get { return m_ActiveSplineHash; }
}
internal Sprite[] spriteArray
{
get { return m_SpriteArray; }
}
internal SpriteShapeParameters spriteShapeParameters
{
get { return m_ActiveShapeParameters; }
}
internal SpriteShapeGeometryCache spriteShapeGeometryCache
{
get
{
if (!m_SpriteShapeGeometryCache)
m_SpriteShapeGeometryCache = GetComponent<SpriteShapeGeometryCache>();
return m_SpriteShapeGeometryCache;
}
}
public int spriteShapeHashCode
{
get { return m_ActiveSpriteShapeHash; }
}
public bool worldSpaceUVs
{
get { return m_WorldSpaceUV; }
set { m_WorldSpaceUV = value; }
}
public float fillPixelsPerUnit
{
get { return m_FillPixelPerUnit; }
set { m_FillPixelPerUnit = value; }
}
public bool enableTangents
{
get { return m_EnableTangents; }
set { m_EnableTangents = value; }
}
public float stretchTiling
{
get { return m_StretchTiling; }
set { m_StretchTiling = value; }
}
public int splineDetail
{
get { return m_SplineDetail; }
set { m_SplineDetail = Mathf.Max(0, value); }
}
public int colliderDetail
{
get { return m_ColliderDetail; }
set { m_ColliderDetail = Mathf.Max(0, value); }
}
public float colliderOffset
{
get { return m_ColliderOffset; }
set { m_ColliderOffset = value; }
}
public float cornerAngleThreshold
{
get { return m_CornerAngleThreshold; }
set { m_CornerAngleThreshold = value; }
}
public bool autoUpdateCollider
{
get { return m_UpdateCollider; }
set { m_UpdateCollider = value; }
}
public bool optimizeCollider
{
get { return m_OptimizeCollider; }
}
public bool optimizeGeometry
{
get { return m_OptimizeGeometry; }
}
public bool hasCollider
{
get { return (edgeCollider != null) || (polygonCollider != null); }
}
public Spline spline
{
get { return m_Spline; }
}
public SpriteShape spriteShape
{
get { return m_SpriteShape; }
set { m_SpriteShape = value; }
}
public EdgeCollider2D edgeCollider
{
get
{
if (!m_EdgeCollider2D)
m_EdgeCollider2D = GetComponent<EdgeCollider2D>();
return m_EdgeCollider2D;
}
}
public PolygonCollider2D polygonCollider
{
get
{
if (!m_PolygonCollider2D)
m_PolygonCollider2D = GetComponent<PolygonCollider2D>();
return m_PolygonCollider2D;
}
}
public SpriteShapeRenderer spriteShapeRenderer
{
get
{
if (!m_SpriteShapeRenderer)
m_SpriteShapeRenderer = GetComponent<SpriteShapeRenderer>();
return m_SpriteShapeRenderer;
}
}
#endregion
#region EventHandles.
void DisposeInternal()
{
if (m_ColliderData.IsCreated)
m_ColliderData.Dispose();
if (m_TangentData.IsCreated)
m_TangentData.Dispose();
}
void OnApplicationQuit()
{
DisposeInternal();
}
void OnEnable()
{
spriteShapeRenderer.enabled = true;
m_DynamicOcclusionOverriden = true;
m_DynamicOcclusionLocal = spriteShapeRenderer.allowOcclusionWhenDynamic;
spriteShapeRenderer.allowOcclusionWhenDynamic = false;
UpdateSpriteData();
}
void OnDisable()
{
spriteShapeRenderer.enabled = false;
DisposeInternal();
}
void OnDestroy()
{
}
void Reset()
{
m_SplineDetail = (int)QualityDetail.High;
m_AdaptiveUV = true;
m_StretchUV = false;
m_FillPixelPerUnit = 100f;
m_ColliderDetail = (int)QualityDetail.High;
m_StretchTiling = 1.0f;
m_WorldSpaceUV = false;
m_CornerAngleThreshold = 30.0f;
m_ColliderOffset = 0;
m_UpdateCollider = true;
m_OptimizeCollider = true;
m_OptimizeGeometry = true;
m_EnableTangents = false;
spline.Clear();
spline.InsertPointAt(0, Vector2.left + Vector2.down);
spline.InsertPointAt(1, Vector2.left + Vector2.up);
spline.InsertPointAt(2, Vector2.right + Vector2.up);
spline.InsertPointAt(3, Vector2.right + Vector2.down);
}
static void SmartDestroy(UnityEngine.Object o)
{
if (o == null)
return;
#if UNITY_EDITOR
if (!Application.isPlaying)
DestroyImmediate(o);
else
#endif
Destroy(o);
}
#endregion
#region HashAndDataCheck
public void RefreshSpriteShape()
{
m_ActiveSplineHash = 0;
}
// Ensure Neighbor points are not too close to each other.
bool ValidateSpline()
{
int pointCount = spline.GetPointCount();
if (pointCount < 2)
return false;
for (int i = 0; i < pointCount - 1; ++i)
{
var vec = spline.GetPosition(i) - spline.GetPosition(i + 1);
if (vec.sqrMagnitude < s_DistanceTolerance)
{
Debug.LogWarningFormat(gameObject, "[SpriteShape] Control points {0} & {1} are too close. SpriteShape will not be generated for < {2} >.", i, i + 1, gameObject.name);
return false;
}
}
return true;
}
// Ensure SpriteShape is valid if not
bool ValidateSpriteShapeTexture()
{
bool valid = false;
// Check if SpriteShape Profile is valid.
if (spriteShape != null)
{
// Open ended and no valid Sprites set. Check if it has a valid fill texture.
if (!spline.isOpenEnded)
{
valid = (spriteShape.fillTexture != null);
}
}
else
{
// Warn that no SpriteShape is set.
Debug.LogWarningFormat(gameObject, "[SpriteShape] A valid SpriteShape profile has not been set for gameObject < {0} >.", gameObject.name);
}
#if UNITY_EDITOR
// We allow null SpriteShape for rapid prototyping in Editor.
valid = true;
#endif
return valid;
}
bool HasSpriteShapeChanged()
{
bool changed = (m_ActiveSpriteShape != spriteShape);
if (changed)
m_ActiveSpriteShape = spriteShape;
return changed;
}
bool HasSpriteShapeDataChanged()
{
bool updateSprites = HasSpriteShapeChanged();
if (spriteShape)
{
var hashCode = SpriteShape.GetSpriteShapeHashCode(spriteShape);
if (spriteShapeHashCode != hashCode)
{
m_ActiveSpriteShapeHash = hashCode;
updateSprites = true;
}
}
return updateSprites;
}
bool HasSplineDataChanged()
{
unchecked
{
// Spline.
int hashCode = (int)2166136261 ^ spline.GetHashCode();
// Local Stuff.
hashCode = hashCode * 16777619 ^ (m_WorldSpaceUV ? 1 : 0);
hashCode = hashCode * 16777619 ^ (m_EnableTangents ? 1 : 0);
hashCode = hashCode * 16777619 ^ (m_GeometryCached ? 1 : 0);
hashCode = hashCode * 16777619 ^ (m_OptimizeGeometry ? 1 : 0);
hashCode = hashCode * 16777619 ^ (m_StretchTiling.GetHashCode());
hashCode = hashCode * 16777619 ^ (m_ColliderOffset.GetHashCode());
hashCode = hashCode * 16777619 ^ (m_ColliderDetail.GetHashCode());
if (splineHashCode != hashCode)
{
m_ActiveSplineHash = hashCode;
return true;
}
}
return false;
}
void OnWillRenderObject()
{
BakeCollider();
BakeMesh();
}
public JobHandle BakeMesh()
{
JobHandle jobHandle = default;
#if !UNITY_EDITOR
if (spriteShapeGeometryCache)
{
// If SpriteShapeGeometry has already been uploaded, don't bother checking further.
if (0 != spriteShapeGeometryCache.maxArrayCount && 0 != m_ActiveSplineHash)
return jobHandle;
}
#endif
bool valid = ValidateSpline();
if (valid)
{
bool splineChanged = HasSplineDataChanged();
bool spriteShapeChanged = HasSpriteShapeDataChanged();
bool spriteShapeParametersChanged = UpdateSpriteShapeParameters();
if (spriteShapeChanged)
{
UpdateSpriteData();
}
if (splineChanged || spriteShapeChanged || spriteShapeParametersChanged)
{
jobHandle = ScheduleBake();
}
}
return jobHandle;
}
#endregion
#region UpdateData
public bool UpdateSpriteShapeParameters()
{
bool carpet = !spline.isOpenEnded;
bool smartSprite = true;
bool adaptiveUV = m_AdaptiveUV;
bool stretchUV = m_StretchUV;
bool spriteBorders = false;
uint fillScale = 0;
uint splineDetail = (uint)m_SplineDetail;
float borderPivot = 0f;
float angleThreshold = (m_CornerAngleThreshold >= 0 && m_CornerAngleThreshold < 90) ? m_CornerAngleThreshold : 89.9999f;
Texture2D fillTexture = null;
Matrix4x4 transformMatrix = Matrix4x4.identity;
if (spriteShape)
{
if (worldSpaceUVs)
transformMatrix = transform.localToWorldMatrix;
fillTexture = spriteShape.fillTexture;
fillScale = stretchUV ? (uint)stretchTiling : (uint)fillPixelsPerUnit;
borderPivot = spriteShape.fillOffset;
spriteBorders = spriteShape.useSpriteBorders;
// If Corners are enabled, set smart-sprite to false.
if (spriteShape.cornerSprites.Count > 0)
smartSprite = false;
}
else
{
#if UNITY_EDITOR
fillTexture = UnityEditor.EditorGUIUtility.whiteTexture;
fillScale = 100;
#endif
}
bool changed = m_ActiveShapeParameters.adaptiveUV != adaptiveUV ||
m_ActiveShapeParameters.angleThreshold != angleThreshold ||
m_ActiveShapeParameters.borderPivot != borderPivot ||
m_ActiveShapeParameters.carpet != carpet ||
m_ActiveShapeParameters.fillScale != fillScale ||
m_ActiveShapeParameters.fillTexture != fillTexture ||
m_ActiveShapeParameters.smartSprite != smartSprite ||
m_ActiveShapeParameters.splineDetail != splineDetail ||
m_ActiveShapeParameters.spriteBorders != spriteBorders ||
m_ActiveShapeParameters.transform != transformMatrix ||
m_ActiveShapeParameters.stretchUV != stretchUV;
m_ActiveShapeParameters.adaptiveUV = adaptiveUV;
m_ActiveShapeParameters.stretchUV = stretchUV;
m_ActiveShapeParameters.angleThreshold = angleThreshold;
m_ActiveShapeParameters.borderPivot = borderPivot;
m_ActiveShapeParameters.carpet = carpet;
m_ActiveShapeParameters.fillScale = fillScale;
m_ActiveShapeParameters.fillTexture = fillTexture;
m_ActiveShapeParameters.smartSprite = smartSprite;
m_ActiveShapeParameters.splineDetail = splineDetail;
m_ActiveShapeParameters.spriteBorders = spriteBorders;
m_ActiveShapeParameters.transform = transformMatrix;
return changed;
}
void UpdateSpriteData()
{
if (spriteShape)
{
List<Sprite> edgeSpriteList = new List<Sprite>();
List<Sprite> cornerSpriteList = new List<Sprite>();
List<AngleRangeInfo> angleRangeInfoList = new List<AngleRangeInfo>();
List<AngleRange> sortedAngleRanges = new List<AngleRange>(spriteShape.angleRanges);
sortedAngleRanges.Sort((a, b) => a.order.CompareTo(b.order));
for (int i = 0; i < sortedAngleRanges.Count; i++)
{
bool validSpritesFound = false;
AngleRange angleRange = sortedAngleRanges[i];
foreach (Sprite edgeSprite in angleRange.sprites)
{
if (edgeSprite != null)
{
validSpritesFound = true;
break;
}
}
if (validSpritesFound)
{
AngleRangeInfo angleRangeInfo = new AngleRangeInfo();
angleRangeInfo.start = angleRange.start;
angleRangeInfo.end = angleRange.end;
angleRangeInfo.order = (uint)angleRange.order;
List<int> spriteIndices = new List<int>();
foreach (Sprite edgeSprite in angleRange.sprites)
{
edgeSpriteList.Add(edgeSprite);
spriteIndices.Add(edgeSpriteList.Count - 1);
}
angleRangeInfo.sprites = spriteIndices.ToArray();
angleRangeInfoList.Add(angleRangeInfo);
}
}
bool validCornerSpritesFound = false;
foreach (CornerSprite cornerSprite in spriteShape.cornerSprites)
{
if (cornerSprite.sprites[0] != null)
{
validCornerSpritesFound = true;
break;
}
}
if (validCornerSpritesFound)
{
for (int i = 0; i < spriteShape.cornerSprites.Count; i++)
{
CornerSprite cornerSprite = spriteShape.cornerSprites[i];
cornerSpriteList.Add(cornerSprite.sprites[0]);
}
}
m_EdgeSpriteArray = edgeSpriteList.ToArray();
m_CornerSpriteArray = cornerSpriteList.ToArray();
m_AngleRangeInfoArray = angleRangeInfoList.ToArray();
List<Sprite> spriteList = new List<Sprite>();
spriteList.AddRange(m_EdgeSpriteArray);
spriteList.AddRange(m_CornerSpriteArray);
m_SpriteArray = spriteList.ToArray();
}
else
{
m_SpriteArray = new Sprite[0];
m_EdgeSpriteArray = new Sprite[0];
m_CornerSpriteArray = new Sprite[0];
m_AngleRangeInfoArray = new AngleRangeInfo[0];
}
}
NativeArray<ShapeControlPoint> GetShapeControlPoints()
{
int pointCount = spline.GetPointCount();
NativeArray<ShapeControlPoint> shapePoints = new NativeArray<ShapeControlPoint>(pointCount, Allocator.Temp);
for (int i = 0; i < pointCount; ++i)
{
ShapeControlPoint shapeControlPoint;
shapeControlPoint.position = spline.GetPosition(i);
shapeControlPoint.leftTangent = spline.GetLeftTangent(i);
shapeControlPoint.rightTangent = spline.GetRightTangent(i);
shapeControlPoint.mode = (int)spline.GetTangentMode(i);
shapePoints[i] = shapeControlPoint;
}
return shapePoints;
}
NativeArray<SpriteShapeMetaData> GetSpriteShapeMetaData()
{
int pointCount = spline.GetPointCount();
NativeArray<SpriteShapeMetaData> shapeMetaData = new NativeArray<SpriteShapeMetaData>(pointCount, Allocator.Temp);
for (int i = 0; i < pointCount; ++i)
{
SpriteShapeMetaData metaData = shapeMetaData[i];
metaData.height = m_Spline.GetHeight(i);
metaData.spriteIndex = (uint)m_Spline.GetSpriteIndex(i);
metaData.corner = m_Spline.GetCorner(i);
shapeMetaData[i] = metaData;
}
return shapeMetaData;
}
int CalculateMaxArrayCount(NativeArray<ShapeControlPoint> shapePoints)
{
bool hasSprites = false;
float smallestWidth = 99999.0f;
if (null != spriteArray)
{
foreach (var sprite in m_SpriteArray)
{
if (sprite != null)
{
hasSprites = true;
float pixelWidth = BezierUtility.GetSpritePixelWidth(sprite);
smallestWidth = (smallestWidth > pixelWidth) ? pixelWidth : smallestWidth;
}
}
}
// Approximate vertex Array Count.
float shapeLength = BezierUtility.BezierLength(shapePoints, splineDetail * splineDetail) * 2.0f;
int adjustWidth = hasSprites ? ((int)(shapeLength / smallestWidth) * 6) + (shapePoints.Length * 6 * splineDetail) : 0;
int adjustShape = shapePoints.Length * 4 * splineDetail;
adjustShape = optimizeGeometry ? (adjustShape) : (adjustShape * 2);
var validFT = ValidateSpriteShapeTexture();
#if !UNITY_EDITOR
adjustShape = validFT ? adjustShape : 0;
#endif
int maxArrayCount = adjustShape + adjustWidth;
return maxArrayCount;
}
#endregion
unsafe JobHandle ScheduleBake()
{
JobHandle jobHandle = default;
bool staticUpload = Application.isPlaying;
#if !UNITY_EDITOR
staticUpload = true;
#endif
if (staticUpload && geometryCached)
{
if (spriteShapeGeometryCache)
if (spriteShapeGeometryCache.maxArrayCount != 0)
return spriteShapeGeometryCache.Upload(spriteShapeRenderer, this);
}
int pointCount = spline.GetPointCount();
NativeArray<ShapeControlPoint> shapePoints = GetShapeControlPoints();
NativeArray<SpriteShapeMetaData> shapeMetaData = GetSpriteShapeMetaData();
int maxArrayCount = CalculateMaxArrayCount(shapePoints);
if (maxArrayCount > 0 && enabled)
{
// Collider Data
if (m_ColliderData.IsCreated)
m_ColliderData.Dispose();
m_ColliderData = new NativeArray<float2>(maxArrayCount, Allocator.Persistent);
// Tangent Data
if (!m_TangentData.IsCreated)
m_TangentData = new NativeArray<Vector4>(1, Allocator.Persistent);
NativeArray<ushort> indexArray;
NativeSlice<Vector3> posArray;
NativeSlice<Vector2> uv0Array;
NativeArray<Bounds> bounds = spriteShapeRenderer.GetBounds();
NativeArray<SpriteShapeSegment> geomArray = spriteShapeRenderer.GetSegments(shapePoints.Length * 8);
NativeSlice<Vector4> tanArray = new NativeSlice<Vector4>(m_TangentData);
if (m_EnableTangents)
{
spriteShapeRenderer.GetChannels(maxArrayCount, out indexArray, out posArray, out uv0Array, out tanArray);
}
else
{
spriteShapeRenderer.GetChannels(maxArrayCount, out indexArray, out posArray, out uv0Array);
}
var spriteShapeJob = new SpriteShapeGenerator() { m_Bounds = bounds, m_PosArray = posArray, m_Uv0Array = uv0Array, m_TanArray = tanArray, m_GeomArray = geomArray, m_IndexArray = indexArray, m_ColliderPoints = m_ColliderData };
spriteShapeJob.Prepare(this, m_ActiveShapeParameters, maxArrayCount, shapePoints, shapeMetaData, m_AngleRangeInfoArray, m_EdgeSpriteArray, m_CornerSpriteArray);
jobHandle = spriteShapeJob.Schedule();
spriteShapeRenderer.Prepare(jobHandle, m_ActiveShapeParameters, m_SpriteArray);
#if UNITY_EDITOR
if (spriteShapeGeometryCache && geometryCached)
spriteShapeGeometryCache.SetGeometryCache(maxArrayCount, posArray, uv0Array, tanArray, indexArray, geomArray);
#endif
JobHandle.ScheduleBatchedJobs();
}
if (m_DynamicOcclusionOverriden)
{
spriteShapeRenderer.allowOcclusionWhenDynamic = m_DynamicOcclusionLocal;
m_DynamicOcclusionOverriden = false;
}
shapePoints.Dispose();
shapeMetaData.Dispose();
return jobHandle;
}
public void BakeCollider()
{
if (m_ColliderData.IsCreated)
{
if (autoUpdateCollider)
{
if (hasCollider)
{
int maxCount = short.MaxValue - 1;
float2 last = (float2)0;
List<Vector2> m_ColliderSegment = new List<Vector2>();
for (int i = 0; i < maxCount; ++i)
{
float2 now = m_ColliderData[i];
if (!math.any(last) && !math.any(now))
break;
m_ColliderSegment.Add(new Vector2(now.x, now.y));
}
if (edgeCollider != null)
edgeCollider.points = m_ColliderSegment.ToArray();
if (polygonCollider != null)
polygonCollider.points = m_ColliderSegment.ToArray();
}
}
// Dispose Collider as its no longer needed.
m_ColliderData.Dispose();
#if UNITY_EDITOR
if (UnityEditor.SceneView.lastActiveSceneView != null)
UnityEditor.SceneView.lastActiveSceneView.Repaint();
#endif
}
}
internal void BakeMeshForced()
{
if (spriteShapeRenderer != null)
{
var hasSplineChanged = HasSplineDataChanged();
if (!spriteShapeRenderer.isVisible && hasSplineChanged)
{
BakeMesh();
Rendering.CommandBuffer rc = new Rendering.CommandBuffer();
rc.GetTemporaryRT(0, 256, 256, 0);
rc.SetRenderTarget(0);
rc.DrawRenderer(spriteShapeRenderer, spriteShapeRenderer.sharedMaterial);
rc.ReleaseTemporaryRT(0);
Graphics.ExecuteCommandBuffer(rc);
}
}
}
Texture2D GetTextureFromIndex(int index)
{
if (index == 0)
return spriteShape ? spriteShape.fillTexture : null;
--index;
if (index < m_EdgeSpriteArray.Length)
return GetSpriteTexture(m_EdgeSpriteArray[index]);
index -= m_EdgeSpriteArray.Length;
return GetSpriteTexture(m_CornerSpriteArray[index]);
}
Texture2D GetSpriteTexture(Sprite sprite)
{
if (sprite)
{
#if UNITY_EDITOR
return UnityEditor.Sprites.SpriteUtility.GetSpriteTexture(sprite, sprite.packed);
#else
return sprite.texture;
#endif
}
return null;
}
}
}

View file

@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 90539df1cd5704abcb25fec9f3f5f84b
timeCreated: 1505457548
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {fileID: 2800000, guid: d1508e1dc42abb745b24c8891a614d2a, type: 3}
userData:
assetBundleName:
assetBundleVariant:

View file

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

View file

@ -0,0 +1,155 @@
using System;
using Unity.Jobs;
using UnityEngine;
using UnityEngine.U2D;
using Unity.Collections;
[Serializable]
internal struct SpriteShapeGeometryInfo
{
[SerializeField]
internal int geomIndex;
[SerializeField]
internal int indexCount;
[SerializeField]
internal int vertexCount;
[SerializeField]
internal int spriteIndex;
}
// Simple Cache for SpriteShape Geometry Data.
[AddComponentMenu("")]
internal class SpriteShapeGeometryCache : MonoBehaviour
{
// Serialized Data.
[SerializeField]
[HideInInspector]
int m_MaxArrayCount;
[SerializeField]
[HideInInspector]
Vector3[] m_PosArray = null;
[SerializeField]
[HideInInspector]
Vector2[] m_Uv0Array = null;
[SerializeField]
[HideInInspector]
Vector4[] m_TanArray = null;
[SerializeField]
[HideInInspector]
ushort[] m_IndexArray = null;
[SerializeField]
[HideInInspector]
SpriteShapeGeometryInfo[] m_GeomArray = null;
// Update set.
bool m_RequiresUpdate = false;
bool m_RequiresUpload = false;
NativeSlice<Vector3> m_PosArrayCache;
NativeSlice<Vector2> m_Uv0ArrayCache;
NativeSlice<Vector4> m_TanArrayCache;
NativeArray<ushort> m_IndexArrayCache;
NativeArray<UnityEngine.U2D.SpriteShapeSegment> m_GeomArrayCache;
internal int maxArrayCount
{
get { return m_MaxArrayCount; }
}
void OnEnable()
{
m_RequiresUpload = true;
m_RequiresUpdate = false;
}
// Set Geometry Cache.
internal void SetGeometryCache(int _maxArrayCount, NativeSlice<Vector3> _posArray, NativeSlice<Vector2> _uv0Array, NativeSlice<Vector4> _tanArray, NativeArray<ushort> _indexArray, NativeArray<UnityEngine.U2D.SpriteShapeSegment> _geomArray)
{
m_RequiresUpdate = true;
m_PosArrayCache = _posArray;
m_Uv0ArrayCache = _uv0Array;
m_TanArrayCache = _tanArray;
m_GeomArrayCache = _geomArray;
m_IndexArrayCache = _indexArray;
m_MaxArrayCount = _maxArrayCount;
}
// Update GeometryCache.
internal void UpdateGeometryCache()
{
bool updateCache = m_RequiresUpdate && m_GeomArrayCache.IsCreated;
updateCache = updateCache && m_IndexArrayCache.IsCreated;
if (updateCache)
{
int geomCount = 0;
int indexCount = 0;
int vertexCount = 0;
for (int i = 0; (i < m_GeomArrayCache.Length); ++i)
{
var geom = m_GeomArrayCache[i];
indexCount += geom.indexCount;
vertexCount += geom.vertexCount;
if (geom.vertexCount > 0)
geomCount = i + 1;
}
m_GeomArray = new SpriteShapeGeometryInfo[geomCount];
NativeArray<SpriteShapeGeometryInfo> geomInfoArray = m_GeomArrayCache.Reinterpret<SpriteShapeGeometryInfo>();
SpriteShapeCopyUtility<SpriteShapeGeometryInfo>.Copy(m_GeomArray, geomInfoArray, geomCount);
m_PosArray = new Vector3[vertexCount];
m_Uv0Array = new Vector2[vertexCount];
m_TanArray = new Vector4[m_TanArrayCache.Length];
m_IndexArray = new ushort[indexCount];
SpriteShapeCopyUtility<Vector3>.Copy(m_PosArray, m_PosArrayCache, vertexCount);
SpriteShapeCopyUtility<Vector2>.Copy(m_Uv0Array, m_Uv0ArrayCache, vertexCount);
SpriteShapeCopyUtility<Vector4>.Copy(m_TanArray, m_TanArrayCache, m_TanArrayCache.Length);
SpriteShapeCopyUtility<ushort>.Copy(m_IndexArray, m_IndexArrayCache, indexCount);
m_MaxArrayCount = (vertexCount > indexCount) ? vertexCount : indexCount;
m_RequiresUpdate = false;
}
}
internal JobHandle Upload(SpriteShapeRenderer sr, SpriteShapeController sc)
{
JobHandle jobHandle = (default);
if (m_RequiresUpload)
{
// Update Geometries.
NativeArray<SpriteShapeSegment> geomArray = sr.GetSegments(m_GeomArray.Length);
NativeArray<SpriteShapeGeometryInfo> geomInfoArray = geomArray.Reinterpret<SpriteShapeGeometryInfo>();
geomInfoArray.CopyFrom(m_GeomArray);
// Update Mesh Data.
NativeSlice<Vector3> posArray;
NativeSlice<Vector2> uv0Array;
NativeArray<ushort> indexArray;
if (sc.enableTangents)
{
NativeSlice<Vector4> tanArray;
sr.GetChannels(m_MaxArrayCount, out indexArray, out posArray, out uv0Array, out tanArray);
SpriteShapeCopyUtility<Vector4>.Copy(tanArray, m_TanArray, m_TanArray.Length);
}
else
{
sr.GetChannels(m_MaxArrayCount, out indexArray, out posArray, out uv0Array);
}
SpriteShapeCopyUtility<Vector3>.Copy(posArray, m_PosArray, m_PosArray.Length);
SpriteShapeCopyUtility<Vector2>.Copy(uv0Array, m_Uv0Array, m_Uv0Array.Length);
SpriteShapeCopyUtility<ushort>.Copy(indexArray, m_IndexArray, m_IndexArray.Length);
sr.Prepare(jobHandle, sc.spriteShapeParameters, sc.spriteArray);
m_RequiresUpload = false;
}
return jobHandle;
}
}

View file

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

View file

@ -0,0 +1,19 @@
{
"name": "Unity.2D.SpriteShape.Runtime",
"references": [
"Unity.2D.Common.Runtime",
"Unity.Mathematics",
"Unity.Burst"
],
"includePlatforms": [],
"excludePlatforms": [],
"allowUnsafeCode": true,
"versionDefines": [
{
"name": "com.unity.burst",
"expression": "0.0.1",
"define": "ENABLE_SPRITESHAPE_BURST"
}
],
"noEngineReferences": false
}

View file

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