SkinUtilities.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. /******************************************************************************
  2. * Spine Runtimes License Agreement
  3. * Last updated January 1, 2020. Replaces all prior versions.
  4. *
  5. * Copyright (c) 2013-2020, Esoteric Software LLC
  6. *
  7. * Integration of the Spine Runtimes into software or otherwise creating
  8. * derivative works of the Spine Runtimes is permitted under the terms and
  9. * conditions of Section 2 of the Spine Editor License Agreement:
  10. * http://esotericsoftware.com/spine-editor-license
  11. *
  12. * Otherwise, it is permitted to integrate the Spine Runtimes into software
  13. * or otherwise create derivative works of the Spine Runtimes (collectively,
  14. * "Products"), provided that each user of the Products must obtain their own
  15. * Spine Editor license and redistribution of the Products in any form must
  16. * include this license and copyright notice.
  17. *
  18. * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
  19. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
  24. * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27. * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. *****************************************************************************/
  29. using UnityEngine;
  30. using System.Collections.Generic;
  31. using System.Collections;
  32. namespace Spine.Unity.AttachmentTools {
  33. public static class SkinUtilities {
  34. #region Skeleton Skin Extensions
  35. /// <summary>
  36. /// Convenience method for duplicating a skeleton's current active skin so changes to it will not affect other skeleton instances. .</summary>
  37. public static Skin UnshareSkin (this Skeleton skeleton, bool includeDefaultSkin, bool unshareAttachments, AnimationState state = null) {
  38. // 1. Copy the current skin and set the skeleton's skin to the new one.
  39. var newSkin = skeleton.GetClonedSkin("cloned skin", includeDefaultSkin, unshareAttachments, true);
  40. skeleton.SetSkin(newSkin);
  41. // 2. Apply correct attachments: skeleton.SetToSetupPose + animationState.Apply
  42. if (state != null) {
  43. skeleton.SetToSetupPose();
  44. state.Apply(skeleton);
  45. }
  46. // 3. Return unshared skin.
  47. return newSkin;
  48. }
  49. public static Skin GetClonedSkin (this Skeleton skeleton, string newSkinName, bool includeDefaultSkin = false, bool cloneAttachments = false, bool cloneMeshesAsLinked = true) {
  50. var newSkin = new Skin(newSkinName); // may have null name. Harmless.
  51. var defaultSkin = skeleton.data.DefaultSkin;
  52. var activeSkin = skeleton.skin;
  53. if (includeDefaultSkin)
  54. defaultSkin.CopyTo(newSkin, true, cloneAttachments, cloneMeshesAsLinked);
  55. if (activeSkin != null)
  56. activeSkin.CopyTo(newSkin, true, cloneAttachments, cloneMeshesAsLinked);
  57. return newSkin;
  58. }
  59. #endregion
  60. /// <summary>
  61. /// Gets a shallow copy of the skin. The cloned skin's attachments are shared with the original skin.</summary>
  62. public static Skin GetClone (this Skin original) {
  63. var newSkin = new Skin(original.name + " clone");
  64. var newSkinAttachments = newSkin.Attachments;
  65. var newSkinBones = newSkin.Bones;
  66. var newSkinConstraints = newSkin.Constraints;
  67. foreach (var a in original.Attachments)
  68. newSkinAttachments[a.Key] = a.Value;
  69. newSkinBones.AddRange(original.bones);
  70. newSkinConstraints.AddRange(original.constraints);
  71. return newSkin;
  72. }
  73. /// <summary>Adds an attachment to the skin for the specified slot index and name. If the name already exists for the slot, the previous value is replaced.</summary>
  74. public static void SetAttachment (this Skin skin, string slotName, string keyName, Attachment attachment, Skeleton skeleton) {
  75. int slotIndex = skeleton.FindSlotIndex(slotName);
  76. if (skeleton == null) throw new System.ArgumentNullException("skeleton", "skeleton cannot be null.");
  77. if (slotIndex == -1) throw new System.ArgumentException(string.Format("Slot '{0}' does not exist in skeleton.", slotName), "slotName");
  78. skin.SetAttachment(slotIndex, keyName, attachment);
  79. }
  80. /// <summary>Adds skin items from another skin. For items that already exist, the previous values are replaced.</summary>
  81. public static void AddAttachments (this Skin skin, Skin otherSkin) {
  82. if (otherSkin == null) return;
  83. otherSkin.CopyTo(skin, true, false);
  84. }
  85. /// <summary>Gets an attachment from the skin for the specified slot index and name.</summary>
  86. public static Attachment GetAttachment (this Skin skin, string slotName, string keyName, Skeleton skeleton) {
  87. int slotIndex = skeleton.FindSlotIndex(slotName);
  88. if (skeleton == null) throw new System.ArgumentNullException("skeleton", "skeleton cannot be null.");
  89. if (slotIndex == -1) throw new System.ArgumentException(string.Format("Slot '{0}' does not exist in skeleton.", slotName), "slotName");
  90. return skin.GetAttachment(slotIndex, keyName);
  91. }
  92. /// <summary>Adds an attachment to the skin for the specified slot index and name. If the name already exists for the slot, the previous value is replaced.</summary>
  93. public static void SetAttachment (this Skin skin, int slotIndex, string keyName, Attachment attachment) {
  94. skin.SetAttachment(slotIndex, keyName, attachment);
  95. }
  96. public static void RemoveAttachment (this Skin skin, string slotName, string keyName, SkeletonData skeletonData) {
  97. int slotIndex = skeletonData.FindSlotIndex(slotName);
  98. if (skeletonData == null) throw new System.ArgumentNullException("skeletonData", "skeletonData cannot be null.");
  99. if (slotIndex == -1) throw new System.ArgumentException(string.Format("Slot '{0}' does not exist in skeleton.", slotName), "slotName");
  100. skin.RemoveAttachment(slotIndex, keyName);
  101. }
  102. public static void Clear (this Skin skin) {
  103. skin.Attachments.Clear();
  104. }
  105. //[System.Obsolete]
  106. public static void Append (this Skin destination, Skin source) {
  107. source.CopyTo(destination, true, false);
  108. }
  109. public static void CopyTo (this Skin source, Skin destination, bool overwrite, bool cloneAttachments, bool cloneMeshesAsLinked = true) {
  110. var sourceAttachments = source.Attachments;
  111. var destinationAttachments = destination.Attachments;
  112. var destinationBones = destination.Bones;
  113. var destinationConstraints = destination.Constraints;
  114. if (cloneAttachments) {
  115. if (overwrite) {
  116. foreach (var e in sourceAttachments) {
  117. Attachment clonedAttachment = e.Value.GetCopy(cloneMeshesAsLinked);
  118. destinationAttachments[new Skin.SkinEntry(e.Key.SlotIndex, e.Key.Name, clonedAttachment)] = clonedAttachment;
  119. }
  120. } else {
  121. foreach (var e in sourceAttachments) {
  122. if (destinationAttachments.ContainsKey(e.Key)) continue;
  123. Attachment clonedAttachment = e.Value.GetCopy(cloneMeshesAsLinked);
  124. destinationAttachments.Add(new Skin.SkinEntry(e.Key.SlotIndex, e.Key.Name, clonedAttachment), clonedAttachment);
  125. }
  126. }
  127. } else {
  128. if (overwrite) {
  129. foreach (var e in sourceAttachments)
  130. destinationAttachments[e.Key] = e.Value;
  131. } else {
  132. foreach (var e in sourceAttachments) {
  133. if (destinationAttachments.ContainsKey(e.Key)) continue;
  134. destinationAttachments.Add(e.Key, e.Value);
  135. }
  136. }
  137. }
  138. foreach (BoneData data in source.bones)
  139. if (!destinationBones.Contains(data)) destinationBones.Add(data);
  140. foreach (ConstraintData data in source.constraints)
  141. if (!destinationConstraints.Contains(data)) destinationConstraints.Add(data);
  142. }
  143. }
  144. }