Initial commit

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

View file

@ -0,0 +1,332 @@
using System;
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
[Serializable]
internal struct Pose
{
public Vector3 position;
public Quaternion rotation;
public Matrix4x4 matrix
{
get { return Matrix4x4.TRS(position, rotation, Vector3.one); }
}
public static Pose Create(Vector3 p, Quaternion r)
{
var pose = new Pose()
{
position = p,
rotation = r
};
return pose;
}
public override bool Equals(object other)
{
return other is Pose && this == (Pose)other;
}
public override int GetHashCode()
{
return position.GetHashCode() ^ rotation.GetHashCode();
}
public static bool operator==(Pose p1, Pose p2)
{
return p1.position == p2.position && p1.rotation == p2.rotation;
}
public static bool operator!=(Pose p1, Pose p2)
{
return !(p1 == p2);
}
}
[Serializable]
internal struct BonePose
{
public Pose pose;
public float length;
public static BonePose Create(Pose p, float l)
{
var pose = new BonePose()
{
pose = p,
length = l
};
return pose;
}
public override bool Equals(object other)
{
return other is BonePose && this == (BonePose)other;
}
public override int GetHashCode()
{
return pose.GetHashCode() ^ length.GetHashCode();
}
public static bool operator==(BonePose p1, BonePose p2)
{
return p1.pose == p2.pose && p1.length == p2.length;
}
public static bool operator!=(BonePose p1, BonePose p2)
{
return !(p1 == p2);
}
}
internal class BoneCache : TransformCache
{
[SerializeField]
Color m_BindPoseColor;
[SerializeField]
private Pose m_BindPose;
[SerializeField]
private BonePose m_DefaultPose;
[SerializeField]
private BoneCache m_ChainedChild;
[SerializeField]
private float m_Depth;
[SerializeField]
private float m_LocalLength = 1f;
[SerializeField]
private bool m_IsVisible = true;
public bool NotInDefaultPose()
{
return localPosition != m_DefaultPose.pose.position
|| localRotation != m_DefaultPose.pose.rotation
|| localLength != m_DefaultPose.length;
}
public bool isVisible
{
get { return m_IsVisible; }
set { m_IsVisible = value; }
}
public Color bindPoseColor
{
get { return m_BindPoseColor; }
set { m_BindPoseColor = value; }
}
public virtual BoneCache parentBone
{
get { return parent as BoneCache; }
}
public SkeletonCache skeleton
{
get
{
var skeleton = parent as SkeletonCache;
if (skeleton != null)
return skeleton;
if (parentBone != null)
return parentBone.skeleton;
return null;
}
}
public virtual BoneCache chainedChild
{
get
{
if (m_ChainedChild != null && m_ChainedChild.parentBone == this)
return m_ChainedChild;
return null;
}
set
{
if (m_ChainedChild != value)
{
if (value == null || value.parentBone == this)
{
m_ChainedChild = value;
if(m_ChainedChild != null)
OrientToChainedChild(false);
}
}
}
}
public Vector3 localEndPosition
{
get { return Vector3.right * localLength; }
}
public Vector3 endPosition
{
get { return localToWorldMatrix.MultiplyPoint3x4(localEndPosition); }
set
{
if (chainedChild == null)
{
var direction = value - position;
right = direction;
length = direction.magnitude;
}
}
}
public BonePose localPose
{
get { return BonePose.Create(Pose.Create(localPosition, localRotation), localLength); }
set
{
localPosition = value.pose.position;
localRotation = value.pose.rotation;
localLength = value.length;
}
}
public BonePose worldPose
{
get { return BonePose.Create(Pose.Create(position, rotation), length); }
set
{
position = value.pose.position;
rotation = value.pose.rotation;
length = value.length;
}
}
public Pose bindPose
{
get { return m_BindPose; }
set { m_BindPose = value; }
}
public float depth
{
get { return m_Depth; }
set { m_Depth = value; }
}
public float localLength
{
get { return m_LocalLength; }
set { m_LocalLength = Mathf.Max(0f, value); }
}
public float length
{
get { return localToWorldMatrix.MultiplyVector(localEndPosition).magnitude; }
set { m_LocalLength = worldToLocalMatrix.MultiplyVector(right * Mathf.Max(0f, value)).magnitude; }
}
internal Pose[] GetChildrenWoldPose()
{
return Array.ConvertAll(children, c => Pose.Create(c.position, c.rotation));
}
internal void SetChildrenWorldPose(Pose[] worldPose)
{
var childrenArray = children;
Debug.Assert(childrenArray.Length == worldPose.Length);
for (var i = 0; i < childrenArray.Length; ++i)
{
var child = childrenArray[i];
var pose= worldPose[i];
child.position = pose.position;
child.rotation = pose.rotation;
}
}
internal override void OnDestroy()
{
base.OnDestroy();
m_ChainedChild = null;
}
new public void SetParent(TransformCache newParent)
{
SetParent(newParent, true);
}
new public void SetParent(TransformCache newParent, bool worldPositionStays)
{
if (parentBone != null && parentBone.chainedChild == this)
parentBone.chainedChild = null;
base.SetParent(newParent, worldPositionStays);
if (parentBone != null && parentBone.chainedChild == null && (parentBone.endPosition - position).sqrMagnitude < 0.001f)
parentBone.chainedChild = this;
}
public void OrientToChainedChild(bool freezeChildren)
{
Debug.Assert(chainedChild != null);
var childPosition = chainedChild.position;
var childRotation = chainedChild.rotation;
Pose[] childrenWorldPose = null;
if (freezeChildren)
childrenWorldPose = GetChildrenWoldPose();
right = childPosition - position;
if (freezeChildren)
{
SetChildrenWorldPose(childrenWorldPose);
}
else
{
chainedChild.position = childPosition;
chainedChild.rotation = childRotation;
}
length = (childPosition - position).magnitude;
}
public void SetDefaultPose()
{
m_DefaultPose = localPose;
if (IsUnscaled())
m_BindPose = worldPose.pose;
else
throw new Exception("BindPose cannot be set under global scale");
}
public void RestoreDefaultPose()
{
localPose = m_DefaultPose;
}
private bool IsUnscaled()
{
var currentTransform = this as TransformCache;
while (currentTransform != null)
{
var scale = currentTransform.localScale;
var isUnscaled = Mathf.Approximately(scale.x, 1f) && Mathf.Approximately(scale.y, 1f) && Mathf.Approximately(scale.z, 1f);
if (!isUnscaled)
return false;
currentTransform = currentTransform.parent;
}
return true;
}
}
}

View file

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

View file

