From 73a50ef12d70d08c2a871714d841f626310385b6 Mon Sep 17 00:00:00 2001 From: Harald Csaszar Date: Tue, 10 Mar 2026 15:23:41 +0100 Subject: [PATCH] [csharp][unity] Port of commit 3789ec0: Make sequence rendering thread-safe. See #2989. --- CHANGELOG.md | 1 + spine-csharp/src/Animation.cs | 10 +- .../src/Attachments/AtlasAttachmentLoader.cs | 54 ++--- .../{IHasTextureRegion.cs => IHasSequence.cs} | 19 +- ...ureRegion.cs.meta => IHasSequence.cs.meta} | 0 .../src/Attachments/MeshAttachment.cs | 150 +++++++------- .../src/Attachments/RegionAttachment.cs | 191 +++++++++--------- spine-csharp/src/Attachments/Sequence.cs | 88 ++++++-- spine-csharp/src/Skeleton.cs | 2 +- spine-csharp/src/SkeletonBinary.cs | 24 +-- spine-csharp/src/SkeletonJson.cs | 14 +- spine-csharp/src/package.json | 2 +- .../Editor/Utility/AssetUtility.cs | 22 +- .../Editor/Windows/SkeletonBaker.cs | 16 +- .../Asset Types/BlendModeMaterials.cs | 43 ++-- .../Asset Types/RegionlessAttachmentLoader.cs | 8 +- .../Mesh Generation/MeshGenerator.cs | 50 +++-- .../TK2D/SpriteCollectionAttachmentLoader.cs | 26 +-- .../BlendModeMaterialsAsset.cs | 10 +- .../spine-unity/Utility/AtlasUtilities.cs | 73 +++---- .../Utility/AttachmentRegionExtensions.cs | 30 +-- .../spine-unity/Utility/SkeletonExtensions.cs | 7 +- spine-unity/Assets/Spine/package.json | 2 +- 23 files changed, 403 insertions(+), 439 deletions(-) rename spine-csharp/src/Attachments/{IHasTextureRegion.cs => IHasSequence.cs} (76%) rename spine-csharp/src/Attachments/{IHasTextureRegion.cs.meta => IHasSequence.cs.meta} (100%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7059b3183..fcedf7e5c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -331,6 +331,7 @@ - Attachment `ComputeWorldVertices()` methods now take an additional `skeleton` parameter - Renamed timeline constraint index methods to use unified `ConstraintIndex` property - Reorganized timeline class hierarchy with new base classes + - Removed `AtlasAttachmentLoader` method `AtlasRegion FindRegion(string name)` from public interface. Added `protected AtlasRegion FindRegion(string name, string path)` instead which may be overridden instead when deriving your own subclass. ### Unity diff --git a/spine-csharp/src/Animation.cs b/spine-csharp/src/Animation.cs index 234c037c0..c033af940 100644 --- a/spine-csharp/src/Animation.cs +++ b/spine-csharp/src/Animation.cs @@ -1881,12 +1881,12 @@ namespace Spine { private const int MODE = 1, DELAY = 2; readonly int slotIndex; - readonly IHasTextureRegion attachment; + readonly IHasSequence attachment; public SequenceTimeline (int frameCount, int slotIndex, Attachment attachment) - : base(frameCount, (int)Property.Sequence + "|" + slotIndex + "|" + ((IHasTextureRegion)attachment).Sequence.Id) { + : base(frameCount, (int)Property.Sequence + "|" + slotIndex + "|" + ((IHasSequence)attachment).Sequence.Id) { this.slotIndex = slotIndex; - this.attachment = (IHasTextureRegion)attachment; + this.attachment = (IHasSequence)attachment; } public override int FrameEntries { @@ -1927,8 +1927,6 @@ namespace Spine { if ((vertexAttachment == null) || vertexAttachment.TimelineAttachment != attachment) return; } - Sequence sequence = ((IHasTextureRegion)slotAttachment).Sequence; - if (sequence == null) return; if (direction == MixDirection.Out) { if (blend == MixBlend.Setup) pose.SequenceIndex = -1; @@ -1946,7 +1944,7 @@ namespace Spine { int modeAndIndex = (int)frames[i + MODE]; float delay = frames[i + DELAY]; - int index = modeAndIndex >> 4, count = sequence.Regions.Length; + int index = modeAndIndex >> 4, count = (((IHasSequence)slotAttachment).Sequence).Regions.Length; SequenceMode mode = (SequenceMode)(modeAndIndex & 0xf); if (mode != SequenceMode.Hold) { index += (int)((time - before) / delay + 0.0001f); diff --git a/spine-csharp/src/Attachments/AtlasAttachmentLoader.cs b/spine-csharp/src/Attachments/AtlasAttachmentLoader.cs index c29041cd3..882d21bd4 100644 --- a/spine-csharp/src/Attachments/AtlasAttachmentLoader.cs +++ b/spine-csharp/src/Attachments/AtlasAttachmentLoader.cs @@ -49,40 +49,32 @@ namespace Spine { this.allowMissingRegions = allowMissingRegions; } - private void LoadSequence (string name, string basePath, Sequence sequence) { + protected void FindRegions (string name, string basePath, Sequence sequence) { TextureRegion[] regions = sequence.Regions; for (int i = 0, n = regions.Length; i < n; i++) { - string path = sequence.GetPath(basePath, i); - regions[i] = FindRegion(path); - if (regions[i] == null && !allowMissingRegions) - throw new ArgumentException(string.Format("Region not found in atlas: {0} (region attachment: {1})", path, name)); + regions[i] = FindRegion(name, sequence.GetPath(basePath, i)); } } + protected AtlasRegion FindRegion (string name, string path) { + for (int i = 0; i < atlasArray.Length; i++) { + AtlasRegion region = atlasArray[i].FindRegion(path); + if (region != null) + return region; + } + if (!allowMissingRegions) + throw new ArgumentException(string.Format("Region not found in atlas: {0} (attachment: {1})", path, name)); + return null; + } + public RegionAttachment NewRegionAttachment (Skin skin, string name, string path, Sequence sequence) { - var attachment = new RegionAttachment(name); - if (sequence != null) - LoadSequence(name, path, sequence); - else { - AtlasRegion region = FindRegion(path); - if (region == null && !allowMissingRegions) - throw new ArgumentException(string.Format("Region not found in atlas: {0} (region attachment: {1})", path, name)); - attachment.Region = region; - } - return attachment; + FindRegions(name, path, sequence); + return new RegionAttachment(name, sequence); } public MeshAttachment NewMeshAttachment (Skin skin, string name, string path, Sequence sequence) { - var attachment = new MeshAttachment(name); - if (sequence != null) - LoadSequence(name, path, sequence); - else { - AtlasRegion region = FindRegion(path); - if (region == null && !allowMissingRegions) - throw new ArgumentException(string.Format("Region not found in atlas: {0} (region attachment: {1})", path, name)); - attachment.Region = region; - } - return attachment; + FindRegions(name, path, sequence); + return new MeshAttachment(name, sequence); } public BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, string name) { @@ -100,17 +92,5 @@ namespace Spine { public ClippingAttachment NewClippingAttachment (Skin skin, string name) { return new ClippingAttachment(name); } - - public AtlasRegion FindRegion (string name) { - AtlasRegion region; - - for (int i = 0; i < atlasArray.Length; i++) { - region = atlasArray[i].FindRegion(name); - if (region != null) - return region; - } - - return null; - } } } diff --git a/spine-csharp/src/Attachments/IHasTextureRegion.cs b/spine-csharp/src/Attachments/IHasSequence.cs similarity index 76% rename from spine-csharp/src/Attachments/IHasTextureRegion.cs rename to spine-csharp/src/Attachments/IHasSequence.cs index 79629bb8b..15da803ca 100644 --- a/spine-csharp/src/Attachments/IHasTextureRegion.cs +++ b/spine-csharp/src/Attachments/IHasSequence.cs @@ -36,25 +36,12 @@ namespace Spine { using Color32F = UnityEngine.Color; #endif - public interface IHasTextureRegion { - /// The name used to find the + public interface IHasSequence { string Path { get; set; } - /// - /// Sets the region used to draw the attachment. After setting the region or if the region's properties are changed, - /// must be called. - /// - TextureRegion Region { get; set; } - - /// - /// Updates any values the attachment calculates using the . Must be called after setting the - /// or if the region's properties are changed. - /// - void UpdateRegion (); - Color32F GetColor (); void SetColor (Color32F color); void SetColor (float r, float g, float b, float a); - - Sequence Sequence { get; set; } + Sequence Sequence { get; } + void UpdateSequence (); } } diff --git a/spine-csharp/src/Attachments/IHasTextureRegion.cs.meta b/spine-csharp/src/Attachments/IHasSequence.cs.meta similarity index 100% rename from spine-csharp/src/Attachments/IHasTextureRegion.cs.meta rename to spine-csharp/src/Attachments/IHasSequence.cs.meta diff --git a/spine-csharp/src/Attachments/MeshAttachment.cs b/spine-csharp/src/Attachments/MeshAttachment.cs index d06ead06a..52f864287 100644 --- a/spine-csharp/src/Attachments/MeshAttachment.cs +++ b/spine-csharp/src/Attachments/MeshAttachment.cs @@ -39,32 +39,25 @@ namespace Spine { #endif /// Attachment that displays a texture region using a mesh. - public class MeshAttachment : VertexAttachment, IHasTextureRegion { - internal TextureRegion region; - internal string path; - internal float[] regionUVs, uvs; + public class MeshAttachment : VertexAttachment, IHasSequence { + internal readonly Sequence sequence; + internal float[] regionUVs; internal int[] triangles; + internal int hullLength; + internal string path; // Color is a struct, set to protected to prevent // Color color = slot.color; color.a = 0.5; // modifying just a copy of the struct instead of the original // object as in reference implementation. protected Color32F color = new Color32F(1, 1, 1, 1); - internal int hullLength; private MeshAttachment parentMesh; - private Sequence sequence; - public TextureRegion Region { - get { return region; } - set { - if (value == null) throw new ArgumentNullException("region", "region cannot be null."); - region = value; - } - } public int HullLength { get { return hullLength; } set { hullLength = value; } } + + /// The UV pair for each vertex, normalized within the texture region. public float[] RegionUVs { get { return regionUVs; } set { regionUVs = value; } } /// The UV pair for each vertex, normalized within the entire texture. /// - public float[] UVs { get { return uvs; } set { uvs = value; } } public int[] Triangles { get { return triangles; } set { triangles = value; } } public Color32F GetColor () { @@ -80,7 +73,7 @@ namespace Spine { } public string Path { get { return path; } set { path = value; } } - public Sequence Sequence { get { return sequence; } set { sequence = value; } } + public Sequence Sequence { get { return sequence; } } public MeshAttachment ParentMesh { get { return parentMesh; } @@ -101,12 +94,18 @@ namespace Spine { } // Nonessential. + /// + /// Vertex index pairs describing edges for controlling triangulation, or be null if nonessential data was not exported. Mesh + /// triangles never cross edges. Triangulation is not performed at runtime. + /// public int[] Edges { get; set; } public float Width { get; set; } public float Height { get; set; } - public MeshAttachment (string name) + public MeshAttachment (string name, Sequence sequence) : base(name) { + if (sequence == null) throw new ArgumentException("sequence cannot be null.", "sequence"); + this.sequence = sequence; } /// Copy constructor. Use if the other mesh is a linked mesh. @@ -115,21 +114,17 @@ namespace Spine { if (parentMesh != null) throw new ArgumentException("Use newLinkedMesh to copy a linked mesh."); - region = other.region; path = other.path; color = other.color; regionUVs = new float[other.regionUVs.Length]; Array.Copy(other.regionUVs, 0, regionUVs, 0, regionUVs.Length); - uvs = new float[other.uvs.Length]; - Array.Copy(other.uvs, 0, uvs, 0, uvs.Length); - triangles = new int[other.triangles.Length]; Array.Copy(other.triangles, 0, triangles, 0, triangles.Length); hullLength = other.hullLength; - sequence = other.sequence == null ? null : new Sequence(other.sequence); + sequence = new Sequence(other.sequence); // Nonessential. if (other.Edges != null) { @@ -140,58 +135,81 @@ namespace Spine { Height = other.Height; } + public void UpdateSequence () { + sequence.Update(this); + } - public void UpdateRegion () { - float[] regionUVs = this.regionUVs; - if (this.uvs == null || this.uvs.Length != regionUVs.Length) this.uvs = new float[regionUVs.Length]; - float[] uvs = this.uvs; + /// Returns a new mesh with this mesh set as the . + public MeshAttachment NewLinkedMesh () { + var mesh = new MeshAttachment(Name, new Sequence(sequence)); + + mesh.timelineAttachment = timelineAttachment; + mesh.path = path; + mesh.color = color; + mesh.ParentMesh = parentMesh != null ? parentMesh : this; + mesh.UpdateSequence(); + return mesh; + } + + public override Attachment Copy () { + return parentMesh != null ? NewLinkedMesh() : new MeshAttachment(this); + } + + /// + /// Computes UVs for a mesh attachment. + /// + /// Output array for the computed UVs, same length as regionUVs. + internal static void ComputeUVs (TextureRegion region, float[] regionUVs, float[] uvs) { int n = uvs.Length; float u, v, width, height; - - if (region is AtlasRegion) { - u = this.region.u; - v = this.region.v; - AtlasRegion region = (AtlasRegion)this.region; - // Note: difference from reference implementation. - // Covers rotation since region.width and height are already setup accordingly. - float textureWidth = this.region.width / (region.u2 - region.u); - float textureHeight = this.region.height / (region.v2 - region.v); - switch (region.degrees) { - case 90: - u -= (region.originalHeight - region.offsetY - region.packedWidth) / textureWidth; - v -= (region.originalWidth - region.offsetX - region.packedHeight) / textureHeight; - width = region.originalHeight / textureWidth; - height = region.originalWidth / textureHeight; + AtlasRegion r = region as AtlasRegion; + if (r != null) { + u = r.u; + v = r.v; + float textureWidth = region.width / (region.u2 - region.u); + float textureHeight = region.height / (region.v2 - region.v); + switch (r.degrees) { + case 90: { + u -= (r.originalHeight - r.offsetY - r.packedWidth) / textureWidth; + v -= (r.originalWidth - r.offsetX - r.packedHeight) / textureHeight; + width = r.originalHeight / textureWidth; + height = r.originalWidth / textureHeight; for (int i = 0; i < n; i += 2) { uvs[i] = u + regionUVs[i + 1] * width; uvs[i + 1] = v + (1 - regionUVs[i]) * height; } return; - case 180: - u -= (region.originalWidth - region.offsetX - region.packedWidth) / textureWidth; - v -= region.offsetY / textureHeight; - width = region.originalWidth / textureWidth; - height = region.originalHeight / textureHeight; + } + case 180: { + u -= (r.originalWidth - r.offsetX - r.packedWidth) / textureWidth; + v -= r.offsetY / textureHeight; + width = r.originalWidth / textureWidth; + height = r.originalHeight / textureHeight; for (int i = 0; i < n; i += 2) { uvs[i] = u + (1 - regionUVs[i]) * width; uvs[i + 1] = v + (1 - regionUVs[i + 1]) * height; } return; - case 270: - u -= region.offsetY / textureWidth; - v -= region.offsetX / textureHeight; - width = region.originalHeight / textureWidth; - height = region.originalWidth / textureHeight; + } + case 270: { + u -= r.offsetY / textureWidth; + v -= r.offsetX / textureHeight; + width = r.originalHeight / textureWidth; + height = r.originalWidth / textureHeight; for (int i = 0; i < n; i += 2) { uvs[i] = u + (1 - regionUVs[i + 1]) * width; uvs[i + 1] = v + regionUVs[i] * height; } return; } - u -= region.offsetX / textureWidth; - v -= (region.originalHeight - region.offsetY - region.packedHeight) / textureHeight; - width = region.originalWidth / textureWidth; - height = region.originalHeight / textureHeight; + default: { + u -= r.offsetX / textureWidth; + v -= (r.originalHeight - r.offsetY - r.packedHeight) / textureHeight; + width = r.originalWidth / textureWidth; + height = r.originalHeight / textureHeight; + break; + } + } } else if (region == null) { u = v = 0; width = height = 1; @@ -206,29 +224,5 @@ namespace Spine { uvs[i + 1] = v + regionUVs[i + 1] * height; } } - - /// If the attachment has a , the region may be changed. - override public void ComputeWorldVertices (Skeleton skeleton, Slot slot, int start, int count, float[] worldVertices, int offset, - int stride = 2) { - if (sequence != null) sequence.Apply(slot.AppliedPose, this); - base.ComputeWorldVertices(skeleton, slot, start, count, worldVertices, offset, stride); - } - - /// Returns a new mesh with this mesh set as the . - public MeshAttachment NewLinkedMesh () { - var mesh = new MeshAttachment(Name); - - mesh.timelineAttachment = timelineAttachment; - mesh.region = region; - mesh.path = path; - mesh.color = color; - mesh.ParentMesh = parentMesh != null ? parentMesh : this; - if (mesh.Region != null) mesh.UpdateRegion(); - return mesh; - } - - public override Attachment Copy () { - return parentMesh != null ? NewLinkedMesh() : new MeshAttachment(this); - } } } diff --git a/spine-csharp/src/Attachments/RegionAttachment.cs b/spine-csharp/src/Attachments/RegionAttachment.cs index 27877eeb6..09bf19f1c 100644 --- a/spine-csharp/src/Attachments/RegionAttachment.cs +++ b/spine-csharp/src/Attachments/RegionAttachment.cs @@ -39,21 +39,19 @@ namespace Spine { #endif /// Attachment that displays a texture region. - public class RegionAttachment : Attachment, IHasTextureRegion { + public class RegionAttachment : Attachment, IHasSequence { public const int BLX = 0, BLY = 1; public const int ULX = 2, ULY = 3; public const int URX = 4, URY = 5; public const int BRX = 6, BRY = 7; - internal TextureRegion region; + internal readonly Sequence sequence; internal float x, y, rotation, scaleX = 1, scaleY = 1, width, height; - internal float[] offset = new float[8], uvs = new float[8]; // Color is a struct, set to protected to prevent // Color color = slot.color; color.a = 0.5; // modifying just a copy of the struct instead of the original // object as in reference implementation. protected Color32F color = new Color32F(1, 1, 1, 1); - internal Sequence sequence; public float X { get { return x; } set { x = value; } } public float Y { get { return y; } set { y = value; } } @@ -76,22 +74,17 @@ namespace Spine { } public string Path { get; set; } - public TextureRegion Region { get { return region; } set { region = value; } } + public Sequence Sequence { get { return sequence; } } - /// For each of the 4 vertices, a pair of x,y values that is the local position of the vertex. - /// - public float[] Offset { get { return offset; } } - public float[] UVs { get { return uvs; } } - public Sequence Sequence { get { return sequence; } set { sequence = value; } } - - public RegionAttachment (string name) + public RegionAttachment (string name, Sequence sequence) : base(name) { + if (sequence == null) throw new ArgumentException("sequence cannot be null.", "sequence"); + this.sequence = sequence; } /// Copy constructor. public RegionAttachment (RegionAttachment other) : base(other) { - region = other.region; Path = other.Path; x = other.x; y = other.y; @@ -100,41 +93,94 @@ namespace Spine { rotation = other.rotation; width = other.width; height = other.height; - Array.Copy(other.uvs, 0, uvs, 0, 8); - Array.Copy(other.offset, 0, offset, 0, 8); color = other.color; - sequence = other.sequence == null ? null : new Sequence(other.sequence); + sequence = new Sequence(other.sequence); } - /// Calculates the and using the region and the attachment's transform. Must be called if the - /// region, the region's properties, or the transform are changed. - public void UpdateRegion () { - float width = Width, height = Height; - float localX2 = width / 2; - float localY2 = height / 2; - float localX = -localX2; - float localY = -localY2; + /// + /// Transforms the attachment's four vertices to world coordinates. If the attachment has a the region may + /// be changed. + /// + /// See World transforms in the Spine + /// Runtimes Guide. + /// The output world vertices. Must have a length greater than or equal to offset + 8. + /// The vertex offsets. + /// The worldVertices index to begin writing values. + /// The number of worldVertices entries between the value pairs written. + public void ComputeWorldVertices (Slot slot, float[] vertexOffsets, float[] worldVertices, int offset, int stride = 2) { + BonePose bone = slot.Bone.AppliedPose; + float bwx = bone.worldX, bwy = bone.worldY; + float a = bone.a, b = bone.b, c = bone.c, d = bone.d; + + // Vertex order is different from RegionAttachment.java + float offsetX = vertexOffsets[BRX]; // 0 + float offsetY = vertexOffsets[BRY]; // 1 + worldVertices[offset] = offsetX * a + offsetY * b + bwx; // bl + worldVertices[offset + 1] = offsetX * c + offsetY * d + bwy; + offset += stride; + + offsetX = vertexOffsets[BLX]; // 2 + offsetY = vertexOffsets[BLY]; // 3 + worldVertices[offset] = offsetX * a + offsetY * b + bwx; // ul + worldVertices[offset + 1] = offsetX * c + offsetY * d + bwy; + offset += stride; + + offsetX = vertexOffsets[ULX]; // 4 + offsetY = vertexOffsets[ULY]; // 5 + worldVertices[offset] = offsetX * a + offsetY * b + bwx; // ur + worldVertices[offset + 1] = offsetX * c + offsetY * d + bwy; + offset += stride; + + offsetX = vertexOffsets[URX]; // 6 + offsetY = vertexOffsets[URY]; // 7 + worldVertices[offset] = offsetX * a + offsetY * b + bwx; // br + worldVertices[offset + 1] = offsetX * c + offsetY * d + bwy; + //offset += stride; + } + + /// + /// Returns the vertex offsets for the specified slot pose. + /// + public float[] GetOffsets (SlotPose pose) { + return sequence.GetOffsets(sequence.ResolveIndex(pose)); + } + + public void UpdateSequence () { + sequence.Update(this); + } + + public override Attachment Copy () { + return new RegionAttachment(this); + } + + /// + /// Computes UVs and offsets for a region attachment. + /// + /// Output array for the computed UVs, length of 8. + /// Output array for the computed vertex offsets, length of 8. + internal static void ComputeUVs (TextureRegion region, float x, float y, float scaleX, float scaleY, float rotation, float width, + float height, float[] offset, float[] uvs) { + float localX2 = width / 2, localY2 = height / 2; + float localX = -localX2, localY = -localY2; bool rotated = false; - if (region is AtlasRegion) { - AtlasRegion region = (AtlasRegion)this.region; - localX += region.offsetX / region.originalWidth * width; - localY += region.offsetY / region.originalHeight * height; - if (region.degrees == 90) { + AtlasRegion r = region as AtlasRegion; + if (r != null) { + localX += r.offsetX / r.originalWidth * width; + localY += r.offsetY / r.originalHeight * height; + if (r.degrees == 90) { rotated = true; - localX2 -= (region.originalWidth - region.offsetX - region.packedHeight) / region.originalWidth * width; - localY2 -= (region.originalHeight - region.offsetY - region.packedWidth) / region.originalHeight * height; + localX2 -= (r.originalWidth - r.offsetX - r.packedHeight) / r.originalWidth * width; + localY2 -= (r.originalHeight - r.offsetY - r.packedWidth) / r.originalHeight * height; } else { - localX2 -= (region.originalWidth - region.offsetX - region.packedWidth) / region.originalWidth * width; - localY2 -= (region.originalHeight - region.offsetY - region.packedHeight) / region.originalHeight * height; + localX2 -= (r.originalWidth - r.offsetX - r.packedWidth) / r.originalWidth * width; + localY2 -= (r.originalHeight - r.offsetY - r.packedHeight) / r.originalHeight * height; } } - float scaleX = ScaleX, scaleY = ScaleY; localX *= scaleX; localY *= scaleY; localX2 *= scaleX; localY2 *= scaleY; - float r = Rotation * MathUtils.DegRad, cos = (float)Math.Cos(r), sin = (float)Math.Sin(r); - float x = X, y = Y; + float rot = rotation * MathUtils.DegRad, cos = (float)Math.Cos(rot), sin = (float)Math.Sin(rot); float localXCos = localX * cos + x; float localXSin = localX * sin; float localYCos = localY * cos + y; @@ -143,7 +189,6 @@ namespace Spine { float localX2Sin = localX2 * sin; float localY2Cos = localY2 * cos + y; float localY2Sin = localY2 * sin; - float[] offset = this.offset; offset[BLX] = localXCos - localYSin; offset[BLY] = localYCos + localXSin; offset[ULX] = localXCos - localY2Sin; @@ -152,8 +197,6 @@ namespace Spine { offset[URY] = localY2Cos + localX2Sin; offset[BRX] = localX2Cos - localYSin; offset[BRY] = localYCos + localX2Sin; - - float[] uvs = this.uvs; if (region == null) { uvs[BLX] = 0; uvs[BLY] = 0; @@ -163,71 +206,23 @@ namespace Spine { uvs[URY] = 1; uvs[BRX] = 1; uvs[BRY] = 0; - } else if (rotated) { - uvs[BLX] = region.u2; - uvs[BLY] = region.v; - uvs[ULX] = region.u2; - uvs[ULY] = region.v2; - uvs[URX] = region.u; - uvs[URY] = region.v2; - uvs[BRX] = region.u; - uvs[BRY] = region.v; } else { uvs[BLX] = region.u2; - uvs[BLY] = region.v2; - uvs[ULX] = region.u; uvs[ULY] = region.v2; uvs[URX] = region.u; - uvs[URY] = region.v; - uvs[BRX] = region.u2; uvs[BRY] = region.v; + if (rotated) { + uvs[BLY] = region.v; + uvs[ULX] = region.u2; + uvs[URY] = region.v2; + uvs[BRX] = region.u; + } else { + uvs[BLY] = region.v2; + uvs[ULX] = region.u; + uvs[URY] = region.v; + uvs[BRX] = region.u2; + } } } - - /// - /// Transforms the attachment's four vertices to world coordinates. If the attachment has a the region may - /// be changed. - /// The parent bone. - /// The output world vertices. Must have a length greater than or equal to offset + 8. - /// The worldVertices index to begin writing values. - /// The number of worldVertices entries between the value pairs written. - public void ComputeWorldVertices (Slot slot, float[] worldVertices, int offset, int stride = 2) { - if (sequence != null) sequence.Apply(slot.AppliedPose, this); - - float[] vertexOffset = this.offset; - BonePose bone = slot.Bone.AppliedPose; - float bwx = bone.worldX, bwy = bone.worldY; - float a = bone.a, b = bone.b, c = bone.c, d = bone.d; - float offsetX, offsetY; - - // Vertex order is different from RegionAttachment.java - offsetX = vertexOffset[BRX]; // 0 - offsetY = vertexOffset[BRY]; // 1 - worldVertices[offset] = offsetX * a + offsetY * b + bwx; // bl - worldVertices[offset + 1] = offsetX * c + offsetY * d + bwy; - offset += stride; - - offsetX = vertexOffset[BLX]; // 2 - offsetY = vertexOffset[BLY]; // 3 - worldVertices[offset] = offsetX * a + offsetY * b + bwx; // ul - worldVertices[offset + 1] = offsetX * c + offsetY * d + bwy; - offset += stride; - - offsetX = vertexOffset[ULX]; // 4 - offsetY = vertexOffset[ULY]; // 5 - worldVertices[offset] = offsetX * a + offsetY * b + bwx; // ur - worldVertices[offset + 1] = offsetX * c + offsetY * d + bwy; - offset += stride; - - offsetX = vertexOffset[URX]; // 6 - offsetY = vertexOffset[URY]; // 7 - worldVertices[offset] = offsetX * a + offsetY * b + bwx; // br - worldVertices[offset + 1] = offsetX * c + offsetY * d + bwy; - //offset += stride; - } - - public override Attachment Copy () { - return new RegionAttachment(this); - } } } diff --git a/spine-csharp/src/Attachments/Sequence.cs b/spine-csharp/src/Attachments/Sequence.cs index 42f523a22..4d4ae6dca 100644 --- a/spine-csharp/src/Attachments/Sequence.cs +++ b/spine-csharp/src/Attachments/Sequence.cs @@ -31,12 +31,18 @@ using System; using System.Text; namespace Spine { + /// + /// Holds texture regions, UVs, and vertex offsets for rendering a region or mesh attachment. must + /// be populated and called before use. + /// public class Sequence { static int nextID = 0; static readonly Object nextIdLock = new Object(); internal readonly int id; internal readonly TextureRegion[] regions; + internal readonly bool pathSuffix; + internal float[][] uvs, offsets; internal int start, digits, setupIndex; public int Start { get { return start; } set { start = value; } } @@ -44,14 +50,16 @@ namespace Spine { /// The index of the region to show for the setup pose. public int SetupIndex { get { return setupIndex; } set { setupIndex = value; } } public TextureRegion[] Regions { get { return regions; } } + public bool PathSuffix { get { return pathSuffix; } } /// Returns a unique ID for this attachment. public int Id { get { return id; } } - public Sequence (int count) { + public Sequence (int count, bool pathSuffix) { lock (Sequence.nextIdLock) { id = Sequence.nextID++; } regions = new TextureRegion[count]; + this.pathSuffix = pathSuffix; } /// Copy constructor. @@ -59,26 +67,82 @@ namespace Spine { lock (Sequence.nextIdLock) { id = Sequence.nextID++; } - regions = new TextureRegion[other.regions.Length]; - Array.Copy(other.regions, 0, regions, 0, regions.Length); + int regionCount = other.regions.Length; + regions = new TextureRegion[regionCount]; + Array.Copy(other.regions, 0, regions, 0, regionCount); start = other.start; digits = other.digits; setupIndex = other.setupIndex; - } + pathSuffix = other.pathSuffix; - public void Apply (SlotPose slot, IHasTextureRegion attachment) { - int index = slot.SequenceIndex; - if (index == -1) index = setupIndex; - if (index >= regions.Length) index = regions.Length - 1; - TextureRegion region = regions[index]; - if (attachment.Region != region) { - attachment.Region = region; - attachment.UpdateRegion(); + if (other.uvs != null) { + int length = other.uvs[0].Length; + uvs = new float[regionCount][]; + for (int i = 0; i < regionCount; i++) { + uvs[i] = new float[length]; + Array.Copy(other.uvs[i], 0, uvs[i], 0, length); + } + } + if (other.offsets != null) { + offsets = new float[regionCount][]; + for (int i = 0; i < regionCount; i++) { + offsets[i] = new float[8]; + Array.Copy(other.offsets[i], 0, offsets[i], 0, 8); + } } } + public void Update (IHasSequence attachment) { + int regionCount = regions.Length; + RegionAttachment region = attachment as RegionAttachment; + if (region != null) { + uvs = new float[regionCount][]; + offsets = new float[regionCount][]; + for (int i = 0; i < regionCount; i++) { + uvs[i] = new float[8]; + offsets[i] = new float[8]; + RegionAttachment.ComputeUVs(regions[i], region.x, region.y, region.scaleX, region.scaleY, region.rotation, + region.width, region.height, offsets[i], uvs[i]); + } + } else { + MeshAttachment mesh = attachment as MeshAttachment; + if (mesh != null) { + float[] regionUVs = mesh.regionUVs; + uvs = new float[regionCount][]; + offsets = null; + for (int i = 0; i < regionCount; i++) { + uvs[i] = new float[regionUVs.Length]; + MeshAttachment.ComputeUVs(regions[i], regionUVs, uvs[i]); + } + } + } + } + + public int ResolveIndex (SlotPose pose) { + int index = pose.SequenceIndex; + if (index == -1) index = setupIndex; + if (index >= regions.Length) index = regions.Length - 1; + return index; + } + + public TextureRegion GetRegion (int index) { + return regions[index]; + } + + public float[] GetUVs (int index) { + return uvs[index]; + } + + /// + /// Returns vertex offsets from the center of a . Invalid to call for a . + /// + public float[] GetOffsets (int index) { + return offsets[index]; + } + public string GetPath (string basePath, int index) { + if (!pathSuffix) return basePath; var buffer = new StringBuilder(basePath.Length + digits); buffer.Append(basePath); string frame = (start + index).ToString(); diff --git a/spine-csharp/src/Skeleton.cs b/spine-csharp/src/Skeleton.cs index d341ad41a..79719c75d 100644 --- a/spine-csharp/src/Skeleton.cs +++ b/spine-csharp/src/Skeleton.cs @@ -459,7 +459,7 @@ namespace Spine { verticesLength = 8; vertices = temp; if (vertices.Length < 8) vertices = temp = new float[8]; - region.ComputeWorldVertices(slot, vertices, 0, 2); + region.ComputeWorldVertices(slot, region.GetOffsets(slot.applied), vertices, 0, 2); triangles = quadTriangles; } else { MeshAttachment mesh = attachment as MeshAttachment; diff --git a/spine-csharp/src/SkeletonBinary.cs b/spine-csharp/src/SkeletonBinary.cs index 04e97fbe8..c4016867c 100644 --- a/spine-csharp/src/SkeletonBinary.cs +++ b/spine-csharp/src/SkeletonBinary.cs @@ -461,7 +461,7 @@ namespace Spine { if (parent == null) throw new Exception("Parent mesh not found: " + linkedMesh.parent); linkedMesh.mesh.TimelineAttachment = linkedMesh.inheritTimelines ? (VertexAttachment)parent : linkedMesh.mesh; linkedMesh.mesh.ParentMesh = (MeshAttachment)parent; - if (linkedMesh.mesh.Region != null) linkedMesh.mesh.UpdateRegion(); + linkedMesh.mesh.UpdateSequence(); } linkedMeshes.Clear(); @@ -546,7 +546,7 @@ namespace Spine { case AttachmentType.Region: { string path = (flags & 16) != 0 ? input.ReadStringRef() : null; uint color = (flags & 32) != 0 ? (uint)input.ReadInt() : 0xffffffff; - Sequence sequence = (flags & 64) != 0 ? ReadSequence(input) : null; + Sequence sequence = ReadSequence(input, (flags & 64) != 0); float rotation = (flags & 128) != 0 ? input.ReadFloat() : 0; float x = input.ReadFloat(); float y = input.ReadFloat(); @@ -567,8 +567,7 @@ namespace Spine { region.width = width * scale; region.height = height * scale; region.SetColor(color.RGBA8888ToColor()); - region.sequence = sequence; - if (region.Region != null) region.UpdateRegion(); + region.UpdateSequence(); return region; } case AttachmentType.Boundingbox: { @@ -586,7 +585,7 @@ namespace Spine { case AttachmentType.Mesh: { string path = (flags & 16) != 0 ? input.ReadStringRef() : name; uint color = (flags & 32) != 0 ? (uint)input.ReadInt() : 0xffffffff; - Sequence sequence = (flags & 64) != 0 ? ReadSequence(input) : null; + Sequence sequence = ReadSequence(input, (flags & 64) != 0); int hullLength = input.ReadInt(true); Vertices vertices = ReadVertices(input, (flags & 128) != 0); float[] uvs = ReadFloatArray(input, vertices.length, 1); @@ -604,25 +603,24 @@ namespace Spine { if (mesh == null) return null; mesh.Path = path; mesh.SetColor(color.RGBA8888ToColor()); + mesh.HullLength = hullLength << 1; mesh.bones = vertices.bones; mesh.vertices = vertices.vertices; mesh.WorldVerticesLength = vertices.length; - mesh.triangles = triangles; mesh.regionUVs = uvs; - if (mesh.Region != null) mesh.UpdateRegion(); - mesh.HullLength = hullLength << 1; - mesh.Sequence = sequence; + mesh.triangles = triangles; if (nonessential) { mesh.Edges = edges; mesh.Width = width * scale; mesh.Height = height * scale; } + mesh.UpdateSequence(); return mesh; } case AttachmentType.Linkedmesh: { string path = (flags & 16) != 0 ? input.ReadStringRef() : name; uint color = (flags & 32) != 0 ? (uint)input.ReadInt() : 0xffffffff; - Sequence sequence = (flags & 64) != 0 ? ReadSequence(input) : null; + Sequence sequence = ReadSequence(input, (flags & 64) != 0); bool inheritTimelines = (flags & 128) != 0; int skinIndex = input.ReadInt(true); string parent = input.ReadStringRef(); @@ -636,7 +634,6 @@ namespace Spine { if (mesh == null) return null; mesh.Path = path; mesh.SetColor(color.RGBA8888ToColor()); - mesh.Sequence = sequence; if (nonessential) { mesh.Width = width * scale; mesh.Height = height * scale; @@ -696,8 +693,9 @@ namespace Spine { return null; } - private Sequence ReadSequence (SkeletonInput input) { - var sequence = new Sequence(input.ReadInt(true)); + private Sequence ReadSequence (SkeletonInput input, bool hasPathSuffix) { + if (!hasPathSuffix) return new Sequence(1, false); + var sequence = new Sequence(input.ReadInt(true), true); sequence.Start = input.ReadInt(true); sequence.Digits = input.ReadInt(true); sequence.SetupIndex = input.ReadInt(true); diff --git a/spine-csharp/src/SkeletonJson.cs b/spine-csharp/src/SkeletonJson.cs index 6428b4342..2b2b67240 100644 --- a/spine-csharp/src/SkeletonJson.cs +++ b/spine-csharp/src/SkeletonJson.cs @@ -494,7 +494,7 @@ namespace Spine { if (parent == null) throw new Exception("Parent mesh not found: " + linkedMesh.parent); linkedMesh.mesh.TimelineAttachment = linkedMesh.inheritTimelines ? (VertexAttachment)parent : linkedMesh.mesh; linkedMesh.mesh.ParentMesh = (MeshAttachment)parent; - if (linkedMesh.mesh.Region != null) linkedMesh.mesh.UpdateRegion(); + linkedMesh.mesh.UpdateSequence(); } linkedMeshes.Clear(); @@ -596,14 +596,13 @@ namespace Spine { region.rotation = GetFloat(map, "rotation", 0); region.width = GetFloat(map, "width") * scale; region.height = GetFloat(map, "height") * scale; - region.sequence = sequence; if (map.ContainsKey("color")) { string color = (string)map["color"]; region.SetColor(ToColor32(color, 8)); } - if (region.Region != null) region.UpdateRegion(); + region.UpdateSequence(); return region; } case AttachmentType.Boundingbox: @@ -628,7 +627,6 @@ namespace Spine { mesh.Width = GetFloat(map, "width", 0) * scale; mesh.Height = GetFloat(map, "height", 0) * scale; - mesh.Sequence = sequence; string parent = GetString(map, "parent", null); if (parent != null) { @@ -640,10 +638,10 @@ namespace Spine { ReadVertices(map, mesh, uvs.Length); mesh.triangles = GetIntArray(map, "triangles"); mesh.regionUVs = uvs; - if (mesh.Region != null) mesh.UpdateRegion(); - + if (map.ContainsKey("hull")) mesh.HullLength = GetInt(map, "hull", 0) << 1; if (map.ContainsKey("edges")) mesh.Edges = GetIntArray(map, "edges"); + mesh.UpdateSequence(); return mesh; } case AttachmentType.Path: { @@ -693,8 +691,8 @@ namespace Spine { public static Sequence ReadSequence (object sequenceJson) { Dictionary map = sequenceJson as Dictionary; - if (map == null) return null; - var sequence = new Sequence(GetInt(map, "count")); + if (map == null) return new Sequence(1, false); + var sequence = new Sequence(GetInt(map, "count"), true); sequence.start = GetInt(map, "start", 1); sequence.digits = GetInt(map, "digits", 0); sequence.setupIndex = GetInt(map, "setup", 0); diff --git a/spine-csharp/src/package.json b/spine-csharp/src/package.json index 9959001ff..0c0ea0376 100644 --- a/spine-csharp/src/package.json +++ b/spine-csharp/src/package.json @@ -2,7 +2,7 @@ "name": "com.esotericsoftware.spine.spine-csharp", "displayName": "spine-csharp Runtime", "description": "This plugin provides the spine-csharp core runtime.", - "version": "4.3.12", + "version": "4.3.13", "unity": "2018.3", "author": { "name": "Esoteric Software", diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/AssetUtility.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/AssetUtility.cs index ef9d1841f..11516abb0 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/AssetUtility.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Utility/AssetUtility.cs @@ -300,24 +300,14 @@ namespace Spine.Unity.Editor { } public RegionAttachment NewRegionAttachment (Skin skin, string name, string path, Sequence sequence) { - RegionAttachment regionAttachment = new RegionAttachment(name); - if (sequence != null) - LoadSequence(path, sequence); - else { - requirementList.Add(path); - AssignDummyRegion(regionAttachment); - } + RegionAttachment regionAttachment = new RegionAttachment(name, sequence); + LoadSequence(path, sequence); return regionAttachment; } public MeshAttachment NewMeshAttachment (Skin skin, string name, string path, Sequence sequence) { - MeshAttachment meshAttachment = new MeshAttachment(name); - if (sequence != null) - LoadSequence(path, sequence); - else { - requirementList.Add(path); - AssignDummyRegion(meshAttachment); - } + MeshAttachment meshAttachment = new MeshAttachment(name, sequence); + LoadSequence(path, sequence); return meshAttachment; } @@ -344,10 +334,6 @@ namespace Spine.Unity.Editor { requirementList.Add(path); } } - - private static void AssignDummyRegion (IHasTextureRegion attachment) { - attachment.Region = new AtlasRegion(); - } } #endregion diff --git a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Windows/SkeletonBaker.cs b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Windows/SkeletonBaker.cs index 8948f3479..31a0764b9 100644 --- a/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Windows/SkeletonBaker.cs +++ b/spine-unity/Assets/Spine/Editor/spine-unity/Editor/Windows/SkeletonBaker.cs @@ -520,8 +520,10 @@ namespace Spine.Unity.Editor { bone.AppliedPose.UpdateWorldTransform(skeleton); float[] floatVerts = new float[8]; - attachment.ComputeWorldVertices(slot, floatVerts, 0); - Vector2[] uvs = ExtractUV(attachment.UVs); + Sequence sequence = attachment.Sequence; + int sequenceIndex = 0; + attachment.ComputeWorldVertices(slot, sequence.GetOffsets(sequenceIndex), floatVerts, 0); + Vector2[] uvs = ExtractUV(sequence.GetUVs(sequenceIndex)); Vector3[] verts = ExtractVerts(floatVerts); //unrotate verts now that they're centered @@ -559,7 +561,10 @@ namespace Spine.Unity.Editor { float[] floatVerts = new float[attachment.WorldVerticesLength]; attachment.ComputeWorldVertices(skeleton, slot, floatVerts); - Vector2[] uvs = ExtractUV(attachment.UVs); + + Sequence sequence = attachment.Sequence; + int sequenceIndex = 0; + Vector2[] uvs = ExtractUV(sequence.GetUVs(sequenceIndex)); Vector3[] verts = ExtractVerts(floatVerts); int[] triangles = attachment.Triangles; @@ -624,7 +629,10 @@ namespace Spine.Unity.Editor { float[] floatVerts = new float[attachment.WorldVerticesLength]; attachment.ComputeWorldVertices(skeleton, skeleton.Slots.Items[slotIndex], floatVerts); - Vector2[] uvs = ExtractUV(attachment.UVs); + + Sequence sequence = attachment.Sequence; + int sequenceIndex = 0; + Vector2[] uvs = ExtractUV(sequence.GetUVs(sequenceIndex)); Vector3[] verts = ExtractVerts(floatVerts); int[] triangles = attachment.Triangles; diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/BlendModeMaterials.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/BlendModeMaterials.cs index 58fd28116..feb1299fa 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/BlendModeMaterials.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/BlendModeMaterials.cs @@ -88,7 +88,7 @@ namespace Spine.Unity { skin.GetAttachments(slotIndex, skinEntries); foreach (Skin.SkinEntry entry in skinEntries) { - if (entry.Attachment is IHasTextureRegion) { + if (entry.Attachment is IHasSequence) { requiresBlendModeMaterials = true; return true; } @@ -165,22 +165,15 @@ namespace Spine.Unity { skin.GetAttachments(slotIndex, skinEntries); foreach (Skin.SkinEntry entry in skinEntries) { - IHasTextureRegion renderableAttachment = entry.Attachment as IHasTextureRegion; + IHasSequence renderableAttachment = entry.Attachment as IHasSequence; if (renderableAttachment != null) { - AtlasRegion originalRegion = (AtlasRegion)renderableAttachment.Region; - if (originalRegion != null) { - anyCreationFailed |= createForRegionFunc( - ref replacementMaterials, ref anyReplacementMaterialsChanged, - originalRegion, materialTemplate, materialSuffix, skeletonDataAsset); - } else { - Sequence sequence = renderableAttachment.Sequence; - if (sequence != null && sequence.Regions != null) { - for (int i = 0, count = sequence.Regions.Length; i < count; ++i) { - originalRegion = (AtlasRegion)sequence.Regions[i]; - anyCreationFailed |= createForRegionFunc( - ref replacementMaterials, ref anyReplacementMaterialsChanged, - originalRegion, materialTemplate, materialSuffix, skeletonDataAsset); - } + Sequence sequence = renderableAttachment.Sequence; + if (sequence != null && sequence.Regions != null) { + for (int i = 0, count = sequence.Regions.Length; i < count; ++i) { + AtlasRegion originalRegion = (AtlasRegion)sequence.Regions[i]; + anyCreationFailed |= createForRegionFunc( + ref replacementMaterials, ref anyReplacementMaterialsChanged, + originalRegion, materialTemplate, materialSuffix, skeletonDataAsset); } } } @@ -268,20 +261,12 @@ namespace Spine.Unity { skin.GetAttachments(slotIndex, skinEntries); foreach (Skin.SkinEntry entry in skinEntries) { - IHasTextureRegion renderableAttachment = entry.Attachment as IHasTextureRegion; + IHasSequence renderableAttachment = entry.Attachment as IHasSequence; if (renderableAttachment != null) { - if (renderableAttachment.Sequence != null) { - TextureRegion[] regions = renderableAttachment.Sequence.Regions; - for (int i = 0; i < regions.Length; ++i) { - regions[i] = CloneAtlasRegionWithMaterial( - (AtlasRegion)regions[i], replacementMaterials); - } - if (regions.Length > 0) { - renderableAttachment.Region = regions[0]; - } - } else if (renderableAttachment.Region != null) { - renderableAttachment.Region = CloneAtlasRegionWithMaterial( - (AtlasRegion)renderableAttachment.Region, replacementMaterials); + TextureRegion[] regions = renderableAttachment.Sequence.Regions; + for (int i = 0; i < regions.Length; ++i) { + regions[i] = CloneAtlasRegionWithMaterial( + (AtlasRegion)regions[i], replacementMaterials); } } } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/RegionlessAttachmentLoader.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/RegionlessAttachmentLoader.cs index 974606098..9a765d53b 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/RegionlessAttachmentLoader.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Asset Types/RegionlessAttachmentLoader.cs @@ -57,16 +57,12 @@ namespace Spine.Unity { } public RegionAttachment NewRegionAttachment (Skin skin, string name, string path, Sequence sequence) { - RegionAttachment attachment = new RegionAttachment(name) { - Region = EmptyRegion - }; + RegionAttachment attachment = new RegionAttachment(name, new Sequence(1, false)); return attachment; } public MeshAttachment NewMeshAttachment (Skin skin, string name, string path, Sequence sequence) { - MeshAttachment attachment = new MeshAttachment(name) { - Region = EmptyRegion - }; + MeshAttachment attachment = new MeshAttachment(name, new Sequence(1, false)); return attachment; } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Mesh Generation/MeshGenerator.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Mesh Generation/MeshGenerator.cs index d68965fed..f098781a2 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Mesh Generation/MeshGenerator.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Mesh Generation/MeshGenerator.cs @@ -254,15 +254,17 @@ namespace Spine.Unity { RegionAttachment regionAttachment = attachment as RegionAttachment; if (regionAttachment != null) { - if (regionAttachment.Sequence != null) regionAttachment.Sequence.Apply(slot.AppliedPose, regionAttachment); - rendererObject = regionAttachment.Region; + Sequence sequence = regionAttachment.Sequence; + int sequenceIndex = sequence.ResolveIndex(slot.AppliedPose); + rendererObject = sequence.GetRegion(sequenceIndex); attachmentVertexCount = 4; attachmentTriangleCount = 6; } else { MeshAttachment meshAttachment = attachment as MeshAttachment; if (meshAttachment != null) { - if (meshAttachment.Sequence != null) meshAttachment.Sequence.Apply(slot.AppliedPose, meshAttachment); - rendererObject = meshAttachment.Region; + Sequence sequence = meshAttachment.Sequence; + int sequenceIndex = sequence.ResolveIndex(slot.AppliedPose); + rendererObject = sequence.GetRegion(sequenceIndex); attachmentVertexCount = meshAttachment.WorldVerticesLength >> 1; attachmentTriangleCount = meshAttachment.Triangles.Length; } else { @@ -323,10 +325,11 @@ namespace Spine.Unity { #endif ) continue; Attachment attachment = slot.AppliedPose.Attachment; - IHasTextureRegion rendererAttachment = attachment as IHasTextureRegion; + IHasSequence rendererAttachment = attachment as IHasSequence; if (rendererAttachment != null) { - if (rendererAttachment.Sequence != null) rendererAttachment.Sequence.Apply(slot.AppliedPose, rendererAttachment); - AtlasRegion atlasRegion = (AtlasRegion)rendererAttachment.Region; + Sequence sequence = rendererAttachment.Sequence; + int sequenceIndex = sequence.ResolveIndex(slot.AppliedPose); + AtlasRegion atlasRegion = (AtlasRegion)sequence.GetRegion(sequenceIndex); Material material = (Material)atlasRegion.page.rendererObject; if (lastRendererMaterial != material) { if (lastRendererMaterial != null) @@ -399,8 +402,9 @@ namespace Spine.Unity { RegionAttachment regionAttachment = attachment as RegionAttachment; if (regionAttachment != null) { - if (regionAttachment.Sequence != null) regionAttachment.Sequence.Apply(slot.AppliedPose, regionAttachment); - region = regionAttachment.Region; + Sequence sequence = regionAttachment.Sequence; + int sequenceIndex = sequence.ResolveIndex(slot.AppliedPose); + region = sequence.GetRegion(sequenceIndex); #if SPINE_TRIANGLECHECK attachmentVertexCount = 4; attachmentTriangleCount = 6; @@ -408,8 +412,9 @@ namespace Spine.Unity { } else { MeshAttachment meshAttachment = attachment as MeshAttachment; if (meshAttachment != null) { - if (meshAttachment.Sequence != null) meshAttachment.Sequence.Apply(slot.AppliedPose, meshAttachment); - region = meshAttachment.Region; + Sequence sequence = meshAttachment.Sequence; + int sequenceIndex = sequence.ResolveIndex(slot.AppliedPose); + region = sequence.GetRegion(sequenceIndex); #if SPINE_TRIANGLECHECK attachmentVertexCount = meshAttachment.WorldVerticesLength >> 1; attachmentTriangleCount = meshAttachment.Triangles.Length; @@ -620,8 +625,10 @@ namespace Spine.Unity { // Identify and prepare values. RegionAttachment region = attachment as RegionAttachment; if (region != null) { - region.ComputeWorldVertices(slot, workingVerts, 0); - uvs = region.UVs; + Sequence sequence = region.Sequence; + int sequenceIndex = sequence.ResolveIndex(slotPose); + region.ComputeWorldVertices(slot, sequence.GetOffsets(sequenceIndex), workingVerts, 0); + uvs = sequence.GetUVs(sequenceIndex); attachmentTriangleIndices = regionTriangles; regionC = region.GetColor(); attachmentVertexCount = 4; @@ -634,8 +641,10 @@ namespace Spine.Unity { workingVerts = new float[meshVerticesLength]; this.tempVerts = workingVerts; } - mesh.ComputeWorldVertices(skeleton, slot, 0, meshVerticesLength, workingVerts, 0); //meshAttachment.ComputeWorldVertices(slot, tempVerts); - uvs = mesh.UVs; + Sequence sequence = mesh.Sequence; + int sequenceIndex = sequence.ResolveIndex(slotPose); + mesh.ComputeWorldVertices(skeleton, slot, 0, meshVerticesLength, workingVerts, 0); + uvs = sequence.GetUVs(sequenceIndex); attachmentTriangleIndices = mesh.Triangles; regionC = mesh.GetColor(); attachmentVertexCount = meshVerticesLength >> 1; // meshVertexCount / 2; @@ -942,7 +951,10 @@ namespace Spine.Unity { RegionAttachment regionAttachment = attachment as RegionAttachment; if (regionAttachment != null) { - regionAttachment.ComputeWorldVertices(slot, tempVerts, 0); + Sequence sequence = regionAttachment.Sequence; + int sequenceIndex = sequence.ResolveIndex(slotPose); + regionAttachment.ComputeWorldVertices(slot, sequence.GetOffsets(sequenceIndex), tempVerts, 0); + Color regionC = regionAttachment.GetColor(); Color combinedC = skeletonC * slotC * regionC; @@ -978,7 +990,7 @@ namespace Spine.Unity { cbi[vertexIndex] = color; cbi[vertexIndex + 1] = color; cbi[vertexIndex + 2] = color; cbi[vertexIndex + 3] = color; - float[] regionUVs = regionAttachment.UVs; + float[] regionUVs = sequence.GetUVs(sequenceIndex); ubi[vertexIndex] = new Vector2(regionUVs[RegionAttachment.BLX], regionUVs[RegionAttachment.BLY]); ubi[vertexIndex + 1] = new Vector2(regionUVs[RegionAttachment.BRX], regionUVs[RegionAttachment.BRY]); ubi[vertexIndex + 2] = new Vector2(regionUVs[RegionAttachment.ULX], regionUVs[RegionAttachment.ULY]); @@ -1032,7 +1044,9 @@ namespace Spine.Unity { color.b = (byte)(combinedC.b * 255); } - float[] attachmentUVs = meshAttachment.UVs; + Sequence sequence = meshAttachment.Sequence; + int sequenceIndex = sequence.ResolveIndex(slotPose); + float[] attachmentUVs = sequence.GetUVs(sequenceIndex); // Potential first attachment bounds initialization. See conditions in RegionAttachment logic. if (vertexIndex == 0) { diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/TK2D/SpriteCollectionAttachmentLoader.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/TK2D/SpriteCollectionAttachmentLoader.cs index 6b9ed0b76..7a9bea0a1 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/TK2D/SpriteCollectionAttachmentLoader.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Modules/TK2D/SpriteCollectionAttachmentLoader.cs @@ -134,31 +134,13 @@ namespace Spine.Unity.TK2D { } public RegionAttachment NewRegionAttachment (Skin skin, String name, String path, Sequence sequence) { - RegionAttachment attachment = new RegionAttachment(name); - if (sequence != null) - LoadSequence(name, path, sequence); - else { - AtlasRegion region = ProcessSpriteDefinition(path); - if (region == null) - throw new ArgumentException(string.Format("Region not found in atlas: {0} (region attachment: {1})", path, name)); - attachment.Region = region; - attachment.Path = path; - } - return attachment; + LoadSequence(name, path, sequence); + return new RegionAttachment(name, sequence); } public MeshAttachment NewMeshAttachment (Skin skin, String name, String path, Sequence sequence) { - MeshAttachment attachment = new MeshAttachment(name); - if (sequence != null) - LoadSequence(name, path, sequence); - else { - AtlasRegion region = ProcessSpriteDefinition(path); - if (region == null) - throw new ArgumentException(string.Format("Region not found in atlas: {0} (region attachment: {1})", path, name)); - attachment.Region = region; - attachment.Path = path; - } - return attachment; + LoadSequence(name, path, sequence); + return new MeshAttachment(name, sequence); } public BoundingBoxAttachment NewBoundingBoxAttachment (Skin skin, String name) { diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonDataModifierAssets/BlendModeMaterials/BlendModeMaterialsAsset.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonDataModifierAssets/BlendModeMaterials/BlendModeMaterialsAsset.cs index 3e34b7d9f..5239cafb7 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonDataModifierAssets/BlendModeMaterials/BlendModeMaterialsAsset.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/SkeletonDataModifierAssets/BlendModeMaterials/BlendModeMaterialsAsset.cs @@ -77,10 +77,12 @@ namespace Spine.Unity { if (templateMaterial == null) continue; foreach (Skin.SkinEntry entry in entryBuffer) { - IHasTextureRegion renderableAttachment = entry.Attachment as IHasTextureRegion; - if (renderableAttachment != null) { - renderableAttachment.Region = materialCache.CloneAtlasRegionWithMaterial( - (AtlasRegion)renderableAttachment.Region, templateMaterial); + IHasSequence renderableAttachment = entry.Attachment as IHasSequence; + if (renderableAttachment == null) continue; + TextureRegion[] regions = renderableAttachment.Sequence.Regions; + for (int i = 0; i < regions.Length; ++i) { + regions[i] = materialCache.CloneAtlasRegionWithMaterial( + (AtlasRegion)regions[i], templateMaterial); } } } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AtlasUtilities.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AtlasUtilities.cs index 5123317b3..9285fef0f 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AtlasUtilities.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AtlasUtilities.cs @@ -498,7 +498,8 @@ namespace Spine.Unity.AttachmentTools { } originalRegions.Clear(); - if (!object.ReferenceEquals(sourceAttachments, outputAttachments)) { + bool isInPlaceOperation = object.ReferenceEquals(sourceAttachments, outputAttachments); + if (!isInPlaceOperation) { outputAttachments.Clear(); outputAttachments.AddRange(sourceAttachments); } @@ -507,40 +508,22 @@ namespace Spine.Unity.AttachmentTools { for (int attachmentIndex = 0, n = sourceAttachments.Count; attachmentIndex < n; attachmentIndex++) { Attachment originalAttachment = sourceAttachments[attachmentIndex]; - if (originalAttachment is IHasTextureRegion) { - MeshAttachment originalMeshAttachment = originalAttachment as MeshAttachment; - IHasTextureRegion originalTextureAttachment = (IHasTextureRegion)originalAttachment; - - Attachment newAttachment = (originalTextureAttachment.Sequence != null) ? originalAttachment : - (originalMeshAttachment != null) ? originalMeshAttachment.NewLinkedMesh() : - originalAttachment.Copy(); - IHasTextureRegion newTextureAttachment = (IHasTextureRegion)newAttachment; - AtlasRegion region = newTextureAttachment.Region as AtlasRegion; - if (region == null && originalTextureAttachment.Sequence != null) - region = (AtlasRegion)originalTextureAttachment.Sequence.Regions[0]; - + if (originalAttachment is IHasSequence) { + IHasSequence originalTextureAttachment = (IHasSequence)originalAttachment; + Attachment newAttachment = originalAttachment.Copy(); + AtlasRegion firstRegion = (AtlasRegion)originalTextureAttachment.Sequence.Regions[0]; int existingIndex; - if (existingRegions.TryGetValue(region, out existingIndex)) { + if (existingRegions.TryGetValue(firstRegion, out existingIndex)) { regionIndices.Add(existingIndex); } else { - existingRegions.Add(region, newRegionIndex); + existingRegions.Add(firstRegion, newRegionIndex); Sequence originalSequence = originalTextureAttachment.Sequence; - if (originalSequence != null) { - newTextureAttachment.Sequence = new Sequence(originalSequence); - for (int i = 0, regionCount = originalSequence.Regions.Length; i < regionCount; ++i) { - AtlasRegion sequenceRegion = (AtlasRegion)originalSequence.Regions[i]; - AddRegionTexturesToPack(numTextureParamsToRepack, sequenceRegion, - settings.textureFormat, settings.mipmaps, settings.additionalTextureFormats, - settings.additionalTexturePropertyIDsToCopy, settings.additionalTextureIsLinear); - originalRegions.Add(sequenceRegion); - regionIndices.Add(newRegionIndex); - newRegionIndex++; - } - } else { - AddRegionTexturesToPack(numTextureParamsToRepack, region, + for (int i = 0, regionCount = originalSequence.Regions.Length; i < regionCount; ++i) { + AtlasRegion sequenceRegion = (AtlasRegion)originalSequence.Regions[i]; + AddRegionTexturesToPack(numTextureParamsToRepack, sequenceRegion, settings.textureFormat, settings.mipmaps, settings.additionalTextureFormats, settings.additionalTexturePropertyIDsToCopy, settings.additionalTextureIsLinear); - originalRegions.Add(region); + originalRegions.Add(sequenceRegion); regionIndices.Add(newRegionIndex); newRegionIndex++; } @@ -616,32 +599,24 @@ namespace Spine.Unity.AttachmentTools { // Map the cloned attachments to the repacked atlas. for (int attachmentIndex = 0, repackedIndex = 0, n = outputAttachments.Count; - attachmentIndex < n; - ++attachmentIndex, ++repackedIndex) { + attachmentIndex < n; ++attachmentIndex, ++repackedIndex) { Attachment attachment = outputAttachments[attachmentIndex]; - IHasTextureRegion textureAttachment = attachment as IHasTextureRegion; + IHasSequence textureAttachment = attachment as IHasSequence; if (textureAttachment != null) { - if (textureAttachment.Sequence != null) { - TextureRegion[] regions = textureAttachment.Sequence.Regions; - for (int r = 0, regionCount = regions.Length; r < regionCount; ++r) { - TextureRegion originalRegion = regions[r]; - TextureRegion repackedRegion = repackedRegions[regionIndices[repackedIndex++]]; + TextureRegion[] regions = textureAttachment.Sequence.Regions; + for (int r = 0, regionCount = regions.Length; r < regionCount; ++r) { + TextureRegion originalRegion = regions[r]; + TextureRegion repackedRegion = repackedRegions[regionIndices[repackedIndex++]]; + if (enableBlendModes) { AssignBlendMode(ref repackedRegion, originalRegion, normalShader, ref blendModePages, additiveMaterialSource, multiplyMaterialSource, screenMaterialSource); - regions[r] = repackedRegion; } - textureAttachment.Region = regions[0]; - --repackedIndex; - } else { - TextureRegion originalRegion = textureAttachment.Region; - TextureRegion repackedRegion = repackedRegions[regionIndices[repackedIndex]]; - if (enableBlendModes) - AssignBlendMode(ref repackedRegion, originalRegion, normalShader, ref blendModePages, - additiveMaterialSource, multiplyMaterialSource, screenMaterialSource); - textureAttachment.Region = repackedRegion; + regions[r] = repackedRegion; } - textureAttachment.UpdateRegion(); + --repackedIndex; + + textureAttachment.UpdateSequence(); } } @@ -1075,7 +1050,7 @@ namespace Spine.Unity.AttachmentTools { } static bool IsRenderable (Attachment a) { - return a is IHasTextureRegion; + return a is IHasSequence; } /// diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentRegionExtensions.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentRegionExtensions.cs index b86bfb8f3..b895c6880 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentRegionExtensions.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/AttachmentRegionExtensions.cs @@ -74,9 +74,10 @@ namespace Spine.Unity.AttachmentTools { if (region == null) throw new System.ArgumentNullException("region"); // (AtlasAttachmentLoader.cs) - RegionAttachment attachment = new RegionAttachment(attachmentName); + Sequence sequence = new Sequence(1, false); + sequence.Regions[0] = region; + RegionAttachment attachment = new RegionAttachment(attachmentName, sequence); - attachment.Region = region; attachment.Path = region.name; attachment.ScaleX = 1; attachment.ScaleY = 1; @@ -84,15 +85,11 @@ namespace Spine.Unity.AttachmentTools { attachment.SetColor(Color.white); // pass OriginalWidth and OriginalHeight because UpdateOffset uses it in its calculation. - TextureRegion textreRegion = attachment.Region; - AtlasRegion atlasRegion = textreRegion as AtlasRegion; - float originalWidth = atlasRegion != null ? atlasRegion.originalWidth : textreRegion.width; - float originalHeight = atlasRegion != null ? atlasRegion.originalHeight : textreRegion.height; - attachment.Width = originalWidth * scale; - attachment.Height = originalHeight * scale; + attachment.Width = region.originalWidth * scale; + attachment.Height = region.originalHeight * scale; attachment.SetColor(Color.white); - attachment.UpdateRegion(); + attachment.UpdateSequence(); return attachment; } @@ -166,8 +163,10 @@ namespace Spine.Unity.AttachmentTools { float scale = 1f / sprite.pixelsPerUnit; if (useOriginalRegionScale) { RegionAttachment regionAttachment = attachment as RegionAttachment; - if (regionAttachment != null) - scale = regionAttachment.Width / regionAttachment.Region.OriginalWidth; + if (regionAttachment != null) { + var firstRegion = regionAttachment.Sequence.GetRegion(0); + scale = regionAttachment.Width / firstRegion.OriginalWidth; + } } attachment.SetRegion(atlasRegion, useOriginalRegionSize, scale); } @@ -181,17 +180,18 @@ namespace Spine.Unity.AttachmentTools { public static void SetRegion (this Attachment attachment, AtlasRegion atlasRegion, bool useOriginalRegionSize = false, float scale = 0.01f) { RegionAttachment regionAttachment = attachment as RegionAttachment; if (regionAttachment != null) { - regionAttachment.Region = atlasRegion; + + regionAttachment.Sequence.Regions[0] = atlasRegion; if (!useOriginalRegionSize) { regionAttachment.Width = atlasRegion.width * scale; regionAttachment.Height = atlasRegion.height * scale; } - regionAttachment.UpdateRegion(); + regionAttachment.UpdateSequence(); } else { MeshAttachment meshAttachment = attachment as MeshAttachment; if (meshAttachment != null) { - meshAttachment.Region = atlasRegion; - meshAttachment.UpdateRegion(); + meshAttachment.Sequence.Regions[0] = atlasRegion; + meshAttachment.UpdateSequence(); } } } diff --git a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/SkeletonExtensions.cs b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/SkeletonExtensions.cs index deb62c3b7..65ada4075 100644 --- a/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/SkeletonExtensions.cs +++ b/spine-unity/Assets/Spine/Runtime/spine-unity/Utility/SkeletonExtensions.cs @@ -229,9 +229,10 @@ namespace Spine.Unity { #region Attachments public static Material GetMaterial (this Attachment a) { object rendererObject = null; - IHasTextureRegion renderableAttachment = a as IHasTextureRegion; - if (renderableAttachment != null) - rendererObject = renderableAttachment.Region; + IHasSequence renderableAttachment = a as IHasSequence; + if (renderableAttachment != null) { + rendererObject = renderableAttachment.Sequence.Regions[0]; + } if (rendererObject == null) return null; diff --git a/spine-unity/Assets/Spine/package.json b/spine-unity/Assets/Spine/package.json index 139e04bab..b39b5c6ce 100644 --- a/spine-unity/Assets/Spine/package.json +++ b/spine-unity/Assets/Spine/package.json @@ -2,7 +2,7 @@ "name": "com.esotericsoftware.spine.spine-unity", "displayName": "spine-unity Runtime", "description": "This plugin provides the spine-unity runtime core and examples. Spine Examples can be installed via the Samples tab.", - "version": "4.3.53", + "version": "4.3.54", "unity": "2018.3", "author": { "name": "Esoteric Software",