mirror of
https://gitgud.io/AbstractConcept/rimworld-animation-studio.git
synced 2024-08-15 00:43:27 +00:00
Initial commit
This commit is contained in:
commit
3c7cc0c973
8391 changed files with 704313 additions and 0 deletions
|
@ -0,0 +1,2 @@
|
|||
using System.Runtime.CompilerServices;
|
||||
[assembly: InternalsVisibleTo("Unity.2D.SpriteShape.Editor")]
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 7974be9b5f0db0f41a7acc758375c648
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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:
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 30fdb7163494e28429d56613fe407bf4
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
8
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet.meta
vendored
Normal file
8
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet.meta
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9214d94ab547c5447a11c7a7c6a59482
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
107
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/Dict.cs
vendored
Normal file
107
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/Dict.cs
vendored
Normal 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
|
11
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/Dict.cs.meta
vendored
Normal file
11
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/Dict.cs.meta
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d1f51a5b71c3ce943b689d3664e4d5fd
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
301
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/Geom.cs
vendored
Normal file
301
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/Geom.cs
vendored
Normal 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
|
11
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/Geom.cs.meta
vendored
Normal file
11
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/Geom.cs.meta
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 8eb4e2609b653584b88dc0ee64a2ba24
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
25
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/LICENSE.txt
vendored
Normal file
25
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/LICENSE.txt
vendored
Normal 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.
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b5ea83a04894a434f9b5e5b5d91c75e5
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
500
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/Mesh.cs
vendored
Normal file
500
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/Mesh.cs
vendored
Normal 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
|
11
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/Mesh.cs.meta
vendored
Normal file
11
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/Mesh.cs.meta
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 3d834cd56fabc3447b5e84a6ad97d96a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
465
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/MeshUtils.cs
vendored
Normal file
465
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/MeshUtils.cs
vendored
Normal 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
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ada7faed6fbdf4a409392af3cfb70479
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
246
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/PriorityHeap.cs
vendored
Normal file
246
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/PriorityHeap.cs
vendored
Normal 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
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 08bd485b57bc7c7498c8597502c34793
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
231
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/PriorityQueue.cs
vendored
Normal file
231
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/PriorityQueue.cs
vendored
Normal 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
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: daf70eb4f3701c347bfa9c15178b236a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
1238
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/Sweep.cs
vendored
Normal file
1238
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/Sweep.cs
vendored
Normal file
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 64ce47adfe8718046a27fd95ffeee1b1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
746
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/Tess.cs
vendored
Normal file
746
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/Tess.cs
vendored
Normal 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
|
11
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/Tess.cs.meta
vendored
Normal file
11
Library/PackageCache/com.unity.2d.spriteshape@3.0.14/Runtime/External/LibTessDotNet/Tess.cs.meta
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 829c254d9e402e64183afa0e99951e04
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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:
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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:
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -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:
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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:
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: c9697ca08d26c2848a5c5de0be739d1b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9aa06092e0908a84585e814e7c214a51
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -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
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: caccfbdb442cdc64fa722b4c5585521f
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Add table
Add a link
Reference in a new issue