@ -0,0 +1,130 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
internal static class BoneCacheExtensions
{
public static BoneCache[] ToCharacterIfNeeded(this BoneCache[] bones)
{
return Array.ConvertAll(bones, b => ToCharacterIfNeeded(b));
}
public static BoneCache[] ToSpriteSheetIfNeeded(this BoneCache[] bones)
{
return Array.ConvertAll(bones, b => ToSpriteSheetIfNeeded(b));
}
public static BoneCache ToCharacterIfNeeded(this BoneCache bone)
{
if (bone == null)
return null;
var skinningCache = bone.skinningCache;
if (skinningCache.hasCharacter)
{
if (bone.skeleton != skinningCache.character.skeleton)
{
var selectedSprite = skinningCache.selectedSprite;
if (selectedSprite == null)
return null;
var skeleton = selectedSprite.GetSkeleton();
var characterPart = selectedSprite.GetCharacterPart();
Debug.Assert(skeleton != null);
Debug.Assert(characterPart != null);
Debug.Assert(bone.skeleton == skeleton);
Debug.Assert(skeleton.BoneCount == characterPart.BoneCount);
var index = skeleton.IndexOf(bone);
if (index == -1)
bone = null;
else
bone = characterPart.GetBone(index);
}
}
return bone;
}
public static BoneCache ToSpriteSheetIfNeeded(this BoneCache bone)
{
if (bone == null)
return null;
var skinningCache = bone.skinningCache;
if (skinningCache.hasCharacter && skinningCache.mode == SkinningMode.SpriteSheet)
{
var selectedSprite = skinningCache.selectedSprite;
if (selectedSprite == null)
return null;
var characterSkeleton = skinningCache.character.skeleton;
Debug.Assert(bone.skeleton == characterSkeleton);
var skeleton = selectedSprite.GetSkeleton();
var characterPart = selectedSprite.GetCharacterPart();
Debug.Assert(skeleton != null);
Debug.Assert(characterPart != null);
Debug.Assert(skeleton.BoneCount == characterPart.BoneCount);
var index = characterPart.IndexOf(bone);
if (index == -1)
bone = null;
else
bone = skeleton.GetBone(index);
}
return bone;
}
public static UnityEngine.U2D.SpriteBone ToSpriteBone(this BoneCache bone, Matrix4x4 rootTransform, int parentId)
{
var position = bone.localPosition;
var rotation = bone.localRotation;
if (parentId == -1)
{
rotation = bone.rotation;
position = rootTransform.inverse.MultiplyPoint3x4(bone.position);
}
return new UnityEngine.U2D.SpriteBone()
{
name = bone.name,
position = new Vector3(position.x, position.y, bone.depth),
rotation = rotation,
length = bone.localLength,
parentId = parentId
};
}
public static UnityEngine.U2D.SpriteBone[] ToSpriteBone(this BoneCache[] bones, Matrix4x4 rootTransform)
{
var spriteBones = new List<UnityEngine.U2D.SpriteBone>();
foreach (var bone in bones)
{
var parentId = -1;
if (ArrayUtility.Contains(bones, bone.parentBone))
parentId = Array.IndexOf(bones, bone.parentBone);
spriteBones.Add(bone.ToSpriteBone(rootTransform, parentId));
}
return spriteBones.ToArray();
}
}
}

View file

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

View file

@ -0,0 +1,53 @@
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
internal class CharacterCache : SkinningObject, IEnumerable<CharacterPartCache>
{
[SerializeField]
private SkeletonCache m_Skeleton;
[SerializeField]
private List<CharacterPartCache> m_Parts = new List<CharacterPartCache>();
[SerializeField]
private Vector2Int m_Dimension;
[SerializeField]
private List<CharacterGroupCache> m_Groups = new List<CharacterGroupCache>();
public SkeletonCache skeleton
{
get { return m_Skeleton; }
set { m_Skeleton = value; }
}
public virtual CharacterPartCache[] parts
{
get { return m_Parts.ToArray(); }
set { m_Parts = new List<CharacterPartCache>(value); }
}
public virtual CharacterGroupCache[] groups
{
get { return m_Groups.ToArray(); }
set { m_Groups = new List<CharacterGroupCache>(value); }
}
public Vector2Int dimension
{
get { return m_Dimension; }
set { m_Dimension = value; }
}
public IEnumerator<CharacterPartCache> GetEnumerator()
{
return ((IEnumerable<CharacterPartCache>)m_Parts).GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return ((IEnumerable<CharacterPartCache>)m_Parts).GetEnumerator();
}
}
}

View file

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

View file

@ -0,0 +1,99 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
[Serializable]
internal class CharacterGroupCache : SkinningObject, ICharacterOrder
{
[SerializeField]
public int parentGroup;
[SerializeField]
private bool m_IsVisible = true;
[SerializeField]
private int m_Order = -1;
public bool isVisible
{
get => m_IsVisible;
set
{
m_IsVisible = value;
skinningCache.GroupVisibilityChanged(this);
}
}
public virtual int order
{
get => m_Order;
set => m_Order = value;
}
}
internal class CharacterPartCache : TransformCache, ICharacterOrder
{
[SerializeField]
private SpriteCache m_Sprite;
[SerializeField]
private List<BoneCache> m_Bones = new List<BoneCache>();
[SerializeField]
private bool m_IsVisible = true;
[SerializeField]
private int m_ParentGroup = -1;
[SerializeField]
private int m_Order = -1;
public virtual int order
{
get => m_Order;
set => m_Order = value;
}
public int parentGroup
{
get { return m_ParentGroup; }
set { m_ParentGroup = value; }
}
public virtual bool isVisible
{
get { return m_IsVisible; }
set
{
m_IsVisible = value;
if (skinningCache != null)
skinningCache.SpriteVisibilityChanged(this);
}
}
public int BoneCount { get { return m_Bones.Count; } }
public virtual SpriteCache sprite
{
get { return m_Sprite; }
set { m_Sprite = value; }
}
public BoneCache[] bones
{
get { return m_Bones.ToArray(); }
set { m_Bones = new List<BoneCache>(value); }
}
public BoneCache GetBone(int index)
{
return m_Bones[index];
}
public int IndexOf(BoneCache bone)
{
return m_Bones.IndexOf(bone);
}
public bool Contains(BoneCache bone)
{
return m_Bones.Contains(bone);
}
}
}

View file

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

View file

@ -0,0 +1,79 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
internal static class CharacterPartCacheExtensions
{
public static void SyncSpriteSheetSkeleton(this CharacterPartCache characterPart)
{
var skinningCache = characterPart.skinningCache;
var character = skinningCache.character;
var characterSkeleton = character.skeleton;
var spriteSkeleton = characterPart.sprite.GetSkeleton();
var spriteSkeletonBones = spriteSkeleton.bones;
var characterPartBones = characterPart.bones;
if (spriteSkeletonBones.Length != characterPartBones.Length)
return;
for (var i = 0; i < characterPartBones.Length; ++i)
{
var spriteBone = spriteSkeletonBones[i];
var characterBone = characterPartBones[i];
var childWorldPose = spriteBone.GetChildrenWoldPose();
spriteBone.position = spriteSkeleton.localToWorldMatrix.MultiplyPoint3x4(
characterPart.worldToLocalMatrix.MultiplyPoint3x4(characterBone.position));
spriteBone.rotation = characterBone.rotation;
spriteBone.length = characterBone.length;
spriteBone.name = characterBone.name;
spriteBone.depth = characterBone.depth;
spriteBone.bindPoseColor = characterBone.bindPoseColor;
spriteBone.SetChildrenWorldPose(childWorldPose);
}
if (characterSkeleton.isPosePreview)
spriteSkeleton.SetPosePreview();
else
spriteSkeleton.SetDefaultPose();
}
public static void DeassociateUnusedBones(this CharacterPartCache characterPart)
{
var skinningCache = characterPart.skinningCache;
var bones = characterPart.bones;
if (bones.Length == 0)
return;
Debug.Assert(characterPart.sprite != null);
var mesh = characterPart.sprite.GetMesh();
Debug.Assert(mesh != null);
var vertices = mesh.vertices;
var newBonesSet = new HashSet<BoneCache>();
foreach (var vertex in vertices)
{
var boneWeight = vertex.editableBoneWeight;
foreach (BoneWeightChannel channel in boneWeight)
if (channel.enabled)
newBonesSet.Add(bones[channel.boneIndex]);
}
bones = new List<BoneCache>(newBonesSet).ToArray();
characterPart.bones = bones;
characterPart.sprite.UpdateMesh(bones);
skinningCache.events.characterPartChanged.Invoke(characterPart);
}
}
}

