#pragma warning disable 0168 // variable declared but not used.
using System;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using UnityEngine.Scripting;
using UnityEngine.U2D.Common;
using Unity.Collections;
using Unity.Collections.LowLevel.Unsafe;
using Unity.Profiling;
using UnityEngine.Rendering;
using UnityEngine.Scripting.APIUpdating;
namespace UnityEngine.U2D.Animation
{
///
/// Represents vertex position.
///
internal struct PositionVertex
{
///
/// Vertex position.
///
public Vector3 position;
}
///
/// Represents vertex position and tangent.
///
internal struct PositionTangentVertex
{
///
/// Vertex position.
///
public Vector3 position;
///
/// Vertex tangent.
///
public Vector4 tangent;
}
///
/// The state of the Sprite Skin.
///
public enum SpriteSkinState
{
///
/// Sprite Renderer doesn't contain a sprite.
///
SpriteNotFound,
///
/// Sprite referenced in the Sprite Renderer doesn't have skinning information.
///
SpriteHasNoSkinningInformation,
///
/// Sprite referenced in the Sprite Renderer doesn't have weights.
///
SpriteHasNoWeights,
///
/// Root transform is not assigned.
///
RootTransformNotFound,
///
/// Bone transform array is not assigned.
///
InvalidTransformArray,
///
/// Bone transform array has incorrect length.
///
InvalidTransformArrayLength,
///
/// One or more bone transforms is not assigned.
///
TransformArrayContainsNull,
///
/// Bone weights are invalid.
///
InvalidBoneWeights,
///
/// Sprite Skin is ready for deformation.
///
Ready
}
///
/// Deforms the Sprite that is currently assigned to the SpriteRenderer in the same GameObject.
///
[Preserve]
[ExecuteInEditMode]
[DefaultExecutionOrder(UpdateOrder.spriteSkinUpdateOrder)]
[DisallowMultipleComponent]
[RequireComponent(typeof(SpriteRenderer))]
[AddComponentMenu("2D Animation/Sprite Skin")]
[IconAttribute(IconUtility.IconPath + "Animation.SpriteSkin.png")]
[MovedFrom("UnityEngine.U2D.Experimental.Animation")]
[HelpURL("https://docs.unity3d.com/Packages/com.unity.2d.animation@latest/index.html?subfolder=/manual/SpriteSkin.html")]
public sealed class SpriteSkin : MonoBehaviour, IPreviewable, ISerializationCallbackReceiver
{
internal static class Profiling
{
public static readonly ProfilerMarker cacheCurrentSprite = new ProfilerMarker("SpriteSkin.CacheCurrentSprite");
public static readonly ProfilerMarker cacheHierarchy = new ProfilerMarker("SpriteSkin.CacheHierarchy");
public static readonly ProfilerMarker getSpriteBonesTransformFromGuid = new ProfilerMarker("SpriteSkin.GetSpriteBoneTransformsFromGuid");
public static readonly ProfilerMarker getSpriteBonesTransformFromPath = new ProfilerMarker("SpriteSkin.GetSpriteBoneTransformsFromPath");
}
internal struct TransformData
{
public string fullName;
public Transform transform;
}
[SerializeField]
Transform m_RootBone;
[SerializeField]
Transform[] m_BoneTransforms = Array.Empty();
[SerializeField]
Bounds m_Bounds;
[SerializeField]
bool m_AlwaysUpdate = true;
[SerializeField]
bool m_AutoRebind = false;
// The deformed m_SpriteVertices stores all 'HOT' channels only in single-stream and essentially depends on Sprite Asset data.
// The order of storage if present is POSITION, NORMALS, TANGENTS.
NativeByteArray m_DeformedVertices;
int m_CurrentDeformVerticesLength = 0;
SpriteRenderer m_SpriteRenderer;
int m_CurrentDeformSprite = 0;
int m_SpriteId = -1;
bool m_IsValid = false;
SpriteSkinState m_State;
int m_TransformsHash = 0;
bool m_ForceCpuDeformation = false;
int m_TransformId;
NativeArray m_BoneTransformId;
int m_RootBoneTransformId;
NativeCustomSlice m_SpriteUVs;
NativeCustomSlice m_SpriteVertices;
NativeCustomSlice m_SpriteTangents;
NativeCustomSlice m_SpriteBoneWeights;
NativeCustomSlice m_SpriteBindPoses;
NativeCustomSlice m_BoneTransformIdNativeSlice;
bool m_SpriteHasTangents;
int m_SpriteVertexStreamSize;
int m_SpriteVertexCount;
int m_SpriteTangentVertexOffset;
int m_DataIndex = -1;
bool m_BoneCacheUpdateToDate = false;
internal Dictionary> m_HierarchyCache = new Dictionary>();
NativeArray m_OutlineIndexCache;
NativeArray m_StaticOutlineVertexCache;
NativeArray m_DeformedOutlineVertexCache;
int m_VertexDeformationHash = 0;
Sprite m_Sprite;
internal NativeArray boneTransformId => m_BoneTransformId;
internal int rootBoneTransformId => m_RootBoneTransformId;
internal DeformationMethods currentDeformationMethod { get; private set; }
internal BaseDeformationSystem deformationSystem { get; private set; }
#if ENABLE_URP
///
/// Returns an array of the outline indices.
/// The indices are sorted and laid out with line topology.
///
internal NativeArray outlineIndices => m_OutlineIndexCache;
///
/// Returns an array of the deformed outline vertices.
///
internal NativeArray outlineVertices => m_DeformedOutlineVertexCache;
#endif
///
/// Returns a hash which is updated every time the mesh is deformed.
///
internal int vertexDeformationHash => m_VertexDeformationHash;
internal Sprite sprite => m_Sprite;
internal SpriteRenderer spriteRenderer => m_SpriteRenderer;
internal NativeCustomSlice spriteBoneWeights => m_SpriteBoneWeights;
///
/// Gets the index of the SpriteSkin in the SpriteSkinComposite.
///
internal int dataIndex => m_DataIndex;
///
/// Get and set the Auto Rebind property.
/// When enabled, Sprite Skin attempts to automatically locate the Transform that is needed for the current Sprite assigned to the Sprite Renderer.
///
public bool autoRebind
{
get => m_AutoRebind;
set
{
m_AutoRebind = value;
if (isActiveAndEnabled)
{
CacheHierarchy();
CacheCurrentSprite(m_AutoRebind);
}
}
}
///
/// Returns the Transform Components that are used for deformation.
/// Do not modify elements of the returned array.
///
/// An array of Transform Components.
public Transform[] boneTransforms => m_BoneTransforms;
///
/// Sets the Transform Components that are used for deformation.
///
/// Array of new bone Transforms.
/// The state of the Sprite Skin.
public SpriteSkinState SetBoneTransforms(Transform[] boneTransformsArray)
{
m_BoneTransforms = boneTransformsArray;
var result = CacheValidFlag();
if (isActiveAndEnabled)
OnBoneTransformChanged();
return result;
}
///
/// Returns the Transform Component that represents the root bone for deformation.
///
/// A Transform Component.
public Transform rootBone => m_RootBone;
///
/// Sets the Transform Component that represents the root bone for deformation.
///
/// Root bone Transform Component.
/// The state of the Sprite Skin.
public SpriteSkinState SetRootBone(Transform rootBoneTransform)
{
m_RootBone = rootBoneTransform;
var result = CacheValidFlag();
if (isActiveAndEnabled)
{
CacheHierarchy();
OnRootBoneTransformChanged();
}
return result;
}
internal Bounds bounds
{
get => m_Bounds;
set => m_Bounds = value;
}
///
/// Determines if the SpriteSkin executes even if the associated
/// SpriteRenderer has been culled from view.
///
public bool alwaysUpdate
{
get => m_AlwaysUpdate;
set => m_AlwaysUpdate = value;
}
///
/// Always run a deformation pass on the CPU.
/// If GPU deformation is enabled, enabling forceCpuDeformation will cause the deformation to run twice, one time on the CPU and one time on the GPU.
///
public bool forceCpuDeformation
{
get => m_ForceCpuDeformation;
set
{
if (m_ForceCpuDeformation == value)
return;
m_ForceCpuDeformation = value;
if (isActiveAndEnabled)
{
UpdateSpriteDeformationData();
DeformationManager.instance.CopyToSpriteSkinData(this);
}
}
}
///
/// Resets the bone transforms to the bind pose.
///
/// True if successful.
public bool ResetBindPose()
{
if (!isValid)
return false;
var spriteBones = spriteRenderer.sprite.GetBones();
for (var i = 0; i < boneTransforms.Length; ++i)
{
var boneTransform = boneTransforms[i];
var spriteBone = spriteBones[i];
if (spriteBone.parentId != -1)
{
boneTransform.localPosition = spriteBone.position;
boneTransform.localRotation = spriteBone.rotation;
boneTransform.localScale = Vector3.one;
}
}
return true;
}
internal bool isValid => this.Validate() == SpriteSkinState.Ready;
#if UNITY_EDITOR
internal static Events.UnityEvent onDrawGizmos = new Events.UnityEvent();
void OnDrawGizmos() => onDrawGizmos.Invoke();
internal bool ignoreNextSpriteChange { get; set; } = true;
#endif
internal void Awake()
{
m_SpriteRenderer = GetComponent();
m_Sprite = m_SpriteRenderer.sprite;
m_SpriteId = m_Sprite != null ? m_Sprite.GetInstanceID() : 0;
}
void OnEnable()
{
m_TransformId = gameObject.transform.GetInstanceID();
m_TransformsHash = 0;
currentDeformationMethod = SpriteSkinUtility.CanSpriteSkinUseGpuDeformation(this) ? DeformationMethods.Gpu : DeformationMethods.Cpu;
Awake();
CacheCurrentSprite(false);
UpdateSpriteDeformationData();
if (m_HierarchyCache.Count == 0)
CacheHierarchy();
RefreshBoneTransforms();
DeformationManager.instance.AddSpriteSkin(this);
SpriteSkinContainer.instance.AddSpriteSkin(this);
m_SpriteRenderer.RegisterSpriteChangeCallback(OnSpriteChanged);
}
void OnDisable()
{
DeactivateSkinning();
BufferManager.instance.ReturnBuffer(GetInstanceID());
deformationSystem?.RemoveSpriteSkin(this);
deformationSystem = null;
SpriteSkinContainer.instance.RemoveSpriteSkin(this);
ResetBoneTransformIdCache();
DisposeOutlineCaches();
}
void RefreshBoneTransforms()
{
DeformationManager.instance.RemoveBoneTransforms(this);
CacheBoneTransformIds();
DeformationManager.instance.AddSpriteSkinBoneTransform(this);
CacheValidFlag();
DeformationManager.instance.CopyToSpriteSkinData(this);
}
void OnSpriteChanged(SpriteRenderer updatedSpriteRenderer)
{
m_Sprite = updatedSpriteRenderer.sprite;
m_SpriteId = m_Sprite != null ? m_Sprite.GetInstanceID() : 0;
}
void CacheBoneTransformIds()
{
m_BoneCacheUpdateToDate = true;
var boneCount = 0;
for (var i = 0; i < boneTransforms?.Length; ++i)
{
if (boneTransforms[i] != null)
++boneCount;
}
if (m_BoneTransformId != default && m_BoneTransformId.IsCreated)
NativeArrayHelpers.ResizeIfNeeded(ref m_BoneTransformId, boneCount);
else
m_BoneTransformId = new NativeArray(boneCount, Allocator.Persistent);
m_RootBoneTransformId = rootBone != null ? rootBone.GetInstanceID() : 0;
m_BoneTransformIdNativeSlice = new NativeCustomSlice(m_BoneTransformId);
for (int i = 0, j = 0; i < boneTransforms?.Length; ++i)
{
if (boneTransforms[i] != null)
{
m_BoneTransformId[j] = boneTransforms[i].GetInstanceID();
++j;
}
}
}
void OnBoneTransformChanged()
{
RefreshBoneTransforms();
SpriteSkinContainer.instance.BoneTransformsChanged(this);
}
void OnRootBoneTransformChanged()
{
RefreshBoneTransforms();
SpriteSkinContainer.instance.BoneTransformsChanged(this);
}
///
/// Called before object is serialized.
///
public void OnBeforeSerialize()
{
OnBeforeSerializeBatch();
}
///
/// Called after object is deserialized.
///
public void OnAfterDeserialize()
{
OnAfterSerializeBatch();
}
void OnBeforeSerializeBatch() { }
void OnAfterSerializeBatch()
{
#if UNITY_EDITOR
m_BoneCacheUpdateToDate = false;
#endif
}
internal void OnEditorEnable()
{
Awake();
}
SpriteSkinState CacheValidFlag()
{
m_State = this.Validate();
m_IsValid = m_State == SpriteSkinState.Ready;
if (!m_IsValid)
DeactivateSkinning();
return m_State;
}
internal bool BatchValidate()
{
if (!m_BoneCacheUpdateToDate)
{
RefreshBoneTransforms();
}
CacheCurrentSprite(m_AutoRebind);
var hasSprite = m_CurrentDeformSprite != 0;
return m_IsValid && hasSprite && m_SpriteRenderer.enabled && (alwaysUpdate || m_SpriteRenderer.isVisible);
}
void Reset()
{
Awake();
if (isActiveAndEnabled)
{
CacheValidFlag();
if (!m_BoneCacheUpdateToDate)
{
RefreshBoneTransforms();
}
DeformationManager.instance.CopyToSpriteSkinData(this);
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
void ResetBoneTransformIdCache()
{
m_BoneTransformId.DisposeIfCreated();
m_BoneTransformId = default;
m_RootBoneTransformId = -1;
m_BoneCacheUpdateToDate = false;
}
internal NativeByteArray GetDeformedVertices(int spriteVertexCount)
{
if (sprite != null)
{
if (m_CurrentDeformVerticesLength != spriteVertexCount)
{
m_TransformsHash = 0;
m_CurrentDeformVerticesLength = spriteVertexCount;
}
}
else
{
m_CurrentDeformVerticesLength = 0;
}
m_DeformedVertices = BufferManager.instance.GetBuffer(GetInstanceID(), m_CurrentDeformVerticesLength);
return m_DeformedVertices;
}
///
/// Returns whether this SpriteSkin has currently deformed vertices.
///
/// Returns true if this SpriteSkin has currently deformed vertices. Returns false otherwise.
public bool HasCurrentDeformedVertices()
{
if (!m_IsValid)
return false;
return m_DataIndex >= 0 && deformationSystem != null && deformationSystem.IsSpriteSkinActiveForDeformation(this);
}
///
/// Gets a byte array to the currently deformed vertices for this SpriteSkin.
///
/// Returns a reference to the currently deformed vertices. This is valid only for this calling frame.
///
/// Thrown when there are no currently deformed vertices.
/// HasCurrentDeformedVertices can be used to verify if there are any deformed vertices available.
///
internal NativeArray GetCurrentDeformedVertices()
{
if (!m_IsValid)
throw new InvalidOperationException("The SpriteSkin deformation is not valid.");
if (m_DataIndex < 0)
throw new InvalidOperationException("There are no currently deformed vertices.");
var buffer = deformationSystem?.GetDeformableBufferForSpriteSkin(this) ?? default;
if (buffer == default)
throw new InvalidOperationException("There are no currently deformed vertices.");
return buffer;
}
///
/// Gets an array of currently deformed position vertices for this SpriteSkin.
///
/// Returns a reference to the currently deformed vertices. This is valid only for this calling frame.
///
/// Thrown when there are no currently deformed vertices or if the deformed vertices does not contain only
/// position data. HasCurrentDeformedVertices can be used to verify if there are any deformed vertices available.
///
internal NativeSlice GetCurrentDeformedVertexPositions()
{
if (!m_IsValid)
throw new InvalidOperationException("The SpriteSkin deformation is not valid.");
if (sprite.HasVertexAttribute(VertexAttribute.Tangent))
throw new InvalidOperationException("This SpriteSkin has deformed tangents");
if (!sprite.HasVertexAttribute(VertexAttribute.Position))
throw new InvalidOperationException("This SpriteSkin does not have deformed positions.");
var deformedBuffer = GetCurrentDeformedVertices();
return deformedBuffer.Slice().SliceConvert();
}
///
/// Gets an array of currently deformed position and tangent vertices for this SpriteSkin.
///
///
/// Returns a reference to the currently deformed position and tangent vertices. This is valid only for this calling frame.
///
///
/// Thrown when there are no currently deformed vertices or if the deformed vertices does not contain only
/// position and tangent data. HasCurrentDeformedVertices can be used to verify if there are any deformed vertices available.
///
internal NativeSlice GetCurrentDeformedVertexPositionsAndTangents()
{
if (!m_IsValid)
throw new InvalidOperationException("The SpriteSkin deformation is not valid.");
if (!sprite.HasVertexAttribute(VertexAttribute.Tangent))
throw new InvalidOperationException("This SpriteSkin does not have deformed tangents");
if (!sprite.HasVertexAttribute(VertexAttribute.Position))
throw new InvalidOperationException("This SpriteSkin does not have deformed positions.");
var deformedBuffer = GetCurrentDeformedVertices();
return deformedBuffer.Slice().SliceConvert();
}
///
/// Gets an enumerable to iterate through all deformed vertex positions of this SpriteSkin.
///
/// Returns an IEnumerable to deformed vertex positions.
///
/// Thrown when there is no vertex positions or deformed vertices.
/// HasCurrentDeformedVertices can be used to verify if there are any deformed vertices available.
///
public IEnumerable GetDeformedVertexPositionData()
{
if (!m_IsValid)
throw new InvalidOperationException("The SpriteSkin deformation is not valid.");
var hasPosition = sprite.HasVertexAttribute(VertexAttribute.Position);
if (!hasPosition)
throw new InvalidOperationException("Sprite does not have vertex position data.");
var rawBuffer = GetCurrentDeformedVertices();
var rawSlice = rawBuffer.Slice(sprite.GetVertexStreamOffset(VertexAttribute.Position));
return new NativeCustomSliceEnumerator(rawSlice, m_SpriteVertexCount, m_SpriteVertexStreamSize);
}
///
/// Gets an enumerable to iterate through all deformed vertex tangents of this SpriteSkin.
///
/// Returns an IEnumerable to deformed vertex tangents.
///
/// Thrown when there is no vertex tangents or deformed vertices.
/// HasCurrentDeformedVertices can be used to verify if there are any deformed vertices available.
///
public IEnumerable GetDeformedVertexTangentData()
{
if (!m_IsValid)
throw new InvalidOperationException("The SpriteSkin deformation is not valid.");
var hasTangent = sprite.HasVertexAttribute(VertexAttribute.Tangent);
if (!hasTangent)
throw new InvalidOperationException("Sprite does not have vertex tangent data.");
var rawBuffer = GetCurrentDeformedVertices();
var rawSlice = rawBuffer.Slice(sprite.GetVertexStreamOffset(VertexAttribute.Tangent));
return new NativeCustomSliceEnumerator(rawSlice, m_SpriteVertexCount, m_SpriteVertexStreamSize);
}
void DisposeOutlineCaches()
{
m_OutlineIndexCache.DisposeIfCreated();
m_StaticOutlineVertexCache.DisposeIfCreated();
m_DeformedOutlineVertexCache.DisposeIfCreated();
m_OutlineIndexCache = default;
m_StaticOutlineVertexCache = default;
m_DeformedOutlineVertexCache = default;
}
///
/// Used by the animation clip preview window.
/// Recommended to not use outside of this purpose.
///
public void OnPreviewUpdate()
{
#if UNITY_EDITOR
if (IsInGUIUpdateLoop())
Deform();
#endif
}
static bool IsInGUIUpdateLoop() => Event.current != null;
void Deform()
{
CacheCurrentSprite(m_AutoRebind);
if (isValid && enabled && (alwaysUpdate || m_SpriteRenderer.isVisible))
{
var transformHash = SpriteSkinUtility.CalculateTransformHash(this);
var spriteVertexCount = sprite.GetVertexStreamSize() * sprite.GetVertexCount();
if (spriteVertexCount > 0 && m_TransformsHash != transformHash)
{
var inputVertices = GetDeformedVertices(spriteVertexCount);
SpriteSkinUtility.Deform(sprite, gameObject.transform.worldToLocalMatrix, boneTransforms, inputVertices.array);
SpriteSkinUtility.UpdateBounds(this, inputVertices.array);
InternalEngineBridge.SetDeformableBuffer(spriteRenderer, inputVertices.array);
m_TransformsHash = transformHash;
m_CurrentDeformSprite = m_SpriteId;
PostDeform(true);
}
}
else if (!InternalEngineBridge.IsUsingDeformableBuffer(spriteRenderer, IntPtr.Zero))
{
DeactivateSkinning();
}
}
internal void PostDeform(bool didDeform)
{
if (didDeform)
{
#if ENABLE_URP
UpdateDeformedOutlineCache();
#endif
m_VertexDeformationHash = Time.frameCount;
}
}
void CacheCurrentSprite(bool rebind)
{
if (m_CurrentDeformSprite == m_SpriteId)
return;
using (Profiling.cacheCurrentSprite.Auto())
{
DeactivateSkinning();
m_CurrentDeformSprite = m_SpriteId;
if (rebind && m_CurrentDeformSprite > 0 && rootBone != null)
{
if (!SpriteSkinHelpers.GetSpriteBonesTransforms(this, out var transforms))
Debug.LogWarning($"Rebind failed for {name}. Could not find all bones required by the Sprite: {sprite.name}.");
SetBoneTransforms(transforms);
}
UpdateSpriteDeformationData();
DeformationManager.instance.CopyToSpriteSkinData(this);
CacheValidFlag();
m_TransformsHash = 0;
}
}
void UpdateSpriteDeformationData()
{
#if ENABLE_URP
CacheSpriteOutline();
#endif
if (sprite == null)
{
m_SpriteUVs = NativeCustomSlice.Default();
m_SpriteVertices = NativeCustomSlice.Default();
m_SpriteTangents = NativeCustomSlice.Default();
m_SpriteBoneWeights = NativeCustomSlice.Default();
m_SpriteBindPoses = NativeCustomSlice.Default();
m_SpriteHasTangents = false;
m_SpriteVertexStreamSize = 0;
m_SpriteVertexCount = 0;
m_SpriteTangentVertexOffset = 0;
}
else
{
var cacheFullMesh = currentDeformationMethod == DeformationMethods.Cpu || forceCpuDeformation;
if (cacheFullMesh)
{
m_SpriteVertices = new NativeCustomSlice(sprite.GetVertexAttribute(VertexAttribute.Position));
m_SpriteVertexCount = sprite.GetVertexCount();
m_SpriteVertexStreamSize = sprite.GetVertexStreamSize();
m_SpriteTangents = new NativeCustomSlice(sprite.GetVertexAttribute(VertexAttribute.Tangent));
m_SpriteHasTangents = sprite.HasVertexAttribute(VertexAttribute.Tangent);
m_SpriteTangentVertexOffset = sprite.GetVertexStreamOffset(VertexAttribute.Tangent);
}
else
{
m_SpriteVertices = new NativeCustomSlice(m_StaticOutlineVertexCache);
m_SpriteVertexCount = m_SpriteVertices.length;
m_SpriteVertexStreamSize = sizeof(float) * 3;
m_SpriteTangents = new NativeCustomSlice(sprite.GetVertexAttribute(VertexAttribute.Tangent));
m_SpriteHasTangents = false;
m_SpriteTangentVertexOffset = 0;
}
m_SpriteUVs = new NativeCustomSlice(sprite.GetVertexAttribute(VertexAttribute.TexCoord0));
m_SpriteBoneWeights = new NativeCustomSlice(sprite.GetVertexAttribute(VertexAttribute.BlendWeight));
m_SpriteBindPoses = new NativeCustomSlice(sprite.GetBindPoses());
}
}
#if ENABLE_URP
void UpdateDeformedOutlineCache()
{
if (sprite == null)
return;
if (!m_OutlineIndexCache.IsCreated || !m_DeformedOutlineVertexCache.IsCreated)
return;
if (!HasCurrentDeformedVertices())
return;
var buffer = GetCurrentDeformedVertices();
var indexCache = m_OutlineIndexCache;
var vertexCache = m_DeformedOutlineVertexCache;
BurstedSpriteSkinUtilities.SetVertexPositionFromByteBuffer(in buffer, in indexCache, ref vertexCache, m_SpriteVertexStreamSize);
m_DeformedOutlineVertexCache = vertexCache;
}
void CacheSpriteOutline()
{
DisposeOutlineCaches();
if (sprite == null)
return;
CacheOutlineIndices(out var maxIndex);
var cacheSize = maxIndex + 1;
CacheOutlineVertices(cacheSize);
}
void CacheOutlineIndices(out int maxIndex)
{
var indices = sprite.GetIndices();
var edgeNativeArr = MeshUtilities.GetOutlineEdges(in indices);
m_OutlineIndexCache = new NativeArray(edgeNativeArr.Length * 2, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
maxIndex = 0;
for (var i = 0; i < edgeNativeArr.Length; ++i)
{
var indexX = edgeNativeArr[i].x;
var indexY = edgeNativeArr[i].y;
m_OutlineIndexCache[i * 2] = indexX;
m_OutlineIndexCache[(i * 2) + 1] = indexY;
if (indexX > maxIndex)
maxIndex = indexX;
if (indexY > maxIndex)
maxIndex = indexY;
}
edgeNativeArr.Dispose();
}
void CacheOutlineVertices(int cacheSize)
{
m_DeformedOutlineVertexCache = new NativeArray(cacheSize, Allocator.Persistent, NativeArrayOptions.UninitializedMemory);
m_StaticOutlineVertexCache = new NativeArray(cacheSize, Allocator.Persistent);
var vertices = sprite.GetVertexAttribute(VertexAttribute.Position);
var vertexCache = m_StaticOutlineVertexCache;
for (var i = 0; i < m_OutlineIndexCache.Length; ++i)
{
var index = m_OutlineIndexCache[i];
vertexCache[index] = vertices[index];
}
m_StaticOutlineVertexCache = vertexCache;
}
#endif
internal void CopyToSpriteSkinData(ref SpriteSkinData data, int spriteSkinIndex)
{
if (!m_BoneCacheUpdateToDate)
{
RefreshBoneTransforms();
}
CacheCurrentSprite(m_AutoRebind);
data.vertices = m_SpriteVertices;
data.boneWeights = m_SpriteBoneWeights;
data.bindPoses = m_SpriteBindPoses;
data.tangents = m_SpriteTangents;
data.hasTangents = m_SpriteHasTangents;
data.spriteVertexStreamSize = m_SpriteVertexStreamSize;
data.spriteVertexCount = m_SpriteVertexCount;
data.tangentVertexOffset = m_SpriteTangentVertexOffset;
data.transformId = m_TransformId;
data.boneTransformId = m_BoneTransformIdNativeSlice;
m_DataIndex = spriteSkinIndex;
}
internal bool NeedToUpdateDeformationCache()
{
unsafe
{
var iptr = new IntPtr(sprite.GetVertexAttribute(VertexAttribute.TexCoord0).GetUnsafeReadOnlyPtr());
var rs = m_SpriteUVs.data != iptr;
if (rs)
{
UpdateSpriteDeformationData();
deformationSystem.CopyToSpriteSkinData(this);
DeformationManager.instance.CopyToSpriteSkinData(this);
}
return rs;
}
}
internal void CacheHierarchy()
{
using (Profiling.cacheHierarchy.Auto())
{
m_HierarchyCache.Clear();
if (rootBone == null || !m_AutoRebind)
return;
var boneCount = CountChildren(rootBone);
m_HierarchyCache.EnsureCapacity(boneCount + 1);
SpriteSkinHelpers.CacheChildren(rootBone, m_HierarchyCache);
foreach (var entry in m_HierarchyCache)
{
if (entry.Value.Count == 1)
continue;
var count = entry.Value.Count;
for (var i = 0; i < count; ++i)
{
var transformEntry = entry.Value[i];
transformEntry.fullName = SpriteSkinHelpers.GenerateTransformPath(rootBone, transformEntry.transform);
entry.Value[i] = transformEntry;
}
}
}
}
internal void DeactivateSkinning()
{
if (m_SpriteRenderer != null)
{
var currentSprite = sprite;
if (currentSprite != null)
InternalEngineBridge.SetLocalAABB(m_SpriteRenderer, currentSprite.bounds);
m_SpriteRenderer.DeactivateDeformableBuffer();
}
m_TransformsHash = 0;
}
internal void ResetSprite()
{
m_CurrentDeformSprite = 0;
CacheValidFlag();
}
internal void SetDeformationSystem(BaseDeformationSystem newDeformationSystem)
{
deformationSystem = newDeformationSystem;
currentDeformationMethod = deformationSystem.deformationMethod;
}
static int CountChildren(Transform transform)
{
var childCount = transform.childCount;
var count = childCount;
for (var i = 0; i < childCount; ++i)
count += CountChildren(transform.GetChild(i));
return count;
}
}
}