123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325 |
- using System.Collections.Generic;
- using System.Linq;
- using UnityEngine;
- namespace UnityEditor.U2D.Animation
- {
- internal static class SpriteCacheExtensions
- {
- public static MeshCache GetMesh(this SpriteCache sprite)
- {
- if (sprite != null)
- return sprite.skinningCache.GetMesh(sprite);
- return null;
- }
- public static MeshPreviewCache GetMeshPreview(this SpriteCache sprite)
- {
- if (sprite != null)
- return sprite.skinningCache.GetMeshPreview(sprite);
- return null;
- }
- public static SkeletonCache GetSkeleton(this SpriteCache sprite)
- {
- if (sprite != null)
- return sprite.skinningCache.GetSkeleton(sprite);
- return null;
- }
- public static CharacterPartCache GetCharacterPart(this SpriteCache sprite)
- {
- if (sprite != null)
- return sprite.skinningCache.GetCharacterPart(sprite);
- return null;
- }
- public static bool IsVisible(this SpriteCache sprite)
- {
- var isVisible = true;
- var characterPart = sprite.GetCharacterPart();
- if (sprite.skinningCache.mode == SkinningMode.Character && characterPart != null)
- isVisible = characterPart.isVisible;
- return isVisible;
- }
- public static Matrix4x4 GetLocalToWorldMatrixFromMode(this SpriteCache sprite)
- {
- var skinningCache = sprite.skinningCache;
- if (skinningCache.mode == SkinningMode.SpriteSheet)
- return sprite.localToWorldMatrix;
- var characterPart = sprite.GetCharacterPart();
- Debug.Assert(characterPart != null);
- return characterPart.localToWorldMatrix;
- }
- public static BoneCache[] GetBonesFromMode(this SpriteCache sprite)
- {
- var skinningCache = sprite.skinningCache;
- if (skinningCache.mode == SkinningMode.SpriteSheet)
- return sprite.GetSkeleton().bones;
- var characterPart = sprite.GetCharacterPart();
- Debug.Assert(characterPart != null);
- return characterPart.bones;
- }
- public static void UpdateMesh(this SpriteCache sprite, BoneCache[] bones)
- {
- var mesh = sprite.GetMesh();
- var previewMesh = sprite.GetMeshPreview();
- Debug.Assert(mesh != null);
- Debug.Assert(previewMesh != null);
- mesh.bones = bones;
- previewMesh.SetWeightsDirty();
- }
- public static void SmoothFill(this SpriteCache sprite)
- {
- var mesh = sprite.GetMesh();
- if (mesh == null)
- return;
- var controller = new SpriteMeshDataController();
- controller.spriteMeshData = mesh;
- controller.SmoothFill();
- }
- public static void RestoreBindPose(this SpriteCache sprite)
- {
- var skinningCache = sprite.skinningCache;
- var skeleton = sprite.GetSkeleton();
- Debug.Assert(skeleton != null);
- skeleton.RestoreDefaultPose();
- skinningCache.events.skeletonPreviewPoseChanged.Invoke(skeleton);
- }
- public static bool AssociateAllBones(this SpriteCache sprite)
- {
- var skinningCache = sprite.skinningCache;
- if (skinningCache.mode == SkinningMode.SpriteSheet)
- return false;
- var character = skinningCache.character;
- Debug.Assert(character != null);
- Debug.Assert(character.skeleton != null);
- var characterPart = sprite.GetCharacterPart();
- Debug.Assert(characterPart != null);
- var bones = character.skeleton.bones.Where(x => x.isVisible).ToArray();
- characterPart.bones = bones;
- characterPart.sprite.UpdateMesh(bones);
- return true;
- }
- public static bool AssociatePossibleBones(this SpriteCache sprite)
- {
- var skinningCache = sprite.skinningCache;
- if (skinningCache.mode == SkinningMode.SpriteSheet)
- return false;
- var character = skinningCache.character;
- Debug.Assert(character != null);
- Debug.Assert(character.skeleton != null);
- var characterPart = sprite.GetCharacterPart();
- Debug.Assert(characterPart != null);
- var bones = character.skeleton.bones.Where(x => x.isVisible).ToArray();
- var possibleBones = new List<BoneCache>();
- // check if any of the bones overlapped
- BoneCache shortestBoneDistance = null;
- var minDistances = float.MaxValue;
- var characterSpriteRect = new Rect(characterPart.position.x , characterPart.position.y, characterPart.sprite.textureRect.width, characterPart.sprite.textureRect.height);
- foreach (var bone in bones)
- {
- var startPoint = bone.position;
- var endPoint = bone.endPosition;
- if (IntersectsSegment(characterSpriteRect, startPoint, endPoint))
- possibleBones.Add(bone);
- if (possibleBones.Count == 0)
- {
- // compare bone start end with rect's 4 line
- // compare rect point with bone line
- var points = new Vector2[] { startPoint, endPoint };
- var rectLinePoints = new []
- {
- new Vector2Int(0, 1),
- new Vector2Int(0, 2),
- new Vector2Int(1, 3),
- new Vector2Int(2, 3),
- };
- var rectPoints = new []
- {
- new Vector2(characterSpriteRect.xMin, characterSpriteRect.yMin),
- new Vector2(characterSpriteRect.xMin, characterSpriteRect.yMax),
- new Vector2(characterSpriteRect.xMax, characterSpriteRect.yMin),
- new Vector2(characterSpriteRect.xMax, characterSpriteRect.yMax)
- };
- foreach (var point in points)
- {
- foreach (var rectLine in rectLinePoints)
- {
- var distance = PointToLineSegmentDistance(point, rectPoints[rectLine.x], rectPoints[rectLine.y]);
- if (distance < minDistances)
- {
- minDistances = distance;
- shortestBoneDistance = bone;
- }
- }
- }
- foreach (var rectPoint in rectPoints)
- {
- var distance = PointToLineSegmentDistance(rectPoint, startPoint, endPoint);
- if (distance < minDistances)
- {
- minDistances = distance;
- shortestBoneDistance = bone;
- }
- }
- }
- }
- // if none overlapped, we use the bone that is closest to us
- if (possibleBones.Count == 0 && shortestBoneDistance != null)
- {
- possibleBones.Add(shortestBoneDistance);
- }
- characterPart.bones = possibleBones.ToArray();
- characterPart.sprite.UpdateMesh(possibleBones.ToArray());
- return true;
- }
- static float PointToLineSegmentDistance(Vector2 p, Vector2 a, Vector2 b)
- {
- Vector2 n = b - a;
- Vector2 pa = a - p;
- float c = Vector2.Dot(n, pa);
- // Closest point is a
- if (c > 0.0f)
- return Vector2.Dot(pa, pa);
- Vector2 bp = p - b;
- // Closest point is b
- if (Vector2.Dot(n, bp) > 0.0f)
- return Vector2.Dot(bp, bp);
- // Closest point is between a and b
- Vector2 e = pa - n * (c / Vector2.Dot(n, n));
- return Vector2.Dot( e, e );
- }
- static bool IntersectsSegment(Rect rect, Vector2 p1, Vector2 p2)
- {
- float minX = Mathf.Min(p1.x, p2.x);
- float maxX = Mathf.Max(p1.x, p2.x);
- if (maxX > rect.xMax)
- {
- maxX = rect.xMax;
- }
- if (minX < rect.xMin)
- {
- minX = rect.xMin;
- }
- if (minX > maxX)
- {
- return false;
- }
- float minY = Mathf.Min(p1.y, p2.y);
- float maxY = Mathf.Max(p1.y, p2.y);
- float dx = p2.x - p1.x;
- if (Mathf.Abs(dx) > float.Epsilon)
- {
- float a = (p2.y - p1.y) / dx;
- float b = p1.y - a * p1.x;
- minY = a * minX + b;
- maxY = a * maxX + b;
- }
- if (minY > maxY)
- {
- float tmp = maxY;
- maxY = minY;
- minY = tmp;
- }
- if (maxY > rect.yMax)
- {
- maxY = rect.yMax;
- }
- if (minY < rect.yMin)
- {
- minY = rect.yMin;
- }
- if (minY > maxY)
- {
- return false;
- }
- return true;
- }
- public static void DeassociateUnusedBones(this SpriteCache sprite)
- {
- var skinningCache = sprite.skinningCache;
- Debug.Assert(skinningCache.mode == SkinningMode.Character);
- var characterPart = sprite.GetCharacterPart();
- Debug.Assert(characterPart != null);
- characterPart.DeassociateUnusedBones();
- }
- public static void DeassociateAllBones(this SpriteCache sprite)
- {
- var skinningCache = sprite.skinningCache;
- if (skinningCache.mode == SkinningMode.SpriteSheet)
- return;
- var part = sprite.GetCharacterPart();
- if (part.bones.Length == 0)
- return;
- Debug.Assert(part.sprite != null);
- part.bones = new BoneCache[0];
- part.sprite.UpdateMesh(part.bones);
- skinningCache.events.characterPartChanged.Invoke(part);
- }
- }
- }
|