View file

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

View file

@ -0,0 +1,203 @@
using System.Collections.Generic;
using UnityEditor.U2D.Sprites;
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
internal class MeshCache : SkinningObject, ISpriteMeshData
{
[SerializeField]
private SpriteCache m_Sprite;
[SerializeField]
private List<Vertex2D> m_Vertices = new List<Vertex2D>();
[SerializeField]
private List<int> m_Indices = new List<int>();
[SerializeField]
private List<Edge> m_Edges = new List<Edge>();
[SerializeField]
private List<BoneCache> m_Bones = new List<BoneCache>();
public ITextureDataProvider textureDataProvider { get; set; }
public SpriteCache sprite
{
get { return m_Sprite; }
set { m_Sprite = value; }
}
public List<Vertex2D> vertices
{
get { return m_Vertices; }
set { m_Vertices = value; }
}
public List<Vector3> vertexPositionOverride { get; set; }
public List<Edge> edges
{
get { return m_Edges; }
set { m_Edges = value; }
}
public List<int> indices
{
get { return m_Indices; }
set { m_Indices = value; }
}
public BoneCache[] bones
{
get { return m_Bones.ToArray(); }
set { SetBones(value); }
}
Rect ISpriteMeshData.frame
{
get { return sprite.textureRect; }
set {}
}
public int vertexCount
{
get { return m_Vertices.Count; }
}
public int boneCount
{
get { return m_Bones.Count; }
}
public Vector2 GetPosition(int index)
{
if (vertexPositionOverride != null)
return vertexPositionOverride[index];
return m_Vertices[index].position;
}
public void SetPosition(int index, Vector2 position)
{
if (vertexPositionOverride != null)
return;
m_Vertices[index].position = position;
}
public EditableBoneWeight GetWeight(int index)
{
return m_Vertices[index].editableBoneWeight;
}
public void SetWeight(int index, EditableBoneWeight weight)
{
m_Vertices[index].editableBoneWeight = weight;
}
public void AddVertex(Vector2 position, BoneWeight weight)
{
m_Vertices.Add(new Vertex2D(position, weight));
}
public void RemoveVertex(int index)
{
m_Vertices.RemoveAt(index);
}
SpriteBoneData ISpriteMeshData.GetBoneData(int index)
{
var worldToLocalMatrix = sprite.worldToLocalMatrix;
//We expect m_Bones to contain character's bones references if character exists. Sprite's skeleton bones otherwise.
if (skinningCache.hasCharacter)
worldToLocalMatrix = sprite.GetCharacterPart().worldToLocalMatrix;
SpriteBoneData spriteBoneData = null;
var bone = m_Bones[index];
if (bone == null)
spriteBoneData = new SpriteBoneData();
else
{
spriteBoneData = new SpriteBoneData()
{
name = bone.name,
parentId = bone.parentBone == null ? -1 : m_Bones.IndexOf(bone.parentBone),
localPosition = bone.localPosition,
localRotation = bone.localRotation,
position = worldToLocalMatrix.MultiplyPoint3x4(bone.position),
endPosition = worldToLocalMatrix.MultiplyPoint3x4(bone.endPosition),
depth = bone.depth,
length = bone.localLength
};
}
return spriteBoneData;
}
float ISpriteMeshData.GetBoneDepth(int index)
{
return m_Bones[index].depth;
}
public void Clear()
{
m_Vertices.Clear();
m_Indices.Clear();
m_Edges.Clear();
}
public bool ContainsBone(BoneCache bone)
{
return m_Bones.Contains(bone);
}
public void SetCompatibleBoneSet(BoneCache[] bones)
{
m_Bones = new List<BoneCache>(bones);
}
private void SetBones(BoneCache[] bones)
{
FixWeights(bones);
SetCompatibleBoneSet(bones);
}
private void FixWeights(BoneCache[] newBones)
{
var newBonesList = new List<BoneCache>(newBones);
var indexMap = new Dictionary<int, int>();
for (var i = 0; i < m_Bones.Count; ++i)
{
var bone = m_Bones[i];
var newIndex = newBonesList.IndexOf(bone);
if (newIndex != -1)
indexMap.Add(i, newIndex);
}
foreach (Vertex2D vertex in vertices)
{
var boneWeight = vertex.editableBoneWeight;
for (var i = 0; i < boneWeight.Count; ++i)
{
var newIndex = 0;
var boneRemoved = indexMap.TryGetValue(boneWeight[i].boneIndex, out newIndex) == false;
if (boneRemoved)
{
boneWeight[i].weight = 0f;
boneWeight[i].enabled = false;
}
boneWeight[i].boneIndex = newIndex;
if (boneRemoved)
boneWeight.CompensateOtherChannels(i);
}
boneWeight.UnifyChannelsWithSameBoneIndex();
}
}
}
}

View file

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

View file

