using System.Collections.Generic;
namespace UnityEngine.U2D.Animation
{
///
/// The available modes for batched Sprite Skin deformation.
///
public enum DeformationMethods
{
///
/// The Sprite Skin is deformed, in batch, on the CPU.
///
Cpu = 0,
///
/// The Sprite Skin is deformed, in batch, on the GPU.
///
Gpu = 1,
///
/// Used as a default value when no deformation method is chosen.
///
None = 2
}
internal class DeformationManager : ScriptableObject
{
static DeformationManager s_Instance;
public static DeformationManager instance
{
get
{
if (s_Instance == null)
{
var managers = Resources.FindObjectsOfTypeAll();
if (managers.Length > 0)
s_Instance = managers[0];
else
s_Instance = ScriptableObject.CreateInstance();
s_Instance.hideFlags = HideFlags.HideAndDontSave;
s_Instance.Init();
}
return s_Instance;
}
}
BaseDeformationSystem[] m_DeformationSystems;
[SerializeField]
GameObject m_Helper;
internal GameObject helperGameObject => m_Helper;
bool canUseGpuDeformation { get; set; }
bool m_WasUsingGpuDeformationLastFrame;
void OnEnable()
{
s_Instance = this;
canUseGpuDeformation = SpriteSkinUtility.CanUseGpuDeformation();
m_WasUsingGpuDeformationLastFrame = SpriteSkinUtility.IsUsingGpuDeformation();
Init();
}
void Init()
{
CreateBatchSystems();
CreateHelper();
}
void CreateBatchSystems()
{
if (m_DeformationSystems != null)
return;
var noOfSystems = canUseGpuDeformation ? 2 : 1;
m_DeformationSystems = new BaseDeformationSystem[noOfSystems];
m_DeformationSystems[(int)DeformationMethods.Cpu] = new CpuDeformationSystem();
if (canUseGpuDeformation)
m_DeformationSystems[(int)DeformationMethods.Gpu] = new GpuDeformationSystem();
for (var i = 0; i < m_DeformationSystems.Length; ++i)
m_DeformationSystems[i].Initialize(m_DeformationSystems[i].GetHashCode());
}
void CreateHelper()
{
if (m_Helper != null)
return;
m_Helper = new GameObject("DeformationManagerUpdater");
m_Helper.hideFlags = HideFlags.HideAndDontSave;
var helperComponent = m_Helper.AddComponent();
helperComponent.onDestroyingComponent += OnHelperDestroyed;
#if !UNITY_EDITOR
GameObject.DontDestroyOnLoad(m_Helper);
#endif
}
void OnHelperDestroyed(GameObject helperGo)
{
if (m_Helper != helperGo)
return;
m_Helper = null;
CreateHelper();
}
void OnDisable()
{
if (m_Helper != null)
{
m_Helper.GetComponent().onDestroyingComponent -= OnHelperDestroyed;
GameObject.DestroyImmediate(m_Helper);
}
for (var i = 0; i < m_DeformationSystems.Length; ++i)
m_DeformationSystems[i].Cleanup();
}
internal void Update()
{
if (HasToggledGpuDeformation())
MoveSpriteSkinsToActiveSystem();
for (var i = 0; i < m_DeformationSystems.Length; ++i)
m_DeformationSystems[i].Update();
}
bool HasToggledGpuDeformation()
{
var isUsingGpuDeformation = SpriteSkinUtility.IsUsingGpuDeformation();
if (isUsingGpuDeformation != m_WasUsingGpuDeformationLastFrame)
{
m_WasUsingGpuDeformationLastFrame = isUsingGpuDeformation;
return true;
}
return false;
}
void MoveSpriteSkinsToActiveSystem()
{
var prevSystem = SpriteSkinUtility.IsUsingGpuDeformation() ? m_DeformationSystems[(int)DeformationMethods.Cpu] : m_DeformationSystems[(int)DeformationMethods.Gpu];
var skins = prevSystem.GetSpriteSkins();
foreach (var spriteSkin in skins)
prevSystem.RemoveSpriteSkin(spriteSkin);
foreach (var spriteSkin in skins)
AddSpriteSkin(spriteSkin);
}
internal void AddSpriteSkin(SpriteSkin spriteSkin)
{
if (spriteSkin == null)
return;
var deformationMethod = SpriteSkinUtility.IsUsingGpuDeformation() ? DeformationMethods.Gpu : DeformationMethods.Cpu;
if (deformationMethod == DeformationMethods.Gpu)
{
if (!canUseGpuDeformation)
{
deformationMethod = DeformationMethods.Cpu;
Debug.LogWarning($"{spriteSkin.name} is trying to use GPU deformation, but the platform does not support it. Switching the renderer over to CPU deformation.", spriteSkin);
}
else if (!SpriteSkinUtility.CanSpriteSkinUseGpuDeformation(spriteSkin))
{
deformationMethod = DeformationMethods.Cpu;
Debug.LogWarning($"{spriteSkin.name} is using a shader without GPU deformation support. Switching the renderer over to CPU deformation.", spriteSkin);
}
}
var deformationSystem = m_DeformationSystems[(int)deformationMethod];
if (deformationSystem.AddSpriteSkin(spriteSkin))
spriteSkin.SetDeformationSystem(deformationSystem);
}
internal void RemoveBoneTransforms(SpriteSkin spriteSkin)
{
for (var i = 0; i < m_DeformationSystems.Length; ++i)
m_DeformationSystems[i].RemoveBoneTransforms(spriteSkin);
}
internal void CopyToSpriteSkinData(SpriteSkin spriteSkin)
{
if (spriteSkin == null)
return;
var system = spriteSkin.deformationSystem;
if (system == null)
return;
system.CopyToSpriteSkinData(spriteSkin);
}
internal void AddSpriteSkinBoneTransform(SpriteSkin spriteSkin)
{
if (spriteSkin == null)
return;
var system = spriteSkin.deformationSystem;
if (system == null)
return;
system.AddBoneTransforms(spriteSkin);
}
#if UNITY_INCLUDE_TESTS
internal SpriteSkin[] GetSpriteSkins()
{
var skinList = new List();
for (var i = 0; i < m_DeformationSystems.Length; ++i)
skinList.AddRange(m_DeformationSystems[i].GetSpriteSkins());
return skinList.ToArray();
}
internal TransformAccessJob GetWorldToLocalTransformAccessJob(DeformationMethods deformationMethod)
{
if (!IsValidDeformationMethod(deformationMethod, out var systemIndex))
return null;
return m_DeformationSystems[systemIndex].GetWorldToLocalTransformAccessJob();
}
internal TransformAccessJob GetLocalToWorldTransformAccessJob(DeformationMethods deformationMethod)
{
if (!IsValidDeformationMethod(deformationMethod, out var systemIndex))
return null;
return m_DeformationSystems[systemIndex].GetLocalToWorldTransformAccessJob();
}
bool IsValidDeformationMethod(DeformationMethods deformationMethod, out int methodIndex)
{
methodIndex = (int)deformationMethod;
return methodIndex < m_DeformationSystems.Length;
}
#endif
}
#if UNITY_EDITOR
[UnityEditor.InitializeOnLoad]
internal class DeformationStartup
{
static DeformationStartup()
{
if (null == DeformationManager.instance.helperGameObject)
throw new System.InvalidOperationException("SpriteSkinComposite not initialized properly.");
}
}
#endif
}