Merge branch '3.6' into 3.7-beta

This commit is contained in:
badlogic 2017-07-31 10:11:41 +02:00
commit cae990f66a
7 changed files with 121 additions and 99 deletions

View File

@ -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);

View File

@ -34,21 +34,21 @@ using System.Collections.Generic;
namespace Spine {
public class AnimationState {
static readonly Animation EmptyAnimation = new Animation("<empty>", new ExposedList<Timeline>(), 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<TrackEntry> tracks = new ExposedList<TrackEntry>();
private readonly HashSet<int> propertyIDs = new HashSet<int>();
private readonly ExposedList<Event> events = new ExposedList<Event>();
private readonly EventQueue queue;
Pool<TrackEntry> trackEntryPool = new Pool<TrackEntry>();
private readonly ExposedList<TrackEntry> tracks = new ExposedList<TrackEntry>();
private readonly ExposedList<Event> events = new ExposedList<Event>();
private readonly EventQueue queue; // Initialized by constructor.
private readonly HashSet<int> propertyIDs = new HashSet<int>();
private readonly ExposedList<TrackEntry> mixingTo = new ExposedList<TrackEntry>();
private bool animationsChanged;
private float timeScale = 1;
Pool<TrackEntry> trackEntryPool = new Pool<TrackEntry>();
public AnimationStateData Data { get { return data; } }
/// <summary>A list of tracks that have animations, which may contain nulls.</summary>
public ExposedList<TrackEntry> 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;
}
/// <summary>
/// Increments the track entry times, setting queued animations as current if needed</summary>
/// <param name="delta">delta time</param>
@ -155,7 +155,6 @@ namespace Spine {
return false;
}
/// <summary>
/// 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.</summary>
@ -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();
}
/// <summary>Sets the active TrackEntry for a given track number.</summary>
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
}
/// <summary>Sets an animation by name. <seealso cref="SetAnimation(int, Animation, bool)" /></summary>
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 {
/// <summary>Queues an animation by name.</summary>
/// <seealso cref="AddAnimation(int, Animation, bool, float)" />
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;
}
/// <summary>Object-pooling version of new TrackEntry. Obtain an unused TrackEntry from the pool and clear/initialize its values.</summary>
/// <param name="last">May be null.</param>
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;
}
/// <summary>Dispose all track entries queued after the given TrackEntry.</summary>
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;
}
/// <summary>Sets the timeline data.</summary>
/// <param name="to">May be null.</param>
internal TrackEntry SetTimelineData (TrackEntry to, ExposedList<TrackEntry> mixingToArray, HashSet<int> 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 ? "<none>" : animation.name;
}
}
class EventQueue {
private readonly List<EventQueueEntry> eventQueueEntries = new List<EventQueueEntry>();
public bool drainDisabled;
internal bool drainDisabled;
private readonly AnimationState state;
private readonly Pool<TrackEntry> trackEntryPool;
public event Action AnimationsChanged;
internal event Action AnimationsChanged;
public EventQueue (AnimationState state, Action HandleAnimationsChanged, Pool<TrackEntry> trackEntryPool) {
internal EventQueue (AnimationState state, Action HandleAnimationsChanged, Pool<TrackEntry> 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 () {
/// <summary>Raises all events in the queue and drains the queue.</summary>
internal void Drain () {
if (drainDisabled) return;
drainDisabled = true;
@ -992,7 +994,7 @@ namespace Spine {
drainDisabled = false;
}
public void Clear () {
internal void Clear () {
eventQueueEntries.Clear();
}
}

View File

@ -43,11 +43,21 @@ using Windows.Storage;
#endif
namespace Spine {
public class Atlas {
public class Atlas : IEnumerable<AtlasRegion> {
readonly List<AtlasPage> pages = new List<AtlasPage>();
List<AtlasRegion> regions = new List<AtlasRegion>();
TextureLoader textureLoader;
#region IEnumerable implementation
public IEnumerator<AtlasRegion> 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);

View File

@ -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<T>.Pop(); https://referencesource.microsoft.com/#mscorlib/system/collections/stack.cs
/// <summary>Pops the last item of the list. If the list is empty, Pop throws an InvalidOperationException.</summary>
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) {

View File

@ -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;

View File

@ -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
{