@ -0,0 +1,370 @@
using UnityEngine;
using System;
using System.Collections.Generic;
namespace UnityEditor.U2D.Animation
{
internal class MeshPreviewCache : SkinningObject
{
private const int kNiceColorCount = 6;
[SerializeField]
private SpriteCache m_Sprite;
[SerializeField]
private Mesh m_Mesh;
[SerializeField]
private Mesh m_DefaultMesh;
private List<Vector3> m_SkinnedVertices = new List<Vector3>();
private List<Vector3> m_Vertices = new List<Vector3>();
private List<BoneWeight> m_Weights = new List<BoneWeight>();
private List<Vector2> m_TexCoords = new List<Vector2>();
private List<Color> m_Colors = new List<Color>();
private List<Matrix4x4> m_SkinningMatrices = new List<Matrix4x4>();
private bool m_MeshDirty;
private bool m_VerticesDirty;
private bool m_SkinningDirty;
private bool m_WeightsDirty;
private bool m_IndicesDirty;
private bool m_ColorsDirty;
private bool m_EnableSkinning;
public SpriteCache sprite
{
get { return m_Sprite; }
set
{
m_Sprite = value;
InitializeDefaultMesh();
SetMeshDirty();
}
}
public Mesh mesh { get { return m_Mesh; } }
public Mesh defaultMesh { get { return m_DefaultMesh; } }
public bool enableSkinning
{
get
{
return m_EnableSkinning;
}
set
{
if (m_EnableSkinning != value)
{
m_EnableSkinning = value;
SetSkinningDirty();
}
}
}
public bool canSkin
{
get { return CanSkin(); }
}
public List<Vector3> vertices
{
get
{
if (enableSkinning && canSkin)
return m_SkinnedVertices;
return m_Vertices;
}
}
private bool CanSkin()
{
if (m_Vertices.Count == 0 || m_Vertices.Count != m_Weights.Count)
return false;
var bones = sprite.GetBonesFromMode();
Debug.Assert(bones != null);
if (bones.Length == 0)
return false;
foreach (var weight in m_Weights)
{
if (weight.boneIndex0 < 0 || weight.boneIndex0 >= bones.Length ||
weight.boneIndex1 < 0 || weight.boneIndex1 >= bones.Length ||
weight.boneIndex2 < 0 || weight.boneIndex2 >= bones.Length ||
weight.boneIndex3 < 0 || weight.boneIndex3 >= bones.Length)
return false;
}
return true;
}
internal override void OnCreate()
{
m_Mesh = CreateMesh();
m_DefaultMesh = CreateMesh();
}
internal override void OnDestroy()
{
DestroyImmediate(m_Mesh);
DestroyImmediate(m_DefaultMesh);
}
private Mesh CreateMesh()
{
var mesh = new Mesh();
mesh.MarkDynamic();
mesh.hideFlags = HideFlags.DontSave;
return mesh;
}
private void InitializeDefaultMesh()
{
Debug.Assert(sprite != null);
Debug.Assert(m_DefaultMesh != null);
var meshCache = sprite.GetMesh();
Debug.Assert(meshCache != null);
int width, height;
meshCache.textureDataProvider.GetTextureActualWidthAndHeight(out width, out height);
var uvScale = new Vector2(1f / width, 1f / height);
Vector3 position = sprite.textureRect.position;
var size = sprite.textureRect.size;
var vertices = new List<Vector3>()
{
Vector3.zero,
new Vector3(0f, size.y, 0f),
new Vector3(size.x, 0f, 0f),
size,
};
var uvs = new List<Vector2>()
{
Vector3.Scale(vertices[0] + position, uvScale),
Vector3.Scale(vertices[1] + position, uvScale),
Vector3.Scale(vertices[2] + position, uvScale),
Vector3.Scale(vertices[3] + position, uvScale),
};
m_DefaultMesh.SetVertices(vertices);
m_DefaultMesh.SetUVs(0, uvs);
m_DefaultMesh.SetColors(new List<Color>
{
Color.black,
Color.black,
Color.black,
Color.black
});
m_DefaultMesh.SetIndices(new int[]
{
0, 1, 3, 0, 3, 2
},
MeshTopology.Triangles, 0);
m_DefaultMesh.UploadMeshData(false);
}
public void SetMeshDirty()
{
m_MeshDirty = true;
}
public void SetVerticesDirty()
{
m_VerticesDirty = true;
}
public void SetSkinningDirty()
{
m_SkinningDirty = true;
}
public void SetWeightsDirty()
{
m_WeightsDirty = true;
}
public void SetIndicesDirty()
{
m_IndicesDirty = true;
}
public void SetColorsDirty()
{
m_ColorsDirty = true;
}
public void Prepare()
{
var meshChanged = false;
var meshCache = sprite.GetMesh();
Debug.Assert(meshCache != null);
m_MeshDirty |= m_Vertices.Count != meshCache.vertices.Count;
if (m_MeshDirty)
{
m_Mesh.Clear();
m_VerticesDirty = true;
m_WeightsDirty = true;
m_IndicesDirty = true;
m_SkinningDirty = true;
m_MeshDirty = false;
}
if (m_VerticesDirty)
{
m_Vertices.Clear();
m_TexCoords.Clear();
int width, height;
meshCache.textureDataProvider.GetTextureActualWidthAndHeight(out width, out height);
var uvScale = new Vector2(1f / width, 1f / height);
foreach (var vertex in meshCache.vertices)
{
m_Vertices.Add(vertex.position);
m_TexCoords.Add(Vector2.Scale(vertex.position + sprite.textureRect.position, uvScale));
}
m_Mesh.SetVertices(m_Vertices);
m_Mesh.SetUVs(0, m_TexCoords);
meshChanged = true;
m_VerticesDirty = false;
}
if (m_WeightsDirty)
{
m_Weights.Clear();
for (int i = 0; i < meshCache.vertices.Count; ++i)
{
var vertex = meshCache.vertices[i];
m_Weights.Add(vertex.editableBoneWeight.ToBoneWeight(true));
}
SetColorsDirty();
meshChanged = true;
m_WeightsDirty = false;
}
if (m_ColorsDirty)
{
PrepareColors();
m_Mesh.SetColors(m_Colors);
meshChanged = true;
m_ColorsDirty = false;
}
if (m_IndicesDirty)
{
m_Mesh.SetTriangles(meshCache.indices, 0);
meshChanged = true;
m_IndicesDirty = false;
}
if (m_SkinningDirty)
{
if (enableSkinning && canSkin)
{
SkinVertices();
m_Mesh.SetVertices(m_SkinnedVertices);
meshChanged = true;
}
m_SkinningDirty = false;
}
if (meshChanged)
{
m_Mesh.UploadMeshData(false);
m_Mesh.RecalculateBounds();
skinningCache.events.meshPreviewChanged.Invoke(this);
}
}
private void PrepareColors()
{
var bones = sprite.GetBonesFromMode();
Debug.Assert(bones != null);
m_Colors.Clear();
for (var i = 0; i < m_Weights.Count; ++i)
{
var boneWeight = m_Weights[i];
var weightSum = 0f;
var color = Color.black;
for (var j = 0; j < 4; ++j)
{
var boneIndex = boneWeight.GetBoneIndex(j);
var weight = boneWeight.GetWeight(j);
if (boneIndex >= 0 && boneIndex < bones.Length)
color += bones[boneIndex].bindPoseColor * weight;
weightSum += weight;
}
color.a = 1f;
m_Colors.Add(Color.Lerp(Color.black, color, weightSum));
}
}
private void SkinVertices()
{
Debug.Assert(canSkin);
Debug.Assert(sprite != null);
var bones = sprite.GetBonesFromMode();
var originMatrix = Matrix4x4.TRS(sprite.pivotRectSpace, Quaternion.identity, Vector3.one);
var originInverseMatrix = originMatrix.inverse;
var spriteMatrix = sprite.GetLocalToWorldMatrixFromMode();
var spriteMatrixInv = spriteMatrix.inverse;
m_SkinnedVertices.Clear();
m_SkinningMatrices.Clear();
for (int i = 0; i < bones.Length; ++i)
m_SkinningMatrices.Add(spriteMatrixInv * originInverseMatrix * bones[i].localToWorldMatrix * bones[i].bindPose.matrix.inverse * spriteMatrix);
for (int i = 0; i < m_Vertices.Count; ++i)
{
var position = m_Vertices[i];
BoneWeight boneWeight = m_Weights[i];
float weightSum = boneWeight.weight0 + boneWeight.weight1 + boneWeight.weight2 + boneWeight.weight3;
if (weightSum > 0f)
{
var weightSumInv = 1f / weightSum;
var skinnedPosition = m_SkinningMatrices[boneWeight.boneIndex0].MultiplyPoint3x4(position) * boneWeight.weight0 * weightSumInv +
m_SkinningMatrices[boneWeight.boneIndex1].MultiplyPoint3x4(position) * boneWeight.weight1 * weightSumInv +
m_SkinningMatrices[boneWeight.boneIndex2].MultiplyPoint3x4(position) * boneWeight.weight2 * weightSumInv +
m_SkinningMatrices[boneWeight.boneIndex3].MultiplyPoint3x4(position) * boneWeight.weight3 * weightSumInv;
position = Vector3.Lerp(position, skinnedPosition, weightSum);
}
m_SkinnedVertices.Add(position);
}
}
protected override void OnAfterDeserialize()
{
SetMeshDirty();
}
}
}

