mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 22:49:01 +08:00
[unity][csharp] API Cleanup: removed many redundant extension methods that are now obsolete with Skin and Attachment API of 3.8. Closes #1557. Fixed an error in Skin where Skin.setAttachment() did not work as expected (See #1485). C# implementation is different to ref-impl here as struct keys do not allow for changing key.Attachment later without removing and readding the entry to the dictionary.
This commit is contained in:
parent
de84c1000e
commit
f2a8c9a3c1
@ -43,6 +43,11 @@
|
|||||||
### Unity
|
### Unity
|
||||||
|
|
||||||
* **Breaking changes**
|
* **Breaking changes**
|
||||||
|
* Removed all `Spine.Unity.AttachmentTools.SkinUtilities` Skin extension methods. These have become obsoleted and error-prone since the introduction of the new Skin API in 3.8. To fix any compile errors, replace any usage of `Skin` extension methods with their counterparts, e.g. replace occurrances of `skin.AddAttachments()` with `skin.AddSkin()`.
|
||||||
|
* Removed redundant `Spine.Unity.AttachmentTools` extension method `Skin.GetRepackedAttachments()`. Please use `Skin.GetRepackedSkin()` instead.
|
||||||
|
* Removed redundant `Spine.Unity.AttachmentTools.AttachmentCloneExtensions` extension methods `Attachment.GetCopy()` and `Attachment.GetLinkedMesh()`. To fix any compile errors, replace any occurrances with `Attachment.Copy()` and `Attachment.NewLinkedMesh()`.
|
||||||
|
* Removed redundant `Spine.SkeletonExtensions` extension methods `Skeleton.Set*ToSetupPose()`. Also removed less commonly used extension methods `TrackEntry.AllowImmediateQueue()` and `Attachment.IsRenderable()`.
|
||||||
|
* `Skin.Attachments` now replaces `Skin.GetAttachments()`, returning an `ICollection<SkinEntry>`. This makes access more consistent and intuitive. To fix any compile errors, replace any occurrances of `skin.GetAttachments()` by `skin.Attachments`.
|
||||||
|
|
||||||
* **Additions**
|
* **Additions**
|
||||||
* Additional **Fix Draw Order** parameter at SkeletonRenderer, defaults to `disabled` (previous behaviour).
|
* Additional **Fix Draw Order** parameter at SkeletonRenderer, defaults to `disabled` (previous behaviour).
|
||||||
|
|||||||
@ -260,8 +260,7 @@ namespace Spine {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void SortPathConstraintAttachment (Skin skin, int slotIndex, Bone slotBone) {
|
private void SortPathConstraintAttachment (Skin skin, int slotIndex, Bone slotBone) {
|
||||||
foreach (var entryObj in skin.Attachments.Keys) {
|
foreach (var entry in skin.Attachments) {
|
||||||
var entry = (Skin.SkinEntry)entryObj;
|
|
||||||
if (entry.SlotIndex == slotIndex) SortPathConstraintAttachment(entry.Attachment, slotBone);
|
if (entry.SlotIndex == slotIndex) SortPathConstraintAttachment(entry.Attachment, slotBone);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -39,12 +39,13 @@ namespace Spine {
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class Skin {
|
public class Skin {
|
||||||
internal string name;
|
internal string name;
|
||||||
private OrderedDictionary<SkinEntry, Attachment> attachments = new OrderedDictionary<SkinEntry, Attachment>(SkinEntryComparer.Instance);
|
private OrderedDictionary<SkinKey, SkinEntry> attachments = new OrderedDictionary<SkinKey, SkinEntry>(SkinKeyComparer.Instance);
|
||||||
internal readonly ExposedList<BoneData> bones = new ExposedList<BoneData>();
|
internal readonly ExposedList<BoneData> bones = new ExposedList<BoneData>();
|
||||||
internal readonly ExposedList<ConstraintData> constraints = new ExposedList<ConstraintData>();
|
internal readonly ExposedList<ConstraintData> constraints = new ExposedList<ConstraintData>();
|
||||||
|
|
||||||
public string Name { get { return name; } }
|
public string Name { get { return name; } }
|
||||||
public OrderedDictionary<SkinEntry, Attachment> Attachments { get { return attachments; } }
|
///<summary>Returns all attachments contained in this skin.</summary>
|
||||||
|
public ICollection<SkinEntry> Attachments { get { return attachments.Values; } }
|
||||||
public ExposedList<BoneData> Bones { get { return bones; } }
|
public ExposedList<BoneData> Bones { get { return bones; } }
|
||||||
public ExposedList<ConstraintData> Constraints { get { return constraints; } }
|
public ExposedList<ConstraintData> Constraints { get { return constraints; } }
|
||||||
|
|
||||||
@ -58,7 +59,7 @@ namespace Spine {
|
|||||||
public void SetAttachment (int slotIndex, string name, Attachment attachment) {
|
public void SetAttachment (int slotIndex, string name, Attachment attachment) {
|
||||||
if (attachment == null) throw new ArgumentNullException("attachment", "attachment cannot be null.");
|
if (attachment == null) throw new ArgumentNullException("attachment", "attachment cannot be null.");
|
||||||
if (slotIndex < 0) throw new ArgumentNullException("slotIndex", "slotIndex must be >= 0.");
|
if (slotIndex < 0) throw new ArgumentNullException("slotIndex", "slotIndex must be >= 0.");
|
||||||
attachments[new SkinEntry(slotIndex, name, attachment)] = attachment;
|
attachments[new SkinKey(slotIndex, name)] = new SkinEntry(slotIndex, name, attachment);
|
||||||
}
|
}
|
||||||
|
|
||||||
///<summary>Adds all attachments, bones, and constraints from the specified skin to this skin.</summary>
|
///<summary>Adds all attachments, bones, and constraints from the specified skin to this skin.</summary>
|
||||||
@ -69,7 +70,7 @@ namespace Spine {
|
|||||||
foreach (ConstraintData data in skin.constraints)
|
foreach (ConstraintData data in skin.constraints)
|
||||||
if (!constraints.Contains(data)) constraints.Add(data);
|
if (!constraints.Contains(data)) constraints.Add(data);
|
||||||
|
|
||||||
foreach (SkinEntry entry in skin.attachments.Keys)
|
foreach (SkinEntry entry in skin.attachments.Values)
|
||||||
SetAttachment(entry.SlotIndex, entry.Name, entry.Attachment);
|
SetAttachment(entry.SlotIndex, entry.Name, entry.Attachment);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -81,7 +82,7 @@ namespace Spine {
|
|||||||
foreach (ConstraintData data in skin.constraints)
|
foreach (ConstraintData data in skin.constraints)
|
||||||
if (!constraints.Contains(data)) constraints.Add(data);
|
if (!constraints.Contains(data)) constraints.Add(data);
|
||||||
|
|
||||||
foreach (SkinEntry entry in skin.attachments.Keys) {
|
foreach (SkinEntry entry in skin.attachments.Values) {
|
||||||
if (entry.Attachment is MeshAttachment)
|
if (entry.Attachment is MeshAttachment)
|
||||||
SetAttachment(entry.SlotIndex, entry.Name,
|
SetAttachment(entry.SlotIndex, entry.Name,
|
||||||
entry.Attachment != null ? ((MeshAttachment)entry.Attachment).NewLinkedMesh() : null);
|
entry.Attachment != null ? ((MeshAttachment)entry.Attachment).NewLinkedMesh() : null);
|
||||||
@ -93,28 +94,23 @@ namespace Spine {
|
|||||||
/// <summary>Returns the attachment for the specified slot index and name, or null.</summary>
|
/// <summary>Returns the attachment for the specified slot index and name, or null.</summary>
|
||||||
/// <returns>May be null.</returns>
|
/// <returns>May be null.</returns>
|
||||||
public Attachment GetAttachment (int slotIndex, string name) {
|
public Attachment GetAttachment (int slotIndex, string name) {
|
||||||
var lookup = new SkinEntry(slotIndex, name, null);
|
var lookup = new SkinKey(slotIndex, name);
|
||||||
Attachment attachment = null;
|
SkinEntry entry;
|
||||||
bool containsKey = attachments.TryGetValue(lookup, out attachment);
|
bool containsKey = attachments.TryGetValue(lookup, out entry);
|
||||||
return containsKey ? attachment : null;
|
return containsKey ? entry.Attachment : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> Removes the attachment in the skin for the specified slot index and name, if any.</summary>
|
/// <summary> Removes the attachment in the skin for the specified slot index and name, if any.</summary>
|
||||||
public void RemoveAttachment (int slotIndex, string name) {
|
public void RemoveAttachment (int slotIndex, string name) {
|
||||||
if (slotIndex < 0) throw new ArgumentOutOfRangeException("slotIndex", "slotIndex must be >= 0");
|
if (slotIndex < 0) throw new ArgumentOutOfRangeException("slotIndex", "slotIndex must be >= 0");
|
||||||
var lookup = new SkinEntry(slotIndex, name, null);
|
var lookup = new SkinKey(slotIndex, name);
|
||||||
attachments.Remove(lookup);
|
attachments.Remove(lookup);
|
||||||
}
|
}
|
||||||
|
|
||||||
///<summary>Returns all attachments contained in this skin.</summary>
|
|
||||||
public ICollection<SkinEntry> GetAttachments () {
|
|
||||||
return this.attachments.Keys;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Returns all attachments in this skin for the specified slot index.</summary>
|
/// <summary>Returns all attachments in this skin for the specified slot index.</summary>
|
||||||
/// <param name="slotIndex">The target slotIndex. To find the slot index, use <see cref="Spine.Skeleton.FindSlotIndex"/> or <see cref="Spine.SkeletonData.FindSlotIndex"/>
|
/// <param name="slotIndex">The target slotIndex. To find the slot index, use <see cref="Spine.Skeleton.FindSlotIndex"/> or <see cref="Spine.SkeletonData.FindSlotIndex"/>
|
||||||
public void GetAttachments (int slotIndex, List<SkinEntry> attachments) {
|
public void GetAttachments (int slotIndex, List<SkinEntry> attachments) {
|
||||||
foreach (SkinEntry entry in this.attachments.Keys)
|
foreach (SkinEntry entry in this.attachments.Values)
|
||||||
if (entry.SlotIndex == slotIndex) attachments.Add(entry);
|
if (entry.SlotIndex == slotIndex) attachments.Add(entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,7 +127,7 @@ namespace Spine {
|
|||||||
|
|
||||||
/// <summary>Attach all attachments from this skin if the corresponding attachment from the old skin is currently attached.</summary>
|
/// <summary>Attach all attachments from this skin if the corresponding attachment from the old skin is currently attached.</summary>
|
||||||
internal void AttachAll (Skeleton skeleton, Skin oldSkin) {
|
internal void AttachAll (Skeleton skeleton, Skin oldSkin) {
|
||||||
foreach (SkinEntry entry in oldSkin.attachments.Keys) {
|
foreach (SkinEntry entry in oldSkin.attachments.Values) {
|
||||||
int slotIndex = entry.SlotIndex;
|
int slotIndex = entry.SlotIndex;
|
||||||
Slot slot = skeleton.slots.Items[slotIndex];
|
Slot slot = skeleton.slots.Items[slotIndex];
|
||||||
if (slot.Attachment == entry.Attachment) {
|
if (slot.Attachment == entry.Attachment) {
|
||||||
@ -146,13 +142,11 @@ namespace Spine {
|
|||||||
private readonly int slotIndex;
|
private readonly int slotIndex;
|
||||||
private readonly string name;
|
private readonly string name;
|
||||||
private readonly Attachment attachment;
|
private readonly Attachment attachment;
|
||||||
internal readonly int hashCode;
|
|
||||||
|
|
||||||
public SkinEntry (int slotIndex, string name, Attachment attachment) {
|
public SkinEntry (int slotIndex, string name, Attachment attachment) {
|
||||||
this.slotIndex = slotIndex;
|
this.slotIndex = slotIndex;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.attachment = attachment;
|
this.attachment = attachment;
|
||||||
this.hashCode = this.name.GetHashCode() + this.slotIndex * 37;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int SlotIndex {
|
public int SlotIndex {
|
||||||
@ -175,17 +169,43 @@ namespace Spine {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Avoids boxing in the dictionary and is necessary to omit entry.attachment in the comparison.
|
/// Note: not present in libgdx reference implementation.
|
||||||
class SkinEntryComparer : IEqualityComparer<SkinEntry> {
|
/// SkinKey contains slot index and name only, as a once-added SkinEntry cannot have its Attachment changed
|
||||||
internal static readonly SkinEntryComparer Instance = new SkinEntryComparer();
|
/// (SkinEntry is a value type as opposed to the java reference implementation) without removing and
|
||||||
|
/// re-adding it to a dictionary, leading to problems in order and unnecessary operations.
|
||||||
|
private struct SkinKey {
|
||||||
|
private readonly int slotIndex;
|
||||||
|
private readonly string name;
|
||||||
|
|
||||||
bool IEqualityComparer<SkinEntry>.Equals (SkinEntry e1, SkinEntry e2) {
|
public SkinKey (int slotIndex, string name) {
|
||||||
|
this.slotIndex = slotIndex;
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int SlotIndex {
|
||||||
|
get {
|
||||||
|
return slotIndex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>The name the attachment is associated with, equivalent to the skin placeholder name in the Spine editor.</summary>
|
||||||
|
public String Name {
|
||||||
|
get {
|
||||||
|
return name;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class SkinKeyComparer : IEqualityComparer<SkinKey> {
|
||||||
|
internal static readonly SkinKeyComparer Instance = new SkinKeyComparer();
|
||||||
|
|
||||||
|
bool IEqualityComparer<SkinKey>.Equals (SkinKey e1, SkinKey e2) {
|
||||||
if (e1.SlotIndex != e2.SlotIndex) return false;
|
if (e1.SlotIndex != e2.SlotIndex) return false;
|
||||||
if (!string.Equals(e1.Name, e2.Name, StringComparison.Ordinal)) return false;
|
if (!string.Equals(e1.Name, e2.Name, StringComparison.Ordinal)) return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
int IEqualityComparer<SkinEntry>.GetHashCode (SkinEntry e) {
|
int IEqualityComparer<SkinKey>.GetHashCode (SkinKey e) {
|
||||||
return e.Name.GetHashCode() + e.SlotIndex * 37;
|
return e.Name.GetHashCode() + e.SlotIndex * 37;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -53,7 +53,7 @@ namespace Spine.Unity.Examples {
|
|||||||
// OPTIONAL: Add all the attachments from the template skin.
|
// OPTIONAL: Add all the attachments from the template skin.
|
||||||
var templateSkin = skeletonAnimation.Skeleton.Data.FindSkin(templateSkinName);
|
var templateSkin = skeletonAnimation.Skeleton.Data.FindSkin(templateSkinName);
|
||||||
if (templateSkin != null)
|
if (templateSkin != null)
|
||||||
equipsSkin.AddAttachments(templateSkin);
|
equipsSkin.AddSkin(templateSkin);
|
||||||
|
|
||||||
skeletonAnimation.Skeleton.Skin = equipsSkin;
|
skeletonAnimation.Skeleton.Skin = equipsSkin;
|
||||||
RefreshSkeletonAttachments();
|
RefreshSkeletonAttachments();
|
||||||
@ -69,8 +69,8 @@ namespace Spine.Unity.Examples {
|
|||||||
// 1. Collect all the attachments of all active skins.
|
// 1. Collect all the attachments of all active skins.
|
||||||
collectedSkin = collectedSkin ?? new Skin("Collected skin");
|
collectedSkin = collectedSkin ?? new Skin("Collected skin");
|
||||||
collectedSkin.Clear();
|
collectedSkin.Clear();
|
||||||
collectedSkin.AddAttachments(skeletonAnimation.Skeleton.Data.DefaultSkin);
|
collectedSkin.AddSkin(skeletonAnimation.Skeleton.Data.DefaultSkin);
|
||||||
collectedSkin.AddAttachments(equipsSkin);
|
collectedSkin.AddSkin(equipsSkin);
|
||||||
|
|
||||||
// 2. Create a repacked skin.
|
// 2. Create a repacked skin.
|
||||||
var repackedSkin = collectedSkin.GetRepackedSkin("Repacked skin", skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial, out runtimeMaterial, out runtimeAtlas);
|
var repackedSkin = collectedSkin.GetRepackedSkin("Repacked skin", skeletonAnimation.SkeletonDataAsset.atlasAssets[0].PrimaryMaterial, out runtimeMaterial, out runtimeAtlas);
|
||||||
|
|||||||
@ -119,8 +119,8 @@ namespace Spine.Unity.Examples {
|
|||||||
// call Skin.GetRepackedSkin to get a cloned skin with cloned attachments that all use one texture.
|
// call Skin.GetRepackedSkin to get a cloned skin with cloned attachments that all use one texture.
|
||||||
if (repack) {
|
if (repack) {
|
||||||
var repackedSkin = new Skin("repacked skin");
|
var repackedSkin = new Skin("repacked skin");
|
||||||
repackedSkin.AddAttachments(skeleton.Data.DefaultSkin); // Include the "default" skin. (everything outside of skin placeholders)
|
repackedSkin.AddSkin(skeleton.Data.DefaultSkin); // Include the "default" skin. (everything outside of skin placeholders)
|
||||||
repackedSkin.AddAttachments(customSkin); // Include your new custom skin.
|
repackedSkin.AddSkin(customSkin); // Include your new custom skin.
|
||||||
repackedSkin = repackedSkin.GetRepackedSkin("repacked skin", sourceMaterial, out runtimeMaterial, out runtimeAtlas); // Pack all the items in the skin.
|
repackedSkin = repackedSkin.GetRepackedSkin("repacked skin", sourceMaterial, out runtimeMaterial, out runtimeAtlas); // Pack all the items in the skin.
|
||||||
skeleton.SetSkin(repackedSkin); // Assign the repacked skin to your Skeleton.
|
skeleton.SetSkin(repackedSkin); // Assign the repacked skin to your Skeleton.
|
||||||
if (bbFollower != null) bbFollower.Initialize(true);
|
if (bbFollower != null) bbFollower.Initialize(true);
|
||||||
|
|||||||
@ -117,8 +117,8 @@ namespace Spine.Unity.Examples {
|
|||||||
// call Skin.GetRepackedSkin to get a cloned skin with cloned attachments that all use one texture.
|
// call Skin.GetRepackedSkin to get a cloned skin with cloned attachments that all use one texture.
|
||||||
if (repack) {
|
if (repack) {
|
||||||
var repackedSkin = new Skin("repacked skin");
|
var repackedSkin = new Skin("repacked skin");
|
||||||
repackedSkin.AddAttachments(skeleton.Data.DefaultSkin);
|
repackedSkin.AddSkin(skeleton.Data.DefaultSkin);
|
||||||
repackedSkin.AddAttachments(customSkin);
|
repackedSkin.AddSkin(customSkin);
|
||||||
repackedSkin = repackedSkin.GetRepackedSkin("repacked skin", sourceMaterial, out runtimeMaterial, out runtimeAtlas);
|
repackedSkin = repackedSkin.GetRepackedSkin("repacked skin", sourceMaterial, out runtimeMaterial, out runtimeAtlas);
|
||||||
skeleton.SetSkin(repackedSkin);
|
skeleton.SetSkin(repackedSkin);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@ -49,7 +49,7 @@ namespace Spine.Unity.Examples {
|
|||||||
combinedSkin.Clear();
|
combinedSkin.Clear();
|
||||||
foreach (var skinName in skinsToCombine) {
|
foreach (var skinName in skinsToCombine) {
|
||||||
var skin = skeleton.Data.FindSkin(skinName);
|
var skin = skeleton.Data.FindSkin(skinName);
|
||||||
if (skin != null) combinedSkin.AddAttachments(skin);
|
if (skin != null) combinedSkin.AddSkin(skin);
|
||||||
}
|
}
|
||||||
|
|
||||||
skeleton.SetSkin(combinedSkin);
|
skeleton.SetSkin(combinedSkin);
|
||||||
|
|||||||
@ -112,10 +112,9 @@ namespace Spine.Unity.Editor {
|
|||||||
|
|
||||||
static void DrawPointsInSkin (Skin skin, Skeleton skeleton, Transform transform) {
|
static void DrawPointsInSkin (Skin skin, Skeleton skeleton, Transform transform) {
|
||||||
foreach (var skinEntry in skin.Attachments) {
|
foreach (var skinEntry in skin.Attachments) {
|
||||||
var attachment = skinEntry.Value as PointAttachment;
|
var attachment = skinEntry.Attachment as PointAttachment;
|
||||||
if (attachment != null) {
|
if (attachment != null) {
|
||||||
var skinKey = (Skin.SkinEntry)skinEntry.Key;
|
var slot = skeleton.Slots.Items[skinEntry.SlotIndex];
|
||||||
var slot = skeleton.Slots.Items[skinKey.SlotIndex];
|
|
||||||
DrawPointAttachmentWithLabel(attachment, slot.Bone, transform);
|
DrawPointAttachmentWithLabel(attachment, slot.Bone, transform);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -180,7 +180,7 @@ namespace Spine.Unity {
|
|||||||
if (autoReset) {
|
if (autoReset) {
|
||||||
var previousAnimations = this.previousAnimations;
|
var previousAnimations = this.previousAnimations;
|
||||||
for (int i = 0, n = previousAnimations.Count; i < n; i++)
|
for (int i = 0, n = previousAnimations.Count; i < n; i++)
|
||||||
previousAnimations[i].SetKeyedItemsToSetupPose(skeleton);
|
previousAnimations[i].Apply(skeleton, 0, 0, false, null, 0, MixBlend.Setup, MixDirection.Out); // SetKeyedItemsToSetupPose
|
||||||
|
|
||||||
previousAnimations.Clear();
|
previousAnimations.Clear();
|
||||||
for (int layer = 0, n = animator.layerCount; layer < n; layer++) {
|
for (int layer = 0, n = animator.layerCount; layer < n; layer++) {
|
||||||
|
|||||||
@ -219,96 +219,6 @@ namespace Spine.Unity.AttachmentTools {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#region Runtime Repacking
|
#region Runtime Repacking
|
||||||
/// <summary>
|
|
||||||
/// Fills the outputAttachments list with new attachment objects based on the attachments in sourceAttachments, but mapped to a new single texture using the same material.</summary>
|
|
||||||
/// <param name="sourceAttachments">The list of attachments to be repacked.</param>
|
|
||||||
/// <param name = "outputAttachments">The List(Attachment) to populate with the newly created Attachment objects.</param>
|
|
||||||
///
|
|
||||||
/// <param name="materialPropertySource">May be null. If no Material property source is provided, no special </param>
|
|
||||||
public static void GetRepackedAttachments (List<Attachment> sourceAttachments, List<Attachment> outputAttachments, Material materialPropertySource, out Material outputMaterial, out Texture2D outputTexture, int maxAtlasSize = 1024, int padding = 2, TextureFormat textureFormat = SpineTextureFormat, bool mipmaps = UseMipMaps, string newAssetName = "Repacked Attachments", bool clearCache = false, bool useOriginalNonrenderables = true) {
|
|
||||||
if (sourceAttachments == null) throw new System.ArgumentNullException("sourceAttachments");
|
|
||||||
if (outputAttachments == null) throw new System.ArgumentNullException("outputAttachments");
|
|
||||||
|
|
||||||
// Use these to detect and use shared regions.
|
|
||||||
var existingRegions = new Dictionary<AtlasRegion, int>();
|
|
||||||
var regionIndexes = new List<int>();
|
|
||||||
var texturesToPack = new List<Texture2D>();
|
|
||||||
var originalRegions = new List<AtlasRegion>();
|
|
||||||
|
|
||||||
outputAttachments.Clear();
|
|
||||||
outputAttachments.AddRange(sourceAttachments);
|
|
||||||
|
|
||||||
int newRegionIndex = 0;
|
|
||||||
for (int i = 0, n = sourceAttachments.Count; i < n; i++) {
|
|
||||||
var originalAttachment = sourceAttachments[i];
|
|
||||||
|
|
||||||
if (IsRenderable(originalAttachment)) {
|
|
||||||
var newAttachment = originalAttachment.GetCopy(true);
|
|
||||||
var region = newAttachment.GetRegion();
|
|
||||||
int existingIndex;
|
|
||||||
if (existingRegions.TryGetValue(region, out existingIndex)) {
|
|
||||||
regionIndexes.Add(existingIndex); // Store the region index for the eventual new attachment.
|
|
||||||
} else {
|
|
||||||
originalRegions.Add(region);
|
|
||||||
texturesToPack.Add(region.ToTexture()); // Add the texture to the PackTextures argument
|
|
||||||
existingRegions.Add(region, newRegionIndex); // Add the region to the dictionary of known regions
|
|
||||||
regionIndexes.Add(newRegionIndex); // Store the region index for the eventual new attachment.
|
|
||||||
newRegionIndex++;
|
|
||||||
}
|
|
||||||
|
|
||||||
outputAttachments[i] = newAttachment;
|
|
||||||
} else {
|
|
||||||
outputAttachments[i] = useOriginalNonrenderables ? originalAttachment : originalAttachment.GetCopy(true);
|
|
||||||
regionIndexes.Add(NonrenderingRegion); // Output attachments pairs with regionIndexes list 1:1. Pad with a sentinel if the attachment doesn't have a region.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fill a new texture with the collected attachment textures.
|
|
||||||
var newTexture = new Texture2D(maxAtlasSize, maxAtlasSize, textureFormat, mipmaps);
|
|
||||||
newTexture.mipMapBias = AtlasUtilities.DefaultMipmapBias;
|
|
||||||
newTexture.name = newAssetName;
|
|
||||||
// Copy settings
|
|
||||||
if (texturesToPack.Count > 0) {
|
|
||||||
var sourceTexture = texturesToPack[0];
|
|
||||||
newTexture.CopyTextureAttributesFrom(sourceTexture);
|
|
||||||
}
|
|
||||||
var rects = newTexture.PackTextures(texturesToPack.ToArray(), padding, maxAtlasSize);
|
|
||||||
|
|
||||||
// Rehydrate the repacked textures as a Material, Spine atlas and Spine.AtlasAttachments
|
|
||||||
Shader shader = materialPropertySource == null ? Shader.Find("Spine/Skeleton") : materialPropertySource.shader;
|
|
||||||
var newMaterial = new Material(shader);
|
|
||||||
if (materialPropertySource != null) {
|
|
||||||
newMaterial.CopyPropertiesFromMaterial(materialPropertySource);
|
|
||||||
newMaterial.shaderKeywords = materialPropertySource.shaderKeywords;
|
|
||||||
}
|
|
||||||
|
|
||||||
newMaterial.name = newAssetName;
|
|
||||||
newMaterial.mainTexture = newTexture;
|
|
||||||
var page = newMaterial.ToSpineAtlasPage();
|
|
||||||
page.name = newAssetName;
|
|
||||||
|
|
||||||
var repackedRegions = new List<AtlasRegion>();
|
|
||||||
for (int i = 0, n = originalRegions.Count; i < n; i++) {
|
|
||||||
var oldRegion = originalRegions[i];
|
|
||||||
var newRegion = UVRectToAtlasRegion(rects[i], oldRegion, page);
|
|
||||||
repackedRegions.Add(newRegion);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Map the cloned attachments to the repacked atlas.
|
|
||||||
for (int i = 0, n = outputAttachments.Count; i < n; i++) {
|
|
||||||
var a = outputAttachments[i];
|
|
||||||
if (IsRenderable(a))
|
|
||||||
a.SetRegion(repackedRegions[regionIndexes[i]]);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Clean up.
|
|
||||||
if (clearCache)
|
|
||||||
AtlasUtilities.ClearCache();
|
|
||||||
|
|
||||||
outputTexture = newTexture;
|
|
||||||
outputMaterial = newMaterial;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates and populates a duplicate skin with cloned attachments that are backed by a new packed texture atlas
|
/// Creates and populates a duplicate skin with cloned attachments that are backed by a new packed texture atlas
|
||||||
/// comprised of all the regions from the original skin.</summary>
|
/// comprised of all the regions from the original skin.</summary>
|
||||||
@ -363,14 +273,13 @@ namespace Spine.Unity.AttachmentTools {
|
|||||||
var originalRegions = new List<AtlasRegion>();
|
var originalRegions = new List<AtlasRegion>();
|
||||||
int newRegionIndex = 0;
|
int newRegionIndex = 0;
|
||||||
|
|
||||||
foreach (var skinEntry in skinAttachments) {
|
foreach (var originalSkinEntry in skinAttachments) {
|
||||||
var originalKey = skinEntry.Key;
|
var originalAttachment = originalSkinEntry.Attachment;
|
||||||
var originalAttachment = skinEntry.Value;
|
|
||||||
|
|
||||||
Attachment newAttachment;
|
if (originalAttachment is IHasRendererObject) {
|
||||||
if (IsRenderable(originalAttachment)) {
|
var originalMeshAttachment = originalAttachment as MeshAttachment;
|
||||||
newAttachment = originalAttachment.GetCopy(true);
|
Attachment newAttachment = (originalMeshAttachment != null) ? originalMeshAttachment.NewLinkedMesh() : originalAttachment.Copy();
|
||||||
var region = newAttachment.GetRegion();
|
var region = ((IHasRendererObject)newAttachment).RendererObject as AtlasRegion;
|
||||||
int existingIndex;
|
int existingIndex;
|
||||||
if (existingRegions.TryGetValue(region, out existingIndex)) {
|
if (existingRegions.TryGetValue(region, out existingIndex)) {
|
||||||
regionIndexes.Add(existingIndex); // Store the region index for the eventual new attachment.
|
regionIndexes.Add(existingIndex); // Store the region index for the eventual new attachment.
|
||||||
@ -386,9 +295,9 @@ namespace Spine.Unity.AttachmentTools {
|
|||||||
}
|
}
|
||||||
|
|
||||||
repackedAttachments.Add(newAttachment);
|
repackedAttachments.Add(newAttachment);
|
||||||
newSkin.SetAttachment(originalKey.SlotIndex, originalKey.Name, newAttachment);
|
newSkin.SetAttachment(originalSkinEntry.SlotIndex, originalSkinEntry.Name, newAttachment);
|
||||||
} else {
|
} else {
|
||||||
newSkin.SetAttachment(originalKey.SlotIndex, originalKey.Name, useOriginalNonrenderables ? originalAttachment : originalAttachment.GetCopy(true));
|
newSkin.SetAttachment(originalSkinEntry.SlotIndex, originalSkinEntry.Name, useOriginalNonrenderables ? originalAttachment : originalAttachment.Copy());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -436,7 +345,7 @@ namespace Spine.Unity.AttachmentTools {
|
|||||||
// Map the cloned attachments to the repacked atlas.
|
// Map the cloned attachments to the repacked atlas.
|
||||||
for (int i = 0, n = repackedAttachments.Count; i < n; i++) {
|
for (int i = 0, n = repackedAttachments.Count; i < n; i++) {
|
||||||
var a = repackedAttachments[i];
|
var a = repackedAttachments[i];
|
||||||
if (IsRenderable(a))
|
if (a is IHasRendererObject)
|
||||||
a.SetRegion(repackedRegions[regionIndexes[i]]);
|
a.SetRegion(repackedRegions[regionIndexes[i]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -523,10 +432,6 @@ namespace Spine.Unity.AttachmentTools {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsRenderable (Attachment a) {
|
|
||||||
return a is IHasRendererObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Get a rect with flipped Y so that a Spine atlas rect gets converted to a Unity Sprite rect and vice versa.</summary>
|
/// Get a rect with flipped Y so that a Spine atlas rect gets converted to a Unity Sprite rect and vice versa.</summary>
|
||||||
static Rect SpineUnityFlipRect (this Rect rect, int textureHeight) {
|
static Rect SpineUnityFlipRect (this Rect rect, int textureHeight) {
|
||||||
|
|||||||
@ -34,44 +34,6 @@ using System.Collections;
|
|||||||
namespace Spine.Unity.AttachmentTools {
|
namespace Spine.Unity.AttachmentTools {
|
||||||
|
|
||||||
public static class AttachmentCloneExtensions {
|
public static class AttachmentCloneExtensions {
|
||||||
/// <summary>
|
|
||||||
/// Clones the attachment.</summary>
|
|
||||||
public static Attachment GetCopy (this Attachment o, bool cloneMeshesAsLinked) {
|
|
||||||
var meshAttachment = o as MeshAttachment;
|
|
||||||
if (meshAttachment != null && cloneMeshesAsLinked)
|
|
||||||
return meshAttachment.NewLinkedMesh();
|
|
||||||
return o.Copy();
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Runtime Linked MeshAttachments
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a new linked mesh linked to this MeshAttachment. It will be mapped to the AtlasRegion provided.</summary>
|
|
||||||
public static MeshAttachment GetLinkedMesh (this MeshAttachment o, string newLinkedMeshName, AtlasRegion region) {
|
|
||||||
if (region == null) throw new System.ArgumentNullException("region");
|
|
||||||
MeshAttachment mesh = o.NewLinkedMesh();
|
|
||||||
mesh.SetRegion(region, false);
|
|
||||||
return mesh;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a new linked mesh linked to this MeshAttachment. It will be mapped to an AtlasRegion generated from a Sprite. The AtlasRegion will be mapped to a new Material based on the shader.
|
|
||||||
/// For better caching and batching, use GetLinkedMesh(string, AtlasRegion, bool)</summary>
|
|
||||||
public static MeshAttachment GetLinkedMesh (this MeshAttachment o, Sprite sprite, Shader shader, Material materialPropertySource = null) {
|
|
||||||
var m = new Material(shader);
|
|
||||||
if (materialPropertySource != null) {
|
|
||||||
m.CopyPropertiesFromMaterial(materialPropertySource);
|
|
||||||
m.shaderKeywords = materialPropertySource.shaderKeywords;
|
|
||||||
}
|
|
||||||
return o.GetLinkedMesh(sprite.name, sprite.ToAtlasRegion());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns a new linked mesh linked to this MeshAttachment. It will be mapped to an AtlasRegion generated from a Sprite. The AtlasRegion will be mapped to a new Material based on the shader.
|
|
||||||
/// For better caching and batching, use GetLinkedMesh(string, AtlasRegion, bool)</summary>
|
|
||||||
public static MeshAttachment GetLinkedMesh (this MeshAttachment o, Sprite sprite, Material materialPropertySource) {
|
|
||||||
return o.GetLinkedMesh(sprite, materialPropertySource.shader, materialPropertySource);
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region RemappedClone Convenience Methods
|
#region RemappedClone Convenience Methods
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -115,8 +77,7 @@ namespace Spine.Unity.AttachmentTools {
|
|||||||
return newAttachment;
|
return newAttachment;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return o.Copy();
|
||||||
return o.GetCopy(true); // Non-renderable Attachments will return as normal cloned attachments.
|
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|||||||
@ -447,10 +447,6 @@ namespace Spine {
|
|||||||
return va.bones != null && va.bones.Length > 0;
|
return va.bones != null && va.bones.Length > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool IsRenderable (this Attachment a) {
|
|
||||||
return a is IHasRendererObject;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Transform Modes
|
#region Transform Modes
|
||||||
public static bool InheritsRotation (this TransformMode mode) {
|
public static bool InheritsRotation (this TransformMode mode) {
|
||||||
const int RotationBit = 0;
|
const int RotationBit = 0;
|
||||||
@ -462,153 +458,5 @@ namespace Spine {
|
|||||||
return ((int)mode & (1U << ScaleBit)) == 0;
|
return ((int)mode & (1U << ScaleBit)) == 0;
|
||||||
}
|
}
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Posing
|
|
||||||
internal static void SetPropertyToSetupPose (this Skeleton skeleton, int propertyID) {
|
|
||||||
int tt = propertyID >> 24;
|
|
||||||
var timelineType = (TimelineType)tt;
|
|
||||||
int i = propertyID - (tt << 24);
|
|
||||||
|
|
||||||
Bone bone;
|
|
||||||
IkConstraint ikc;
|
|
||||||
PathConstraint pc;
|
|
||||||
|
|
||||||
switch (timelineType) {
|
|
||||||
// Bone
|
|
||||||
case TimelineType.Rotate:
|
|
||||||
bone = skeleton.bones.Items[i];
|
|
||||||
bone.rotation = bone.data.rotation;
|
|
||||||
break;
|
|
||||||
case TimelineType.Translate:
|
|
||||||
bone = skeleton.bones.Items[i];
|
|
||||||
bone.x = bone.data.x;
|
|
||||||
bone.y = bone.data.y;
|
|
||||||
break;
|
|
||||||
case TimelineType.Scale:
|
|
||||||
bone = skeleton.bones.Items[i];
|
|
||||||
bone.scaleX = bone.data.scaleX;
|
|
||||||
bone.scaleY = bone.data.scaleY;
|
|
||||||
break;
|
|
||||||
case TimelineType.Shear:
|
|
||||||
bone = skeleton.bones.Items[i];
|
|
||||||
bone.shearX = bone.data.shearX;
|
|
||||||
bone.shearY = bone.data.shearY;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Slot
|
|
||||||
case TimelineType.Attachment:
|
|
||||||
skeleton.SetSlotAttachmentToSetupPose(i);
|
|
||||||
break;
|
|
||||||
case TimelineType.Color:
|
|
||||||
skeleton.slots.Items[i].SetColorToSetupPose();
|
|
||||||
break;
|
|
||||||
case TimelineType.TwoColor:
|
|
||||||
skeleton.slots.Items[i].SetColorToSetupPose();
|
|
||||||
break;
|
|
||||||
case TimelineType.Deform:
|
|
||||||
skeleton.slots.Items[i].Deform.Clear();
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Skeleton
|
|
||||||
case TimelineType.DrawOrder:
|
|
||||||
skeleton.SetDrawOrderToSetupPose();
|
|
||||||
break;
|
|
||||||
|
|
||||||
// IK Constraint
|
|
||||||
case TimelineType.IkConstraint:
|
|
||||||
ikc = skeleton.ikConstraints.Items[i];
|
|
||||||
ikc.mix = ikc.data.mix;
|
|
||||||
ikc.softness = ikc.data.softness;
|
|
||||||
ikc.bendDirection = ikc.data.bendDirection;
|
|
||||||
ikc.stretch = ikc.data.stretch;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// TransformConstraint
|
|
||||||
case TimelineType.TransformConstraint:
|
|
||||||
var tc = skeleton.transformConstraints.Items[i];
|
|
||||||
var tcData = tc.data;
|
|
||||||
tc.rotateMix = tcData.rotateMix;
|
|
||||||
tc.translateMix = tcData.translateMix;
|
|
||||||
tc.scaleMix = tcData.scaleMix;
|
|
||||||
tc.shearMix = tcData.shearMix;
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Path Constraint
|
|
||||||
case TimelineType.PathConstraintPosition:
|
|
||||||
pc = skeleton.pathConstraints.Items[i];
|
|
||||||
pc.position = pc.data.position;
|
|
||||||
break;
|
|
||||||
case TimelineType.PathConstraintSpacing:
|
|
||||||
pc = skeleton.pathConstraints.Items[i];
|
|
||||||
pc.spacing = pc.data.spacing;
|
|
||||||
break;
|
|
||||||
case TimelineType.PathConstraintMix:
|
|
||||||
pc = skeleton.pathConstraints.Items[i];
|
|
||||||
pc.rotateMix = pc.data.rotateMix;
|
|
||||||
pc.translateMix = pc.data.translateMix;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Resets the DrawOrder to the Setup Pose's draw order</summary>
|
|
||||||
public static void SetDrawOrderToSetupPose (this Skeleton skeleton) {
|
|
||||||
var slotsItems = skeleton.slots.Items;
|
|
||||||
int n = skeleton.slots.Count;
|
|
||||||
|
|
||||||
var drawOrder = skeleton.drawOrder;
|
|
||||||
drawOrder.Clear(false);
|
|
||||||
drawOrder.EnsureCapacity(n);
|
|
||||||
drawOrder.Count = n;
|
|
||||||
System.Array.Copy(slotsItems, drawOrder.Items, n);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Resets all the slots on the skeleton to their Setup Pose attachments but does not reset slot colors.</summary>
|
|
||||||
public static void SetSlotAttachmentsToSetupPose (this Skeleton skeleton) {
|
|
||||||
var slotsItems = skeleton.slots.Items;
|
|
||||||
for (int i = 0; i < skeleton.slots.Count; i++) {
|
|
||||||
Slot slot = slotsItems[i];
|
|
||||||
string attachmentName = slot.data.attachmentName;
|
|
||||||
slot.Attachment = string.IsNullOrEmpty(attachmentName) ? null : skeleton.GetAttachment(i, attachmentName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Resets the color of a slot to Setup Pose value.</summary>
|
|
||||||
public static void SetColorToSetupPose (this Slot slot) {
|
|
||||||
slot.r = slot.data.r;
|
|
||||||
slot.g = slot.data.g;
|
|
||||||
slot.b = slot.data.b;
|
|
||||||
slot.a = slot.data.a;
|
|
||||||
slot.r2 = slot.data.r2;
|
|
||||||
slot.g2 = slot.data.g2;
|
|
||||||
slot.b2 = slot.data.b2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Sets a slot's attachment to setup pose. If you have the slotIndex, Skeleton.SetSlotAttachmentToSetupPose is faster.</summary>
|
|
||||||
public static void SetAttachmentToSetupPose (this Slot slot) {
|
|
||||||
var slotData = slot.data;
|
|
||||||
slot.Attachment = slot.bone.skeleton.GetAttachment(slotData.name, slotData.attachmentName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Resets the attachment of slot at a given slotIndex to setup pose. This is faster than Slot.SetAttachmentToSetupPose.</summary>
|
|
||||||
public static void SetSlotAttachmentToSetupPose (this Skeleton skeleton, int slotIndex) {
|
|
||||||
var slot = skeleton.slots.Items[slotIndex];
|
|
||||||
string attachmentName = slot.data.attachmentName;
|
|
||||||
if (string.IsNullOrEmpty(attachmentName)) {
|
|
||||||
slot.Attachment = null;
|
|
||||||
} else {
|
|
||||||
var attachment = skeleton.GetAttachment(slotIndex, attachmentName);
|
|
||||||
slot.Attachment = attachment;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Resets Skeleton parts to Setup Pose according to a Spine.Animation's keyed items.</summary>
|
|
||||||
public static void SetKeyedItemsToSetupPose (this Animation animation, Skeleton skeleton) {
|
|
||||||
animation.Apply(skeleton, 0, 0, false, null, 0, MixBlend.Setup, MixDirection.Out);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void AllowImmediateQueue (this TrackEntry trackEntry) {
|
|
||||||
if (trackEntry.nextTrackLast < 0) trackEntry.nextTrackLast = 0;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,165 +0,0 @@
|
|||||||
/******************************************************************************
|
|
||||||
* Spine Runtimes License Agreement
|
|
||||||
* Last updated May 1, 2019. Replaces all prior versions.
|
|
||||||
*
|
|
||||||
* Copyright (c) 2013-2019, Esoteric Software LLC
|
|
||||||
*
|
|
||||||
* Integration of the Spine Runtimes into software or otherwise creating
|
|
||||||
* derivative works of the Spine Runtimes is permitted under the terms and
|
|
||||||
* conditions of Section 2 of the Spine Editor License Agreement:
|
|
||||||
* http://esotericsoftware.com/spine-editor-license
|
|
||||||
*
|
|
||||||
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
|
||||||
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
|
||||||
* "Products"), provided that each user of the Products must obtain their own
|
|
||||||
* Spine Editor license and redistribution of the Products in any form must
|
|
||||||
* include this license and copyright notice.
|
|
||||||
*
|
|
||||||
* THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY EXPRESS
|
|
||||||
* OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
|
||||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
|
|
||||||
* NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
||||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
||||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS
|
|
||||||
* INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY
|
|
||||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
||||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
||||||
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
||||||
*****************************************************************************/
|
|
||||||
|
|
||||||
using UnityEngine;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections;
|
|
||||||
|
|
||||||
namespace Spine.Unity.AttachmentTools {
|
|
||||||
|
|
||||||
public static class SkinUtilities {
|
|
||||||
|
|
||||||
#region Skeleton Skin Extensions
|
|
||||||
/// <summary>
|
|
||||||
/// Convenience method for duplicating a skeleton's current active skin so changes to it will not affect other skeleton instances. .</summary>
|
|
||||||
public static Skin UnshareSkin (this Skeleton skeleton, bool includeDefaultSkin, bool unshareAttachments, AnimationState state = null) {
|
|
||||||
// 1. Copy the current skin and set the skeleton's skin to the new one.
|
|
||||||
var newSkin = skeleton.GetClonedSkin("cloned skin", includeDefaultSkin, unshareAttachments, true);
|
|
||||||
skeleton.SetSkin(newSkin);
|
|
||||||
|
|
||||||
// 2. Apply correct attachments: skeleton.SetToSetupPose + animationState.Apply
|
|
||||||
if (state != null) {
|
|
||||||
skeleton.SetToSetupPose();
|
|
||||||
state.Apply(skeleton);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 3. Return unshared skin.
|
|
||||||
return newSkin;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static Skin GetClonedSkin (this Skeleton skeleton, string newSkinName, bool includeDefaultSkin = false, bool cloneAttachments = false, bool cloneMeshesAsLinked = true) {
|
|
||||||
var newSkin = new Skin(newSkinName); // may have null name. Harmless.
|
|
||||||
var defaultSkin = skeleton.data.DefaultSkin;
|
|
||||||
var activeSkin = skeleton.skin;
|
|
||||||
|
|
||||||
if (includeDefaultSkin)
|
|
||||||
defaultSkin.CopyTo(newSkin, true, cloneAttachments, cloneMeshesAsLinked);
|
|
||||||
|
|
||||||
if (activeSkin != null)
|
|
||||||
activeSkin.CopyTo(newSkin, true, cloneAttachments, cloneMeshesAsLinked);
|
|
||||||
|
|
||||||
return newSkin;
|
|
||||||
}
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets a shallow copy of the skin. The cloned skin's attachments are shared with the original skin.</summary>
|
|
||||||
public static Skin GetClone (this Skin original) {
|
|
||||||
var newSkin = new Skin(original.name + " clone");
|
|
||||||
var newSkinAttachments = newSkin.Attachments;
|
|
||||||
var newSkinBones = newSkin.Bones;
|
|
||||||
var newSkinConstraints = newSkin.Constraints;
|
|
||||||
|
|
||||||
foreach (var a in original.Attachments)
|
|
||||||
newSkinAttachments[a.Key] = a.Value;
|
|
||||||
|
|
||||||
newSkinBones.AddRange(original.bones);
|
|
||||||
newSkinConstraints.AddRange(original.constraints);
|
|
||||||
return newSkin;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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>
|
|
||||||
public static void SetAttachment (this Skin skin, string slotName, string keyName, Attachment attachment, Skeleton skeleton) {
|
|
||||||
int slotIndex = skeleton.FindSlotIndex(slotName);
|
|
||||||
if (skeleton == null) throw new System.ArgumentNullException("skeleton", "skeleton cannot be null.");
|
|
||||||
if (slotIndex == -1) throw new System.ArgumentException(string.Format("Slot '{0}' does not exist in skeleton.", slotName), "slotName");
|
|
||||||
skin.SetAttachment(slotIndex, keyName, attachment);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Adds skin items from another skin. For items that already exist, the previous values are replaced.</summary>
|
|
||||||
public static void AddAttachments (this Skin skin, Skin otherSkin) {
|
|
||||||
if (otherSkin == null) return;
|
|
||||||
otherSkin.CopyTo(skin, true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>Gets an attachment from the skin for the specified slot index and name.</summary>
|
|
||||||
public static Attachment GetAttachment (this Skin skin, string slotName, string keyName, Skeleton skeleton) {
|
|
||||||
int slotIndex = skeleton.FindSlotIndex(slotName);
|
|
||||||
if (skeleton == null) throw new System.ArgumentNullException("skeleton", "skeleton cannot be null.");
|
|
||||||
if (slotIndex == -1) throw new System.ArgumentException(string.Format("Slot '{0}' does not exist in skeleton.", slotName), "slotName");
|
|
||||||
return skin.GetAttachment(slotIndex, keyName);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <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>
|
|
||||||
public static void SetAttachment (this Skin skin, int slotIndex, string keyName, Attachment attachment) {
|
|
||||||
skin.SetAttachment(slotIndex, keyName, attachment);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void RemoveAttachment (this Skin skin, string slotName, string keyName, SkeletonData skeletonData) {
|
|
||||||
int slotIndex = skeletonData.FindSlotIndex(slotName);
|
|
||||||
if (skeletonData == null) throw new System.ArgumentNullException("skeletonData", "skeletonData cannot be null.");
|
|
||||||
if (slotIndex == -1) throw new System.ArgumentException(string.Format("Slot '{0}' does not exist in skeleton.", slotName), "slotName");
|
|
||||||
skin.RemoveAttachment(slotIndex, keyName);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void Clear (this Skin skin) {
|
|
||||||
skin.Attachments.Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
//[System.Obsolete]
|
|
||||||
public static void Append (this Skin destination, Skin source) {
|
|
||||||
source.CopyTo(destination, true, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void CopyTo (this Skin source, Skin destination, bool overwrite, bool cloneAttachments, bool cloneMeshesAsLinked = true) {
|
|
||||||
var sourceAttachments = source.Attachments;
|
|
||||||
var destinationAttachments = destination.Attachments;
|
|
||||||
var destinationBones = destination.Bones;
|
|
||||||
var destinationConstraints = destination.Constraints;
|
|
||||||
|
|
||||||
if (cloneAttachments) {
|
|
||||||
if (overwrite) {
|
|
||||||
foreach (var e in sourceAttachments)
|
|
||||||
destinationAttachments[e.Key] = e.Value.GetCopy(cloneMeshesAsLinked);
|
|
||||||
} else {
|
|
||||||
foreach (var e in sourceAttachments) {
|
|
||||||
if (destinationAttachments.ContainsKey(e.Key)) continue;
|
|
||||||
destinationAttachments.Add(e.Key, e.Value.GetCopy(cloneMeshesAsLinked));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (overwrite) {
|
|
||||||
foreach (var e in sourceAttachments)
|
|
||||||
destinationAttachments[e.Key] = e.Value;
|
|
||||||
} else {
|
|
||||||
foreach (var e in sourceAttachments) {
|
|
||||||
if (destinationAttachments.ContainsKey(e.Key)) continue;
|
|
||||||
destinationAttachments.Add(e.Key, e.Value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (BoneData data in source.bones)
|
|
||||||
if (!destinationBones.Contains(data)) destinationBones.Add(data);
|
|
||||||
|
|
||||||
foreach (ConstraintData data in source.constraints)
|
|
||||||
if (!destinationConstraints.Contains(data)) destinationConstraints.Add(data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,12 +0,0 @@
|
|||||||
fileFormatVersion: 2
|
|
||||||
guid: f4692b9527684d048862210ba3f9834e
|
|
||||||
timeCreated: 1563321428
|
|
||||||
licenseType: Free
|
|
||||||
MonoImporter:
|
|
||||||
serializedVersion: 2
|
|
||||||
defaultReferences: []
|
|
||||||
executionOrder: 0
|
|
||||||
icon: {instanceID: 0}
|
|
||||||
userData:
|
|
||||||
assetBundleName:
|
|
||||||
assetBundleVariant:
|
|
||||||
@ -161,7 +161,7 @@ namespace Spine.Unity.Playables {
|
|||||||
if (!isAnimationTransitionMatch) {
|
if (!isAnimationTransitionMatch) {
|
||||||
dummyAnimationState.ClearTracks();
|
dummyAnimationState.ClearTracks();
|
||||||
fromTrack = dummyAnimationState.SetAnimation(0, fromAnimation, fromClipLoop);
|
fromTrack = dummyAnimationState.SetAnimation(0, fromAnimation, fromClipLoop);
|
||||||
fromTrack.AllowImmediateQueue();
|
if (fromTrack.nextTrackLast < 0) fromTrack.nextTrackLast = 0; // fromTrack.AllowImmediateQueue
|
||||||
if (toAnimation != null)
|
if (toAnimation != null)
|
||||||
toTrack = dummyAnimationState.SetAnimation(0, toAnimation, clipData.loop);
|
toTrack = dummyAnimationState.SetAnimation(0, toAnimation, clipData.loop);
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user