diff --git a/spine-cocos2dx/src/spine/SkeletonRenderer.cpp b/spine-cocos2dx/src/spine/SkeletonRenderer.cpp index e3035e23e..bc6c8cca4 100644 --- a/spine-cocos2dx/src/spine/SkeletonRenderer.cpp +++ b/spine-cocos2dx/src/spine/SkeletonRenderer.cpp @@ -282,8 +282,10 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t color.a *= nodeColor.a * _skeleton->color.a * slot->color.a * 255; // skip rendering if the color of this attachment is 0 - if (color.a == 0) + if (color.a == 0){ + spSkeletonClipping_clipEnd(_clipper, slot); continue; + } float multiplier = _premultipliedAlpha ? color.a : 255; color.r *= nodeColor.r * _skeleton->color.r * slot->color.r * multiplier; color.g *= nodeColor.g * _skeleton->color.g * slot->color.g * multiplier; @@ -313,8 +315,10 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t spSkeletonClipping_clipTriangles(_clipper, (float*)&triangles.verts[0].vertices, triangles.vertCount * sizeof(cocos2d::V3F_C4B_T2F) / 4, triangles.indices, triangles.indexCount, (float*)&triangles.verts[0].texCoords, 6); batch->deallocateVertices(triangles.vertCount); - if (_clipper->clippedTriangles->size == 0) + if (_clipper->clippedTriangles->size == 0){ + spSkeletonClipping_clipEnd(_clipper, slot); continue; + } triangles.vertCount = _clipper->clippedVertices->size >> 1; triangles.verts = batch->allocateVertices(triangles.vertCount); @@ -397,8 +401,10 @@ void SkeletonRenderer::draw (Renderer* renderer, const Mat4& transform, uint32_t spSkeletonClipping_clipTriangles(_clipper, (float*)&trianglesTwoColor.verts[0].position, trianglesTwoColor.vertCount * sizeof(V3F_C4B_C4B_T2F) / 4, trianglesTwoColor.indices, trianglesTwoColor.indexCount, (float*)&trianglesTwoColor.verts[0].texCoords, 7); twoColorBatch->deallocateVertices(trianglesTwoColor.vertCount); - if (_clipper->clippedTriangles->size == 0) + if (_clipper->clippedTriangles->size == 0){ + spSkeletonClipping_clipEnd(_clipper, slot); continue; + } trianglesTwoColor.vertCount = _clipper->clippedVertices->size >> 1; trianglesTwoColor.verts = twoColorBatch->allocateVertices(trianglesTwoColor.vertCount); diff --git a/spine-csharp/src/AnimationState.cs b/spine-csharp/src/AnimationState.cs index 770fc91e7..2f7a47bc2 100644 --- a/spine-csharp/src/AnimationState.cs +++ b/spine-csharp/src/AnimationState.cs @@ -34,21 +34,21 @@ using System.Collections.Generic; namespace Spine { public class AnimationState { static readonly Animation EmptyAnimation = new Animation("", new ExposedList(), 0); - internal const int SUBSEQUENT = 0, FIRST = 1, DIP = 2, DIP_MIX = 3; + internal const int Subsequent = 0, First = 1, Dip = 2, DipMix = 3; private AnimationStateData data; - private readonly ExposedList tracks = new ExposedList(); - private readonly HashSet propertyIDs = new HashSet(); - private readonly ExposedList events = new ExposedList(); - private readonly EventQueue queue; + Pool trackEntryPool = new Pool(); + private readonly ExposedList tracks = new ExposedList(); + private readonly ExposedList events = new ExposedList(); + private readonly EventQueue queue; // Initialized by constructor. + + private readonly HashSet propertyIDs = new HashSet(); private readonly ExposedList mixingTo = new ExposedList(); private bool animationsChanged; private float timeScale = 1; - Pool trackEntryPool = new Pool(); - public AnimationStateData Data { get { return data; } } /// A list of tracks that have animations, which may contain nulls. public ExposedList Tracks { get { return tracks; } } @@ -63,13 +63,13 @@ namespace Spine { public AnimationState (AnimationStateData data) { if (data == null) throw new ArgumentNullException("data", "data cannot be null."); this.data = data; - this.queue = new EventQueue(this, HandleAnimationsChanged, trackEntryPool); + this.queue = new EventQueue( + this, + delegate { this.animationsChanged = true; }, + trackEntryPool + ); } - - void HandleAnimationsChanged () { - this.animationsChanged = true; - } - + /// /// Increments the track entry times, setting queued animations as current if needed /// delta time @@ -155,7 +155,6 @@ namespace Spine { return false; } - /// /// Poses the skeleton using the track entry animations. There are no side effects other than invoking listeners, so the /// animation state can be applied to multiple skeletons to pose them identically. @@ -197,7 +196,7 @@ namespace Spine { for (int ii = 0; ii < timelineCount; ii++) { Timeline timeline = timelinesItems[ii]; - MixPose pose = timelineData[ii] >= FIRST ? MixPose.Setup : currentPose; + MixPose pose = timelineData[ii] >= AnimationState.First ? MixPose.Setup : currentPose; var rotateTimeline = timeline as RotateTimeline; if (rotateTimeline != null) ApplyRotateTimeline(rotateTimeline, skeleton, animationTime, mix, pose, timelinesRotation, ii << 1, firstFrame); @@ -246,17 +245,17 @@ namespace Spine { for (int i = 0; i < timelineCount; i++) { Timeline timeline = timelinesItems[i]; switch (timelineData[i]) { - case SUBSEQUENT: + case Subsequent: if (!attachments && timeline is AttachmentTimeline) continue; if (!drawOrder && timeline is DrawOrderTimeline) continue; pose = currentPose; alpha = alphaMix; break; - case FIRST: + case First: pose = MixPose.Setup; alpha = alphaMix; break; - case DIP: + case Dip: pose = MixPose.Setup; alpha = alphaDip; break; @@ -421,6 +420,7 @@ namespace Spine { queue.Drain(); } + /// Sets the active TrackEntry for a given track number. private void SetCurrent (int index, TrackEntry current, bool interrupt) { TrackEntry from = ExpandToIndex(index); tracks.Items[index] = current; @@ -437,12 +437,12 @@ namespace Spine { from.timelinesRotation.Clear(); // Reset rotation for mixing out, in case entry was mixed in. } - queue.Start(current); + queue.Start(current); // triggers AnimationsChanged } /// Sets an animation by name. - public TrackEntry SetAnimation (int trackIndex, String animationName, bool loop) { + public TrackEntry SetAnimation (int trackIndex, string animationName, bool loop) { Animation animation = data.skeletonData.FindAnimation(animationName); if (animation == null) throw new ArgumentException("Animation not found: " + animationName, "animationName"); return SetAnimation(trackIndex, animation, loop); @@ -480,7 +480,7 @@ namespace Spine { /// Queues an animation by name. /// - public TrackEntry AddAnimation (int trackIndex, String animationName, bool loop, float delay) { + public TrackEntry AddAnimation (int trackIndex, string animationName, bool loop, float delay) { Animation animation = data.skeletonData.FindAnimation(animationName); if (animation == null) throw new ArgumentException("Animation not found: " + animationName, "animationName"); return AddAnimation(trackIndex, animation, loop, delay); @@ -570,6 +570,7 @@ namespace Spine { return null; } + /// Object-pooling version of new TrackEntry. Obtain an unused TrackEntry from the pool and clear/initialize its values. /// May be null. private TrackEntry NewTrackEntry (int trackIndex, Animation animation, bool loop, TrackEntry last) { TrackEntry entry = trackEntryPool.Obtain(); // Pooling @@ -589,7 +590,7 @@ namespace Spine { entry.delay = 0; entry.trackTime = 0; entry.trackLast = -1; - entry.nextTrackLast = -1; + entry.nextTrackLast = -1; // nextTrackLast == -1 signifies a TrackEntry that wasn't applied yet. entry.trackEnd = float.MaxValue; // loop ? float.MaxValue : animation.Duration; entry.timeScale = 1; @@ -600,6 +601,7 @@ namespace Spine { return entry; } + /// Dispose all track entries queued after the given TrackEntry. private void DisposeNext (TrackEntry entry) { TrackEntry next = entry.next; while (next != null) { @@ -628,7 +630,7 @@ namespace Spine { return (trackIndex >= tracks.Count) ? null : tracks.Items[trackIndex]; } - override public String ToString () { + override public string ToString () { var buffer = new System.Text.StringBuilder(); for (int i = 0, n = tracks.Count; i < n; i++) { TrackEntry entry = tracks.Items[i]; @@ -680,11 +682,12 @@ namespace Spine { Event = null; } + /// Sets the timeline data. /// May be null. internal TrackEntry SetTimelineData (TrackEntry to, ExposedList mixingToArray, HashSet propertyIDs) { if (to != null) mixingToArray.Add(to); var lastEntry = mixingFrom != null ? mixingFrom.SetTimelineData(this, mixingToArray, propertyIDs) : this; - if (to != null) mixingToArray.RemoveAt(mixingToArray.Count - 1); // mixingToArray.pop(); + if (to != null) mixingToArray.Pop(); var mixingTo = mixingToArray.Items; int mixingToLast = mixingToArray.Count - 1; @@ -698,21 +701,19 @@ namespace Spine { for (int i = 0; i < timelinesCount; i++) { int id = timelines[i].PropertyId; if (!propertyIDs.Add(id)) { - timelineDataItems[i] = AnimationState.SUBSEQUENT; + timelineDataItems[i] = AnimationState.Subsequent; } else if (to == null || !to.HasTimeline(id)) { - timelineDataItems[i] = AnimationState.FIRST; + timelineDataItems[i] = AnimationState.First; } else { for (int ii = mixingToLast; ii >= 0; ii--) { var entry = mixingTo[ii]; - if (!entry.HasTimeline(id)) { - if (entry.mixDuration > 0) { - timelineDataItems[i] = AnimationState.DIP_MIX; - timelineDipMixItems[i] = entry; - goto outer; // continue outer; - } + if (entry.mixDuration > 0 && !entry.HasTimeline(id)) { + timelineDataItems[i] = AnimationState.DipMix; + timelineDipMixItems[i] = entry; + goto outer; // continue outer; } } - timelineDataItems[i] = AnimationState.DIP; + timelineDataItems[i] = AnimationState.Dip; } outer: {} } @@ -886,20 +887,20 @@ namespace Spine { timelinesRotation.Clear(); } - override public String ToString () { + override public string ToString () { return animation == null ? "" : animation.name; } } class EventQueue { private readonly List eventQueueEntries = new List(); - public bool drainDisabled; + internal bool drainDisabled; private readonly AnimationState state; private readonly Pool trackEntryPool; - public event Action AnimationsChanged; + internal event Action AnimationsChanged; - public EventQueue (AnimationState state, Action HandleAnimationsChanged, Pool trackEntryPool) { + internal EventQueue (AnimationState state, Action HandleAnimationsChanged, Pool trackEntryPool) { this.state = state; this.AnimationsChanged += HandleAnimationsChanged; this.trackEntryPool = trackEntryPool; @@ -921,33 +922,34 @@ namespace Spine { Start, Interrupt, End, Dispose, Complete, Event } - public void Start (TrackEntry entry) { + internal void Start (TrackEntry entry) { eventQueueEntries.Add(new EventQueueEntry(EventType.Start, entry)); if (AnimationsChanged != null) AnimationsChanged(); } - public void Interrupt (TrackEntry entry) { + internal void Interrupt (TrackEntry entry) { eventQueueEntries.Add(new EventQueueEntry(EventType.Interrupt, entry)); } - public void End (TrackEntry entry) { + internal void End (TrackEntry entry) { eventQueueEntries.Add(new EventQueueEntry(EventType.End, entry)); if (AnimationsChanged != null) AnimationsChanged(); } - public void Dispose (TrackEntry entry) { + internal void Dispose (TrackEntry entry) { eventQueueEntries.Add(new EventQueueEntry(EventType.Dispose, entry)); } - public void Complete (TrackEntry entry) { + internal void Complete (TrackEntry entry) { eventQueueEntries.Add(new EventQueueEntry(EventType.Complete, entry)); } - public void Event (TrackEntry entry, Event e) { + internal void Event (TrackEntry entry, Event e) { eventQueueEntries.Add(new EventQueueEntry(EventType.Event, entry, e)); } - public void Drain () { + /// Raises all events in the queue and drains the queue. + internal void Drain () { if (drainDisabled) return; drainDisabled = true; @@ -992,7 +994,7 @@ namespace Spine { drainDisabled = false; } - public void Clear () { + internal void Clear () { eventQueueEntries.Clear(); } } diff --git a/spine-csharp/src/Atlas.cs b/spine-csharp/src/Atlas.cs index 04f2c5755..b58897153 100644 --- a/spine-csharp/src/Atlas.cs +++ b/spine-csharp/src/Atlas.cs @@ -43,11 +43,21 @@ using Windows.Storage; #endif namespace Spine { - public class Atlas { + public class Atlas : IEnumerable { readonly List pages = new List(); List regions = new List(); TextureLoader textureLoader; + #region IEnumerable implementation + public IEnumerator GetEnumerator () { + return regions.GetEnumerator(); + } + + System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator () { + return regions.GetEnumerator(); + } + #endregion + #if !(IS_UNITY) #if WINDOWS_STOREAPP private async Task ReadFile(string path, TextureLoader textureLoader) { @@ -99,7 +109,7 @@ namespace Spine { } private void Load (TextReader reader, string imagesDir, TextureLoader textureLoader) { - if (textureLoader == null) throw new ArgumentNullException("textureLoader cannot be null."); + if (textureLoader == null) throw new ArgumentNullException("textureLoader", "textureLoader cannot be null."); this.textureLoader = textureLoader; string[] tuple = new string[4]; @@ -168,11 +178,11 @@ namespace Spine { region.height = Math.Abs(height); if (ReadTuple(reader, tuple) == 4) { // split is optional - region.splits = new int[] {int.Parse(tuple[0]), int.Parse(tuple[1]), + region.splits = new [] {int.Parse(tuple[0]), int.Parse(tuple[1]), int.Parse(tuple[2]), int.Parse(tuple[3])}; if (ReadTuple(reader, tuple) == 4) { // pad is optional, but only present with splits - region.pads = new int[] {int.Parse(tuple[0]), int.Parse(tuple[1]), + region.pads = new [] {int.Parse(tuple[0]), int.Parse(tuple[1]), int.Parse(tuple[2]), int.Parse(tuple[3])}; ReadTuple(reader, tuple); diff --git a/spine-csharp/src/ExposedList.cs b/spine-csharp/src/ExposedList.cs index 421c6a2c3..c2c7de4d9 100644 --- a/spine-csharp/src/ExposedList.cs +++ b/spine-csharp/src/ExposedList.cs @@ -104,14 +104,14 @@ namespace Spine { } } - private void CheckRange (int idx, int count) { - if (idx < 0) + private void CheckRange (int index, int count) { + if (index < 0) throw new ArgumentOutOfRangeException("index"); if (count < 0) throw new ArgumentOutOfRangeException("count"); - if ((uint)idx + (uint)count > (uint)Count) + if ((uint)index + (uint)count > (uint)Count) throw new ArgumentException("index and count exceed length of list"); } @@ -450,6 +450,21 @@ namespace Spine { version++; } + // Spine Added Method + // Based on Stack.Pop(); https://referencesource.microsoft.com/#mscorlib/system/collections/stack.cs + /// Pops the last item of the list. If the list is empty, Pop throws an InvalidOperationException. + public T Pop () { + if (Count == 0) + throw new InvalidOperationException("List is empty. Nothing to pop."); + + int i = Count - 1; + T item = Items[i]; + Items[i] = default(T); + Count--; + version++; + return item; + } + public void RemoveRange (int index, int count) { CheckRange(index, count); if (count > 0) { diff --git a/spine-starling/spine-starling-example/lib/spine-starling.swc b/spine-starling/spine-starling-example/lib/spine-starling.swc index 0774a336f..91ad4b906 100644 Binary files a/spine-starling/spine-starling-example/lib/spine-starling.swc and b/spine-starling/spine-starling-example/lib/spine-starling.swc differ diff --git a/spine-starling/spine-starling/src/spine/starling/StarlingAtlasAttachmentLoader.as b/spine-starling/spine-starling/src/spine/starling/StarlingAtlasAttachmentLoader.as index 7c6543381..62467744e 100644 --- a/spine-starling/spine-starling/src/spine/starling/StarlingAtlasAttachmentLoader.as +++ b/spine-starling/spine-starling/src/spine/starling/StarlingAtlasAttachmentLoader.as @@ -50,7 +50,6 @@ package spine.starling { public function StarlingAtlasAttachmentLoader(atlas : TextureAtlas) { this.atlas = atlas; - Bone.yDown = true; } @@ -59,11 +58,11 @@ package spine.starling { } public function newRegionAttachment(skin : Skin, name : String, path : String) : RegionAttachment { - var texture : Texture = getTexture(path); + var texture : SubTexture = getTexture(path) as SubTexture; if (texture == null) throw new Error("Region not found in Starling atlas: " + path + " (region attachment: " + name + ")"); var attachment : RegionAttachment = new RegionAttachment(name); - var rotated : Boolean = atlas.getRotation(path); + var rotated : Boolean = texture.rotated; attachment.rendererObject = new Image(Texture.fromTexture(texture)); // Discard frame. var frame : Rectangle = texture.frame; attachment.regionOffsetX = frame ? -frame.x : 0; @@ -79,59 +78,44 @@ package spine.starling { tmp = attachment.regionWidth; attachment.regionWidth = attachment.regionHeight; attachment.regionHeight = tmp; + attachment["regionU2"] = 0; + attachment["regionV2"] = 1; + attachment["regionU"] = 1; + attachment["regionV"] = 0; + }else{ + attachment["regionU"] = 0; + attachment["regionV"] = 0; + attachment["regionU2"] = 1; + attachment["regionV2"] = 1; } - if (!rotated) { - attachment["regionU"] = 0; - attachment["regionV"] = 0; - attachment["regionU2"] = 1; - attachment["regionV2"] = 1; - } else { - attachment["regionU2"] = 0; - attachment["regionV2"] = 1; - attachment["regionU"] = 1; - attachment["regionV"] = 0; - } - attachment.setUVs(attachment["regionU"], attachment["regionV"], attachment["regionU2"], attachment["regionV2"], atlas.getRotation(path)); + attachment.setUVs(attachment["regionU"], attachment["regionV"], attachment["regionU2"], attachment["regionV2"], rotated); return attachment; } public function newMeshAttachment(skin : Skin, name : String, path : String) : MeshAttachment { - var texture : Texture = getTexture(path); + var texture : SubTexture = getTexture(path) as SubTexture; if (texture == null) throw new Error("Region not found in Starling atlas: " + path + " (mesh attachment: " + name + ")"); - var rotated : Boolean = atlas.getRotation(path); + var rotated : Boolean = texture.rotated; var attachment : MeshAttachment = new MeshAttachment(name); attachment.regionRotate = rotated; attachment.rendererObject = new Image(Texture.fromTexture(texture)); // Discard frame. - var subTexture : SubTexture = texture as SubTexture; - if (subTexture) { - var root : Texture = subTexture.root; - var rectRegion : Rectangle = atlas.getRegion(path); - if (!rotated) { - attachment.regionU = rectRegion.x / root.width; - attachment.regionV = rectRegion.y / root.height; - attachment.regionU2 = (rectRegion.x + subTexture.width) / root.width; - attachment.regionV2 = (rectRegion.y + subTexture.height) / root.height; - } else { - attachment.regionU2 = rectRegion.x / root.width; - attachment.regionV2 = rectRegion.y / root.height; - attachment.regionU = (rectRegion.x + subTexture.height) / root.width; - attachment.regionV = (rectRegion.y + subTexture.width) / root.height; - } - attachment.rendererObject = new Image(root); + + var root : Texture = texture.root; + var rectRegion : Rectangle = atlas.getRegion(path); + if (!rotated) { + attachment.regionU = rectRegion.x / root.width; + attachment.regionV = rectRegion.y / root.height; + attachment.regionU2 = (rectRegion.x + texture.width) / root.width; + attachment.regionV2 = (rectRegion.y + texture.height) / root.height; } else { - if (!rotated) { - attachment.regionU = 0; - attachment.regionV = 1; - attachment.regionU2 = 1; - attachment.regionV2 = 0; - } else { - attachment.regionU2 = 0; - attachment.regionV2 = 1; - attachment.regionU = 1; - attachment.regionV = 0; - } + attachment.regionU2 = rectRegion.x / root.width; + attachment.regionV2 = rectRegion.y / root.height; + attachment.regionU = (rectRegion.x + texture.height) / root.width; + attachment.regionV = (rectRegion.y + texture.width) / root.height; } + attachment.rendererObject = new Image(root); + var frame : Rectangle = texture.frame; attachment.regionOffsetX = frame ? -frame.x : 0; attachment.regionOffsetY = frame ? -frame.y : 0; diff --git a/spine-unity/Assets/spine-unity/SkeletonAnimator.cs b/spine-unity/Assets/spine-unity/SkeletonAnimator.cs index 7d76b28ac..0337eedc4 100644 --- a/spine-unity/Assets/spine-unity/SkeletonAnimator.cs +++ b/spine-unity/Assets/spine-unity/SkeletonAnimator.cs @@ -75,7 +75,12 @@ namespace Spine.Unity { public void Update () { if (!valid) return; + #if UNITY_EDITOR + if (Application.isPlaying) + translator.Apply(skeleton); + #else translator.Apply(skeleton); + #endif // UpdateWorldTransform and Bone Callbacks {