View file

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

View file

@ -0,0 +1,192 @@
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
internal class SkeletonCache : TransformCache
{
[SerializeField]
private bool m_IsPosePreview = false;
[SerializeField]
private List<BoneCache> m_Bones = new List<BoneCache>();
public bool isPosePreview { get { return m_IsPosePreview; } }
public int BoneCount { get { return m_Bones.Count; } }
public virtual BoneCache[] bones
{
get { return m_Bones.ToArray(); }
}
public void AddBone(BoneCache bone)
{
AddBone(bone, true);
}
public void AddBone(BoneCache bone, bool worldPositionStays)
{
Debug.Assert(bone != null);
Debug.Assert(!Contains(bone));
if (bone.parent == null)
bone.SetParent(this, worldPositionStays);
m_Bones.Add(bone);
}
public void ReorderBones(IEnumerable<BoneCache> boneCache)
{
if (boneCache.Count() == m_Bones.Count)
{
foreach (var b in m_Bones)
{
if (!boneCache.Contains(b))
return;
}
m_Bones = boneCache.ToList();
}
}
public void DestroyBone(BoneCache bone)
{
Debug.Assert(bone != null);
Debug.Assert(Contains(bone));
m_Bones.Remove(bone);
var children = bone.children;
foreach (var child in children)
child.SetParent(bone.parent);
skinningCache.Destroy(bone);
}
public void SetDefaultPose()
{
foreach (var bone in m_Bones)
bone.SetDefaultPose();
m_IsPosePreview = false;
}
public void RestoreDefaultPose()
{
foreach (var bone in m_Bones)
bone.RestoreDefaultPose();
m_IsPosePreview = false;
skinningCache.events.skeletonPreviewPoseChanged.Invoke(this);
}
public void SetPosePreview()
{
m_IsPosePreview = true;
}
public BonePose[] GetLocalPose()
{
var pose = new List<BonePose>();
foreach (var bone in m_Bones)
pose.Add(bone.localPose);
return pose.ToArray();
}
public void SetLocalPose(BonePose[] pose)
{
Debug.Assert(m_Bones.Count == pose.Length);
for (var i = 0; i < m_Bones.Count; ++i)
m_Bones[i].localPose = pose[i];
m_IsPosePreview = true;
}
public BonePose[] GetWorldPose()
{
var pose = new List<BonePose>();
foreach (var bone in m_Bones)
pose.Add(bone.worldPose);
return pose.ToArray();
}
public void SetWorldPose(BonePose[] pose)
{
Debug.Assert(m_Bones.Count == pose.Length);
for (var i = 0; i < m_Bones.Count; ++i)
{
var bone = m_Bones[i];
var childWoldPose = bone.GetChildrenWoldPose();
bone.worldPose = pose[i];
bone.SetChildrenWorldPose(childWoldPose);
}
m_IsPosePreview = true;
}
public BoneCache GetBone(int index)
{
return m_Bones[index];
}
public int IndexOf(BoneCache bone)
{
return m_Bones.IndexOf(bone);
}
public bool Contains(BoneCache bone)
{
return m_Bones.Contains(bone);
}
public void Clear()
{
var roots = children;
foreach (var root in roots)
DestroyHierarchy(root);
m_Bones.Clear();
}
public string GetUniqueName(BoneCache bone)
{
Debug.Assert(Contains(bone));
var boneName = bone.name;
var names = m_Bones.ConvertAll(b => b.name);
var index = IndexOf(bone);
var count = 0;
Debug.Assert(index < names.Count);
for (var i = 0; i < index; ++i)
if (names[i].Equals(boneName))
++count;
if (count == 0)
return boneName;
return string.Format("{0} ({1})", boneName, count + 1);
}
private void DestroyHierarchy(TransformCache root)
{
Debug.Assert(root != null);
var children = root.children;
foreach (var child in children)
DestroyHierarchy(child);
skinningCache.Destroy(root);
}
}
}

View file

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

View file

@ -0,0 +1,181 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
internal static class SkeletonCacheExtensions
{
public static void RotateBones(this SkeletonCache skeleton, BoneCache[] bones, float deltaAngle)
{
Debug.Assert(skeleton != null);
foreach (var bone in bones)
{
Debug.Assert(bone != null);
Debug.Assert(skeleton.Contains(bone));
bone.localRotation *= Quaternion.AngleAxis(deltaAngle, Vector3.forward);
}
}
public static void MoveBones(this SkeletonCache skeleton, BoneCache[] bones, Vector3 deltaPosition)
{
Debug.Assert(skeleton != null);
foreach (var bone in bones)
{
Debug.Assert(bone != null);
Debug.Assert(skeleton.Contains(bone));
bone.position += deltaPosition;
if (bone.parentBone != null && bone.parentBone.chainedChild == bone)
bone.parentBone.OrientToChainedChild(false);
}
}
public static void FreeMoveBones(this SkeletonCache skeleton, BoneCache[] bones, Vector3 deltaPosition)
{
Debug.Assert(skeleton != null);
foreach (var bone in bones)
{
Debug.Assert(bone != null);
Debug.Assert(skeleton.Contains(bone));
var childrenWorldPose = bone.GetChildrenWoldPose();
if (bone.chainedChild != null && ArrayUtility.Contains(bones, bone.chainedChild) == false)
bone.chainedChild = null;
if (bone.parentBone != null && bone.parentBone.chainedChild == bone && ArrayUtility.Contains(bones, bone.parentBone) == false)
bone.parentBone.chainedChild = null;
bone.position += deltaPosition;
bone.SetChildrenWorldPose(childrenWorldPose);
}
}
public static void MoveJoints(this SkeletonCache skeleton, BoneCache[] bones, Vector3 deltaPosition)
{
Debug.Assert(skeleton != null);
foreach (var bone in bones)
{
Debug.Assert(bone != null);
Debug.Assert(skeleton.Contains(bone));
var childrenWorldPose = bone.GetChildrenWoldPose();
var endPosition = bone.endPosition;
bone.position += deltaPosition;
if (bone.localLength > 0f)
bone.endPosition = endPosition;
if (bone.parentBone != null && bone.parentBone.chainedChild == bone)
bone.parentBone.OrientToChainedChild(true);
bone.SetChildrenWorldPose(childrenWorldPose);
if (bone.chainedChild != null)
bone.OrientToChainedChild(true);
}
}
public static void SetEndPosition(this SkeletonCache skeleton, BoneCache bone, Vector3 endPosition)
{
Debug.Assert(skeleton != null);
Debug.Assert(bone != null);
Debug.Assert(skeleton.Contains(bone));
var childrenStorage = bone.GetChildrenWoldPose();
bone.endPosition = endPosition;
bone.SetChildrenWorldPose(childrenStorage);
}
public static BoneCache SplitBone(this SkeletonCache skeleton, BoneCache boneToSplit, float splitLength, string name)
{
Debug.Assert(skeleton.Contains(boneToSplit));
Debug.Assert(boneToSplit.length > splitLength);
var endPosition = boneToSplit.endPosition;
var chainedChild = boneToSplit.chainedChild;
var splitPosition = boneToSplit.position + boneToSplit.right * splitLength;
boneToSplit.length = splitLength;
var bone = skeleton.CreateBone(boneToSplit, splitPosition, endPosition, true, name);
if (chainedChild != null)
{
chainedChild.SetParent(bone);
bone.chainedChild = chainedChild;
}
return bone;
}
public static BoneCache CreateBone(this SkeletonCache skeleton, BoneCache parentBone, Vector3 position, Vector3 endPosition, bool isChained, string name)
{
Debug.Assert(skeleton != null);
if (parentBone != null)
Debug.Assert(skeleton.Contains(parentBone));
var bone = skeleton.skinningCache.CreateCache<BoneCache>();
bone.SetParent(parentBone);
bone.name = name;
bone.bindPoseColor = ModuleUtility.CalculateNiceColor(skeleton.BoneCount, 6);
bone.position = position;
bone.endPosition = endPosition;
if (isChained && parentBone != null)
parentBone.chainedChild = bone;
skeleton.AddBone(bone);
return bone;
}
public static void SetBones(this SkeletonCache skeleton, BoneCache[] bones)
{
skeleton.SetBones(bones, true);
}
public static void SetBones(this SkeletonCache skeleton, BoneCache[] bones, bool worldPositionStays)
{
skeleton.Clear();
skeleton.AddBones(bones, worldPositionStays);
skeleton.SetDefaultPose();
}
public static void AddBones(this SkeletonCache skeleton, BoneCache[] bones)
{
skeleton.AddBones(bones, true);
}
public static void AddBones(this SkeletonCache skeleton, BoneCache[] bones, bool worldPositionStays)
{
foreach (var bone in bones)
skeleton.AddBone(bone, worldPositionStays);
}
public static void DestroyBones(this SkeletonCache skeleton, BoneCache[] bones)
{
Debug.Assert(skeleton != null);
foreach (var bone in bones)
{
Debug.Assert(bone != null);
Debug.Assert(skeleton.Contains(bone));
skeleton.DestroyBone(bone);
}
}
}
}

View file

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

View file

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

View file

@ -0,0 +1,270 @@
using System;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
internal interface ISkinningCachePersistentState
{
String lastSpriteId
{
get;
set;
}
Tools lastUsedTool
{
get;
set;
}
List<int> lastBoneSelectionIds
{
get;
}
Texture2D lastTexture
{
get;
set;
}
SerializableDictionary<int, BonePose> lastPreviewPose
{
get;
}
SerializableDictionary<int, bool> lastBoneVisibility
{
get;
}
SerializableDictionary<int, bool> lastBoneExpansion
{
get;
}
SerializableDictionary<string, bool> lastSpriteVisibility
{
get;
}
SerializableDictionary<int, bool> lastGroupVisibility
{
get;
}
SkinningMode lastMode
{
get;
set;
}
bool lastVisibilityToolActive
{
get;
set;
}
int lastVisibilityToolIndex
{
get;
set;
}
IndexedSelection lastVertexSelection
{
get;
}
float lastBrushSize
{
get;
set;
}
float lastBrushHardness
{
get;
set;
}
float lastBrushStep
{
get;
set;
}
}
[Serializable]
internal class SkinningCachePersistentState
: ScriptableSingleton<SkinningCachePersistentState>
, ISkinningCachePersistentState
{
[SerializeField] private Tools m_LastUsedTool = Tools.EditPose;
[SerializeField] private SkinningMode m_LastMode = SkinningMode.Character;
[SerializeField] private string m_LastSpriteId = String.Empty;
[SerializeField] private List<int> m_LastBoneSelectionIds = new List<int>();
[SerializeField] private Texture2D m_LastTexture;
[SerializeField]
private SerializableDictionary<int, BonePose> m_SkeletonPreviewPose =
new SerializableDictionary<int, BonePose>();
[SerializeField]
private SerializableDictionary<int, bool> m_BoneVisibility =
new SerializableDictionary<int, bool>();
[SerializeField]
private SerializableDictionary<int, bool> m_BoneExpansion =
new SerializableDictionary<int, bool>();
[SerializeField]
private SerializableDictionary<string, bool> m_SpriteVisibility =
new SerializableDictionary<string, bool>();
[SerializeField]
private SerializableDictionary<int, bool> m_GroupVisibility =
new SerializableDictionary<int, bool>();
[SerializeField] private IndexedSelection m_VertexSelection;
[SerializeField] private bool m_VisibilityToolActive;
[SerializeField] private int m_VisibilityToolIndex = -1;
[SerializeField] private float m_LastBrushSize = 25f;
[SerializeField] private float m_LastBrushHardness = 1f;
[SerializeField] private float m_LastBrushStep = 20f;
public SkinningCachePersistentState()
{
m_VertexSelection = new IndexedSelection();
}
public void SetDefault()
{
m_LastUsedTool = Tools.EditPose;
m_LastMode = SkinningMode.Character;
m_LastSpriteId = String.Empty;
m_LastBoneSelectionIds.Clear();
m_LastTexture = null;
m_VertexSelection.Clear();
m_SkeletonPreviewPose.Clear();
m_BoneVisibility.Clear();
m_BoneExpansion.Clear();
m_SpriteVisibility.Clear();
m_GroupVisibility.Clear();
m_VisibilityToolActive = false;
m_VisibilityToolIndex = -1;
}
public string lastSpriteId
{
get { return m_LastSpriteId; }
set { m_LastSpriteId = value; }
}
public Tools lastUsedTool
{
get { return m_LastUsedTool; }
set { m_LastUsedTool = value; }
}
public List<int> lastBoneSelectionIds
{
get { return m_LastBoneSelectionIds; }
}
public Texture2D lastTexture
{
get { return m_LastTexture; }
set
{
if (value != m_LastTexture)
{
m_LastMode = SkinningMode.Character;
m_LastSpriteId = String.Empty;
m_LastBoneSelectionIds.Clear();
m_VertexSelection.Clear();
m_SkeletonPreviewPose.Clear();
m_BoneVisibility.Clear();
m_BoneExpansion.Clear();
m_SpriteVisibility.Clear();
m_GroupVisibility.Clear();
}
m_LastTexture = value;
}
}
public SerializableDictionary<int, BonePose> lastPreviewPose
{
get { return m_SkeletonPreviewPose; }
}
public SerializableDictionary<int, bool> lastBoneVisibility
{
get { return m_BoneVisibility; }
}
public SerializableDictionary<int, bool> lastBoneExpansion
{
get { return m_BoneExpansion; }
}
public SerializableDictionary<string, bool> lastSpriteVisibility
{
get { return m_SpriteVisibility; }
}
public SerializableDictionary<int, bool> lastGroupVisibility
{
get { return m_GroupVisibility; }
}
public SkinningMode lastMode
{
get { return m_LastMode; }
set { m_LastMode = value; }
}
public bool lastVisibilityToolActive
{
get { return m_VisibilityToolActive; }
set { m_VisibilityToolActive = value; }
}
public int lastVisibilityToolIndex
{
get { return m_VisibilityToolIndex; }
set { m_VisibilityToolIndex = value; }
}
public IndexedSelection lastVertexSelection
{
get { return m_VertexSelection; }
}
public float lastBrushSize
{
get { return m_LastBrushSize; }
set { m_LastBrushSize = value; }
}
public float lastBrushHardness
{
get { return m_LastBrushHardness; }
set { m_LastBrushHardness = value; }
}
public float lastBrushStep
{
get { return m_LastBrushStep; }
set { m_LastBrushStep = value; }
}
}
}

View file

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

View file

@ -0,0 +1,32 @@
using System;
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
internal enum SkinningMode
{
SpriteSheet,
Character
}
internal enum Tools
{
EditGeometry,
CreateVertex,
CreateEdge,
SplitEdge,
GenerateGeometry,
EditPose,
EditJoints,
CreateBone,
SplitBone,
ReparentBone,
WeightSlider,
WeightBrush,
GenerateWeights,
BoneInfluence,
CopyPaste,
Visibility,
SwitchMode
}
}

View file

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

View file

@ -0,0 +1,67 @@
using System;
using UnityEngine;
using UnityEngine.Events;
namespace UnityEditor.U2D.Animation
{
internal class SkinningEvents
{
public class SpriteEvent : UnityEvent<SpriteCache> {}
public class SkeletonEvent : UnityEvent<SkeletonCache> {}
public class MeshEvent : UnityEvent<MeshCache> {}
public class MeshPreviewEvent : UnityEvent<MeshPreviewCache> {}
public class SkinningModuleModeEvent : UnityEvent<SkinningMode> {}
public class BoneSelectionEvent : UnityEvent {}
public class BoneEvent : UnityEvent<BoneCache> {}
public class CharacterPartEvent : UnityEvent<CharacterPartCache> {}
public class ToolChangeEvent : UnityEvent<ITool> {}
public class RestoreBindPoseEvent : UnityEvent {}
public class CopyEvent : UnityEvent {}
public class PasteEvent : UnityEvent<bool, bool, bool, bool> {}
public class ShortcutEvent : UnityEvent<string> {}
public class BoneVisibilityEvent : UnityEvent<string> {}
public class SpriteLibraryEvent : UnityEvent {}
public class MeshPreviewBehaviourChangeEvent : UnityEvent<IMeshPreviewBehaviour> {}
private SpriteEvent m_SelectedSpriteChanged = new SpriteEvent();
private SkeletonEvent m_SkeletonPreviewPoseChanged = new SkeletonEvent();
private SkeletonEvent m_SkeletonBindPoseChanged = new SkeletonEvent();
private SkeletonEvent m_SkeletonTopologyChanged = new SkeletonEvent();
private MeshEvent m_MeshChanged = new MeshEvent();
private MeshPreviewEvent m_MeshPreviewChanged = new MeshPreviewEvent();
private SkinningModuleModeEvent m_SkinningModuleModeChanged = new SkinningModuleModeEvent();
private BoneSelectionEvent m_BoneSelectionChangedEvent = new BoneSelectionEvent();
private BoneEvent m_BoneNameChangedEvent = new BoneEvent();
private BoneEvent m_BoneDepthChangedEvent = new BoneEvent();
private CharacterPartEvent m_CharacterPartChanged = new CharacterPartEvent();
private ToolChangeEvent m_ToolChanged = new ToolChangeEvent();
private RestoreBindPoseEvent m_RestoreBindPose = new RestoreBindPoseEvent();
private CopyEvent m_CopyEvent = new CopyEvent();
private PasteEvent m_PasteEvent = new PasteEvent();
private ShortcutEvent m_ShortcutEvent = new ShortcutEvent();
private BoneVisibilityEvent m_BoneVisibilityEvent = new BoneVisibilityEvent();
private SpriteLibraryEvent m_SpriteLibraryEvent = new SpriteLibraryEvent();
private MeshPreviewBehaviourChangeEvent m_MeshPreviewBehaviourChange = new MeshPreviewBehaviourChangeEvent();
//Setting them as virtual so that we can create mock them
public virtual SpriteEvent selectedSpriteChanged { get { return m_SelectedSpriteChanged; } }
public virtual SkeletonEvent skeletonPreviewPoseChanged { get { return m_SkeletonPreviewPoseChanged; } }
public virtual SkeletonEvent skeletonBindPoseChanged { get { return m_SkeletonBindPoseChanged; } }
public virtual SkeletonEvent skeletonTopologyChanged { get { return m_SkeletonTopologyChanged; } }
public virtual MeshEvent meshChanged { get { return m_MeshChanged; } }
public virtual MeshPreviewEvent meshPreviewChanged { get { return m_MeshPreviewChanged; } }
public virtual SkinningModuleModeEvent skinningModeChanged { get { return m_SkinningModuleModeChanged; } }
public virtual BoneSelectionEvent boneSelectionChanged { get { return m_BoneSelectionChangedEvent; } }
public virtual BoneEvent boneNameChanged { get { return m_BoneNameChangedEvent; } }
public virtual BoneEvent boneDepthChanged { get { return m_BoneDepthChangedEvent; } }
public virtual CharacterPartEvent characterPartChanged { get { return m_CharacterPartChanged; } }
public virtual ToolChangeEvent toolChanged { get { return m_ToolChanged; } }
public virtual RestoreBindPoseEvent restoreBindPose { get { return m_RestoreBindPose; } }
public virtual CopyEvent copy { get { return m_CopyEvent; } }
public virtual PasteEvent paste { get { return m_PasteEvent; } }
public virtual ShortcutEvent shortcut { get { return m_ShortcutEvent; } }
public virtual BoneVisibilityEvent boneVisibility { get { return m_BoneVisibilityEvent; } }
public virtual SpriteLibraryEvent spriteLibraryChanged { get { return m_SpriteLibraryEvent; } }
public virtual MeshPreviewBehaviourChangeEvent meshPreviewBehaviourChange { get { return m_MeshPreviewBehaviourChange; } }
}
}

View file

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

View file

@ -0,0 +1,44 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
internal class SpriteCache : TransformCache
{
[SerializeField]
private string m_ID;
[SerializeField]
private Rect m_TextureRect;
[SerializeField]
private Vector2 m_PivotNormalized;
public string id
{
get { return m_ID; }
internal set { m_ID = value; }
}
public Rect textureRect
{
get { return m_TextureRect; }
set { m_TextureRect = value; }
}
public Vector2 pivotNormalized
{
get { return m_PivotNormalized; }
set { m_PivotNormalized = value; }
}
public Vector2 pivotRectSpace
{
get { return Vector2.Scale(textureRect.size, pivotNormalized); }
}
public Vector2 pivotTextureSpace
{
get { return localToWorldMatrix.MultiplyPoint3x4(pivotRectSpace); }
}
}
}

View file

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

View file

@ -0,0 +1,325 @@
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);
}
}
}

View file

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

View file

@ -0,0 +1,287 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
internal class TransformCache : SkinningObject, IEnumerable<TransformCache>
{
[SerializeField]
private TransformCache m_Parent;
[SerializeField]
private List<TransformCache> m_Children = new List<TransformCache>();
[SerializeField]
private Vector3 m_LocalPosition;
[SerializeField]
private Quaternion m_LocalRotation = Quaternion.identity;
[SerializeField]
private Vector3 m_LocalScale = Vector3.one;
[SerializeField]
private Matrix4x4 m_LocalToWorldMatrix = Matrix4x4.identity;
public TransformCache parent
{
get { return m_Parent; }
}
public TransformCache[] children
{
get { return m_Children.ToArray(); }
}
internal virtual int siblingIndex
{
get { return GetSiblingIndex(); }
set { SetSiblingIndex(value); }
}
public int ChildCount
{
get { return m_Children.Count; }
}
public Vector3 localPosition
{
get { return m_LocalPosition; }
set
{
m_LocalPosition = value;
Update();
}
}
public Quaternion localRotation
{
get { return m_LocalRotation; }
set
{
m_LocalRotation = MathUtility.NormalizeQuaternion(value);
Update();
}
}
public Vector3 localScale
{
get { return m_LocalScale; }
set
{
m_LocalScale = value;
Update();
}
}
public Vector3 position
{
get { return parentMatrix.MultiplyPoint3x4(localPosition); }
set { localPosition = parentMatrix.inverse.MultiplyPoint3x4(value); }
}
public Quaternion rotation
{
get { return GetGlobalRotation(); }
set { SetGlobalRotation(value); }
}
public Vector3 right
{
get { return localToWorldMatrix.MultiplyVector(Vector3.right).normalized; }
set { MatchDirection(Vector3.right, value); }
}
public Vector3 up
{
get { return localToWorldMatrix.MultiplyVector(Vector3.up).normalized; }
set { MatchDirection(Vector3.up, value); }
}
public Vector3 forward
{
get { return localToWorldMatrix.MultiplyVector(Vector3.forward).normalized; }
set { MatchDirection(Vector3.forward, value); }
}
public Matrix4x4 localToWorldMatrix
{
get { return m_LocalToWorldMatrix; }
}
public Matrix4x4 worldToLocalMatrix
{
get { return localToWorldMatrix.inverse; }
}
private Matrix4x4 parentMatrix
{
get
{
var parentMatrix = Matrix4x4.identity;
if (parent != null)
parentMatrix = parent.localToWorldMatrix;
return parentMatrix;
}
}
internal override void OnDestroy()
{
if (parent != null)
parent.RemoveChild(this);
m_Parent = null;
m_Children.Clear();
}
private void Update()
{
m_LocalToWorldMatrix = parentMatrix * Matrix4x4.TRS(localPosition, localRotation, localScale);
foreach (var child in m_Children)
child.Update();
}
private void AddChild(TransformCache transform)
{
m_Children.Add(transform);
}
private void InsertChildAt(int index, TransformCache transform)
{
m_Children.Insert(index, transform);
}
private void RemoveChild(TransformCache transform)
{
m_Children.Remove(transform);
}
private void RemoveChildAt(int index)
{
m_Children.RemoveAt(index);
}
private int GetSiblingIndex()
{
if (parent == null)
return -1;
return parent.m_Children.IndexOf(this);
}
private void SetSiblingIndex(int index)
{
if (parent != null)
{
var currentIndex = parent.m_Children.IndexOf(this);
var indexToRemove = index < currentIndex ? currentIndex + 1 : currentIndex;
parent.InsertChildAt(index, this);
parent.RemoveChildAt(indexToRemove);
}
}
public void SetParent(TransformCache newParent)
{
SetParent(newParent, true);
}
public void SetParent(TransformCache newParent, bool worldPositionStays)
{
if (m_Parent == newParent)
return;
var oldPosition = position;
var oldRotation = rotation;
if (m_Parent != null)
m_Parent.RemoveChild(this);
m_Parent = newParent;
if (m_Parent != null)
m_Parent.AddChild(this);
if (worldPositionStays)
{
position = oldPosition;
rotation = oldRotation;
}
else
{
Update();
}
}
private Quaternion GetGlobalRotation()
{
var globalRotation = localRotation;
var currentParent = parent;
while (currentParent != null)
{
globalRotation = ScaleMulQuat(currentParent.localScale, globalRotation);
globalRotation = currentParent.localRotation * globalRotation;
currentParent = currentParent.parent;
}
return globalRotation;
}
private void SetGlobalRotation(Quaternion r)
{
if (parent != null)
r = parent.InverseTransformRotation(r);
localRotation = r;
}
private Quaternion InverseTransformRotation(Quaternion r)
{
if (parent != null)
r = parent.InverseTransformRotation(r);
r = Quaternion.Inverse(localRotation) * r;
r = ScaleMulQuat(localScale, r);
return r;
}
private Quaternion ScaleMulQuat(Vector3 scale, Quaternion q)
{
var s = new Vector3(Chgsign(1f, scale.x), Chgsign(1f, scale.y), Chgsign(1f, scale.z));
q.x = Chgsign(q.x, s.y * s.z);
q.y = Chgsign(q.y, s.x * s.z);
q.z = Chgsign(q.z, s.x * s.y);
return q;
}
private float Chgsign(float x, float y)
{
return y < 0f ? -x : x;
}
private void MatchDirection(Vector3 localDirection, Vector3 worldDirection)
{
var direction = worldToLocalMatrix.MultiplyVector(worldDirection);
direction = Matrix4x4.TRS(Vector3.zero, localRotation, localScale).MultiplyVector(direction);
var scaledLocalDirection = Vector3.Scale(localDirection, localScale);
var deltaRotation = Quaternion.identity;
if (scaledLocalDirection.sqrMagnitude > 0f)
{
var axis = Vector3.Cross(scaledLocalDirection, direction);
var angle = Vector3.SignedAngle(scaledLocalDirection, direction, axis);
deltaRotation = Quaternion.AngleAxis(angle, axis);
}
localRotation = deltaRotation;
}
IEnumerator<TransformCache> IEnumerable<TransformCache>.GetEnumerator()
{
return m_Children.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return (IEnumerator)m_Children.GetEnumerator();
}
}
}

View file

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

View file

@ -0,0 +1,43 @@
using System;
using System.Linq;
using UnityEngine;
namespace UnityEditor.U2D.Animation
{
internal static class TransformCacheExtensions
{
internal static bool IsDescendant<T>(this T transform, T ancestor) where T : TransformCache
{
if (ancestor != null)
{
var parent = transform.parent;
while (parent != null)
{
if (parent == ancestor)
return true;
parent = parent.parent;
}
}
return false;
}
internal static bool IsDescendant<T>(this T transform, T[] ancestors) where T : TransformCache
{
return ancestors.FirstOrDefault( t => transform.IsDescendant<T>(t) ) != null;
}
internal static T[] FindRoots<T>(this T[] transforms) where T : TransformCache
{
return transforms.Where(t => t.IsDescendant(transforms) == false).ToArray();
}
internal static T FindRoot<T>(this T transform, T[] transforms) where T : TransformCache
{
var roots = transforms.FindRoots<T>();
return roots.FirstOrDefault( r => transform == r || IsDescendant<T>(transform, r) );
}
}
}

View file

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