Merge pull request #375 from LostPolygon/optimizations

A bunch of optimizations
This commit is contained in:
Fenrisul 2015-07-08 23:18:06 -07:00
commit 054e303d2e
24 changed files with 1215 additions and 338 deletions

View File

@ -34,15 +34,15 @@ using System.Collections.Generic;
namespace Spine { namespace Spine {
public class Animation { public class Animation {
internal List<Timeline> timelines; internal ExposedList<Timeline> timelines;
internal float duration; internal float duration;
internal String name; internal String name;
public String Name { get { return name; } } public String Name { get { return name; } }
public List<Timeline> Timelines { get { return timelines; } set { timelines = value; } } public ExposedList<Timeline> Timelines { get { return timelines; } set { timelines = value; } }
public float Duration { get { return duration; } set { duration = value; } } public float Duration { get { return duration; } set { duration = value; } }
public Animation (String name, List<Timeline> timelines, float duration) { public Animation (String name, ExposedList<Timeline> timelines, float duration) {
if (name == null) throw new ArgumentNullException("name cannot be null."); if (name == null) throw new ArgumentNullException("name cannot be null.");
if (timelines == null) throw new ArgumentNullException("timelines cannot be null."); if (timelines == null) throw new ArgumentNullException("timelines cannot be null.");
this.name = name; this.name = name;
@ -53,7 +53,7 @@ namespace Spine {
/// <summary>Poses the skeleton at the specified time for this animation.</summary> /// <summary>Poses the skeleton at the specified time for this animation.</summary>
/// <param name="lastTime">The last time the animation was applied.</param> /// <param name="lastTime">The last time the animation was applied.</param>
/// <param name="events">Any triggered events are added.</param> /// <param name="events">Any triggered events are added.</param>
public void Apply (Skeleton skeleton, float lastTime, float time, bool loop, List<Event> events) { public void Apply (Skeleton skeleton, float lastTime, float time, bool loop, ExposedList<Event> events) {
if (skeleton == null) throw new ArgumentNullException("skeleton cannot be null."); if (skeleton == null) throw new ArgumentNullException("skeleton cannot be null.");
if (loop && duration != 0) { if (loop && duration != 0) {
@ -61,16 +61,16 @@ namespace Spine {
lastTime %= duration; lastTime %= duration;
} }
List<Timeline> timelines = this.timelines; ExposedList<Timeline> timelines = this.timelines;
for (int i = 0, n = timelines.Count; i < n; i++) for (int i = 0, n = timelines.Count; i < n; i++)
timelines[i].Apply(skeleton, lastTime, time, events, 1); timelines.Items[i].Apply(skeleton, lastTime, time, events, 1);
} }
/// <summary>Poses the skeleton at the specified time for this animation mixed with the current pose.</summary> /// <summary>Poses the skeleton at the specified time for this animation mixed with the current pose.</summary>
/// <param name="lastTime">The last time the animation was applied.</param> /// <param name="lastTime">The last time the animation was applied.</param>
/// <param name="events">Any triggered events are added.</param> /// <param name="events">Any triggered events are added.</param>
/// <param name="alpha">The amount of this animation that affects the current pose.</param> /// <param name="alpha">The amount of this animation that affects the current pose.</param>
public void Mix (Skeleton skeleton, float lastTime, float time, bool loop, List<Event> events, float alpha) { public void Mix (Skeleton skeleton, float lastTime, float time, bool loop, ExposedList<Event> events, float alpha) {
if (skeleton == null) throw new ArgumentNullException("skeleton cannot be null."); if (skeleton == null) throw new ArgumentNullException("skeleton cannot be null.");
if (loop && duration != 0) { if (loop && duration != 0) {
@ -78,9 +78,9 @@ namespace Spine {
lastTime %= duration; lastTime %= duration;
} }
List<Timeline> timelines = this.timelines; ExposedList<Timeline> timelines = this.timelines;
for (int i = 0, n = timelines.Count; i < n; i++) for (int i = 0, n = timelines.Count; i < n; i++)
timelines[i].Apply(skeleton, lastTime, time, events, alpha); timelines.Items[i].Apply(skeleton, lastTime, time, events, alpha);
} }
/// <param name="target">After the first and before the last entry.</param> /// <param name="target">After the first and before the last entry.</param>
@ -125,7 +125,7 @@ namespace Spine {
public interface Timeline { public interface Timeline {
/// <summary>Sets the value(s) for the specified time.</summary> /// <summary>Sets the value(s) for the specified time.</summary>
/// <param name="events">May be null to not collect fired events.</param> /// <param name="events">May be null to not collect fired events.</param>
void Apply (Skeleton skeleton, float lastTime, float time, List<Event> events, float alpha); void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> events, float alpha);
} }
/// <summary>Base class for frames that use an interpolation bezier curve.</summary> /// <summary>Base class for frames that use an interpolation bezier curve.</summary>
@ -140,7 +140,7 @@ namespace Spine {
curves = new float[(frameCount - 1) * BEZIER_SIZE]; curves = new float[(frameCount - 1) * BEZIER_SIZE];
} }
abstract public void Apply (Skeleton skeleton, float lastTime, float time, List<Event> firedEvents, float alpha); abstract public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha);
public void SetLinear (int frameIndex) { public void SetLinear (int frameIndex) {
curves[frameIndex * BEZIER_SIZE] = LINEAR; curves[frameIndex * BEZIER_SIZE] = LINEAR;
@ -230,11 +230,11 @@ namespace Spine {
frames[frameIndex + 1] = angle; frames[frameIndex + 1] = angle;
} }
override public void Apply (Skeleton skeleton, float lastTime, float time, List<Event> firedEvents, float alpha) { override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha) {
float[] frames = this.frames; float[] frames = this.frames;
if (time < frames[0]) return; // Time is before first frame. if (time < frames[0]) return; // Time is before first frame.
Bone bone = skeleton.bones[boneIndex]; Bone bone = skeleton.bones.Items[boneIndex];
float amount; float amount;
@ -293,11 +293,11 @@ namespace Spine {
frames[frameIndex + 2] = y; frames[frameIndex + 2] = y;
} }
override public void Apply (Skeleton skeleton, float lastTime, float time, List<Event> firedEvents, float alpha) { override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha) {
float[] frames = this.frames; float[] frames = this.frames;
if (time < frames[0]) return; // Time is before first frame. if (time < frames[0]) return; // Time is before first frame.
Bone bone = skeleton.bones[boneIndex]; Bone bone = skeleton.bones.Items[boneIndex];
if (time >= frames[frames.Length - 3]) { // Time is after last frame. if (time >= frames[frames.Length - 3]) { // Time is after last frame.
bone.x += (bone.data.x + frames[frames.Length - 2] - bone.x) * alpha; bone.x += (bone.data.x + frames[frames.Length - 2] - bone.x) * alpha;
@ -323,11 +323,11 @@ namespace Spine {
: base(frameCount) { : base(frameCount) {
} }
override public void Apply (Skeleton skeleton, float lastTime, float time, List<Event> firedEvents, float alpha) { override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha) {
float[] frames = this.frames; float[] frames = this.frames;
if (time < frames[0]) return; // Time is before first frame. if (time < frames[0]) return; // Time is before first frame.
Bone bone = skeleton.bones[boneIndex]; Bone bone = skeleton.bones.Items[boneIndex];
if (time >= frames[frames.Length - 3]) { // Time is after last frame. if (time >= frames[frames.Length - 3]) { // Time is after last frame.
bone.scaleX += (bone.data.scaleX * frames[frames.Length - 2] - bone.scaleX) * alpha; bone.scaleX += (bone.data.scaleX * frames[frames.Length - 2] - bone.scaleX) * alpha;
bone.scaleY += (bone.data.scaleY * frames[frames.Length - 1] - bone.scaleY) * alpha; bone.scaleY += (bone.data.scaleY * frames[frames.Length - 1] - bone.scaleY) * alpha;
@ -375,7 +375,7 @@ namespace Spine {
frames[frameIndex + 4] = a; frames[frameIndex + 4] = a;
} }
override public void Apply (Skeleton skeleton, float lastTime, float time, List<Event> firedEvents, float alpha) { override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha) {
float[] frames = this.frames; float[] frames = this.frames;
if (time < frames[0]) return; // Time is before first frame. if (time < frames[0]) return; // Time is before first frame.
@ -403,7 +403,7 @@ namespace Spine {
b = prevFrameB + (frames[frameIndex + FRAME_B] - prevFrameB) * percent; b = prevFrameB + (frames[frameIndex + FRAME_B] - prevFrameB) * percent;
a = prevFrameA + (frames[frameIndex + FRAME_A] - prevFrameA) * percent; a = prevFrameA + (frames[frameIndex + FRAME_A] - prevFrameA) * percent;
} }
Slot slot = skeleton.slots[slotIndex]; Slot slot = skeleton.slots.Items[slotIndex];
if (alpha < 1) { if (alpha < 1) {
slot.r += (r - slot.r) * alpha; slot.r += (r - slot.r) * alpha;
slot.g += (g - slot.g) * alpha; slot.g += (g - slot.g) * alpha;
@ -439,7 +439,7 @@ namespace Spine {
attachmentNames[frameIndex] = attachmentName; attachmentNames[frameIndex] = attachmentName;
} }
public void Apply (Skeleton skeleton, float lastTime, float time, List<Event> firedEvents, float alpha) { public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha) {
float[] frames = this.frames; float[] frames = this.frames;
if (time < frames[0]) { if (time < frames[0]) {
if (lastTime > time) Apply(skeleton, lastTime, int.MaxValue, null, 0); if (lastTime > time) Apply(skeleton, lastTime, int.MaxValue, null, 0);
@ -451,7 +451,7 @@ namespace Spine {
if (frames[frameIndex] < lastTime) return; if (frames[frameIndex] < lastTime) return;
String attachmentName = attachmentNames[frameIndex]; String attachmentName = attachmentNames[frameIndex];
skeleton.slots[slotIndex].Attachment = skeleton.slots.Items[slotIndex].Attachment =
attachmentName == null ? null : skeleton.GetAttachment(slotIndex, attachmentName); attachmentName == null ? null : skeleton.GetAttachment(slotIndex, attachmentName);
} }
} }
@ -476,7 +476,7 @@ namespace Spine {
} }
/// <summary>Fires events for frames > lastTime and <= time.</summary> /// <summary>Fires events for frames > lastTime and <= time.</summary>
public void Apply (Skeleton skeleton, float lastTime, float time, List<Event> firedEvents, float alpha) { public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha) {
if (firedEvents == null) return; if (firedEvents == null) return;
float[] frames = this.frames; float[] frames = this.frames;
int frameCount = frames.Length; int frameCount = frames.Length;
@ -524,7 +524,7 @@ namespace Spine {
drawOrders[frameIndex] = drawOrder; drawOrders[frameIndex] = drawOrder;
} }
public void Apply (Skeleton skeleton, float lastTime, float time, List<Event> firedEvents, float alpha) { public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha) {
float[] frames = this.frames; float[] frames = this.frames;
if (time < frames[0]) return; // Time is before first frame. if (time < frames[0]) return; // Time is before first frame.
@ -534,15 +534,16 @@ namespace Spine {
else else
frameIndex = Animation.binarySearch(frames, time) - 1; frameIndex = Animation.binarySearch(frames, time) - 1;
List<Slot> drawOrder = skeleton.drawOrder; ExposedList<Slot> drawOrder = skeleton.drawOrder;
List<Slot> slots = skeleton.slots; ExposedList<Slot> slots = skeleton.slots;
int[] drawOrderToSetupIndex = drawOrders[frameIndex]; int[] drawOrderToSetupIndex = drawOrders[frameIndex];
if (drawOrderToSetupIndex == null) { if (drawOrderToSetupIndex == null) {
drawOrder.Clear(); drawOrder.Clear();
drawOrder.AddRange(slots); for (int i = 0, n = slots.Count; i < n; i++)
drawOrder.Add(slots.Items[i]);
} else { } else {
for (int i = 0, n = drawOrderToSetupIndex.Length; i < n; i++) for (int i = 0, n = drawOrderToSetupIndex.Length; i < n; i++)
drawOrder[i] = slots[drawOrderToSetupIndex[i]]; drawOrder.Items[i] = slots.Items[drawOrderToSetupIndex[i]];
} }
} }
} }
@ -570,8 +571,8 @@ namespace Spine {
frameVertices[frameIndex] = vertices; frameVertices[frameIndex] = vertices;
} }
override public void Apply (Skeleton skeleton, float lastTime, float time, List<Event> firedEvents, float alpha) { override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha) {
Slot slot = skeleton.slots[slotIndex]; Slot slot = skeleton.slots.Items[slotIndex];
if (slot.attachment != attachment) return; if (slot.attachment != attachment) return;
float[] frames = this.frames; float[] frames = this.frames;
@ -649,11 +650,11 @@ namespace Spine {
frames[frameIndex + 2] = bendDirection; frames[frameIndex + 2] = bendDirection;
} }
override public void Apply (Skeleton skeleton, float lastTime, float time, List<Event> firedEvents, float alpha) { override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha) {
float[] frames = this.frames; float[] frames = this.frames;
if (time < frames[0]) return; // Time is before first frame. if (time < frames[0]) return; // Time is before first frame.
IkConstraint ikConstraint = skeleton.ikConstraints[ikConstraintIndex]; IkConstraint ikConstraint = skeleton.ikConstraints.Items[ikConstraintIndex];
if (time >= frames[frames.Length - 3]) { // Time is after last frame. if (time >= frames[frames.Length - 3]) { // Time is after last frame.
ikConstraint.mix += (frames[frames.Length - 2] - ikConstraint.mix) * alpha; ikConstraint.mix += (frames[frames.Length - 2] - ikConstraint.mix) * alpha;
@ -693,7 +694,7 @@ namespace Spine {
frames[frameIndex + 1] = flip ? 1 : 0; frames[frameIndex + 1] = flip ? 1 : 0;
} }
public void Apply (Skeleton skeleton, float lastTime, float time, List<Event> firedEvents, float alpha) { public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha) {
float[] frames = this.frames; float[] frames = this.frames;
if (time < frames[0]) { if (time < frames[0]) {
if (lastTime > time) Apply(skeleton, lastTime, int.MaxValue, null, 0); if (lastTime > time) Apply(skeleton, lastTime, int.MaxValue, null, 0);
@ -704,7 +705,7 @@ namespace Spine {
int frameIndex = (time >= frames[frames.Length - 2] ? frames.Length : Animation.binarySearch(frames, time, 2)) - 2; int frameIndex = (time >= frames[frames.Length - 2] ? frames.Length : Animation.binarySearch(frames, time, 2)) - 2;
if (frames[frameIndex] < lastTime) return; if (frames[frameIndex] < lastTime) return;
SetFlip(skeleton.bones[boneIndex], frames[frameIndex + 1] != 0); SetFlip(skeleton.bones.Items[boneIndex], frames[frameIndex + 1] != 0);
} }
virtual protected void SetFlip (Bone bone, bool flip) { virtual protected void SetFlip (Bone bone, bool flip) {

View File

@ -36,8 +36,8 @@ using System.Text;
namespace Spine { namespace Spine {
public class AnimationState { public class AnimationState {
private AnimationStateData data; private AnimationStateData data;
private List<TrackEntry> tracks = new List<TrackEntry>(); private ExposedList<TrackEntry> tracks = new ExposedList<TrackEntry>();
private List<Event> events = new List<Event>(); private ExposedList<Event> events = new ExposedList<Event>();
private float timeScale = 1; private float timeScale = 1;
public AnimationStateData Data { get { return data; } } public AnimationStateData Data { get { return data; } }
@ -61,7 +61,7 @@ namespace Spine {
public void Update (float delta) { public void Update (float delta) {
delta *= timeScale; delta *= timeScale;
for (int i = 0; i < tracks.Count; i++) { for (int i = 0; i < tracks.Count; i++) {
TrackEntry current = tracks[i]; TrackEntry current = tracks.Items[i];
if (current == null) continue; if (current == null) continue;
float trackDelta = delta * current.timeScale; float trackDelta = delta * current.timeScale;
@ -93,10 +93,10 @@ namespace Spine {
} }
public void Apply (Skeleton skeleton) { public void Apply (Skeleton skeleton) {
List<Event> events = this.events; ExposedList<Event> events = this.events;
for (int i = 0; i < tracks.Count; i++) { for (int i = 0; i < tracks.Count; i++) {
TrackEntry current = tracks[i]; TrackEntry current = tracks.Items[i];
if (current == null) continue; if (current == null) continue;
events.Clear(); events.Clear();
@ -125,7 +125,7 @@ namespace Spine {
} }
for (int ii = 0, nn = events.Count; ii < nn; ii++) { for (int ii = 0, nn = events.Count; ii < nn; ii++) {
Event e = events[ii]; Event e = events.Items[ii];
current.OnEvent(this, i, e); current.OnEvent(this, i, e);
if (Event != null) Event(this, i, e); if (Event != null) Event(this, i, e);
} }
@ -142,17 +142,17 @@ namespace Spine {
public void ClearTrack (int trackIndex) { public void ClearTrack (int trackIndex) {
if (trackIndex >= tracks.Count) return; if (trackIndex >= tracks.Count) return;
TrackEntry current = tracks[trackIndex]; TrackEntry current = tracks.Items[trackIndex];
if (current == null) return; if (current == null) return;
current.OnEnd(this, trackIndex); current.OnEnd(this, trackIndex);
if (End != null) End(this, trackIndex); if (End != null) End(this, trackIndex);
tracks[trackIndex] = null; tracks.Items[trackIndex] = null;
} }
private TrackEntry ExpandToIndex (int index) { private TrackEntry ExpandToIndex (int index) {
if (index < tracks.Count) return tracks[index]; if (index < tracks.Count) return tracks.Items[index];
while (index >= tracks.Count) while (index >= tracks.Count)
tracks.Add(null); tracks.Add(null);
return null; return null;
@ -178,7 +178,7 @@ namespace Spine {
} }
} }
tracks[index] = entry; tracks.Items[index] = entry;
entry.OnStart(this, index); entry.OnStart(this, index);
if (Start != null) Start(this, index); if (Start != null) Start(this, index);
@ -224,7 +224,7 @@ namespace Spine {
last = last.next; last = last.next;
last.next = entry; last.next = entry;
} else } else
tracks[trackIndex] = entry; tracks.Items[trackIndex] = entry;
if (delay <= 0) { if (delay <= 0) {
if (last != null) if (last != null)
@ -240,13 +240,13 @@ namespace Spine {
/// <returns>May be null.</returns> /// <returns>May be null.</returns>
public TrackEntry GetCurrent (int trackIndex) { public TrackEntry GetCurrent (int trackIndex) {
if (trackIndex >= tracks.Count) return null; if (trackIndex >= tracks.Count) return null;
return tracks[trackIndex]; return tracks.Items[trackIndex];
} }
override public String ToString () { override public String ToString () {
StringBuilder buffer = new StringBuilder(); StringBuilder buffer = new StringBuilder();
for (int i = 0, n = tracks.Count; i < n; i++) { for (int i = 0, n = tracks.Count; i < n; i++) {
TrackEntry entry = tracks[i]; TrackEntry entry = tracks.Items[i];
if (entry == null) continue; if (entry == null) continue;
if (buffer.Length > 0) buffer.Append(", "); if (buffer.Length > 0) buffer.Append(", ");
buffer.Append(entry.ToString()); buffer.Append(entry.ToString());

View File

@ -96,7 +96,7 @@ namespace Spine {
public void ComputeWorldVertices (Slot slot, float[] worldVertices) { public void ComputeWorldVertices (Slot slot, float[] worldVertices) {
Skeleton skeleton = slot.bone.skeleton; Skeleton skeleton = slot.bone.skeleton;
List<Bone> skeletonBones = skeleton.bones; ExposedList<Bone> skeletonBones = skeleton.bones;
float x = skeleton.x, y = skeleton.y; float x = skeleton.x, y = skeleton.y;
float[] weights = this.weights; float[] weights = this.weights;
int[] bones = this.bones; int[] bones = this.bones;
@ -105,7 +105,7 @@ namespace Spine {
float wx = 0, wy = 0; float wx = 0, wy = 0;
int nn = bones[v++] + v; int nn = bones[v++] + v;
for (; v < nn; v++, b += 3) { for (; v < nn; v++, b += 3) {
Bone bone = skeletonBones[bones[v]]; Bone bone = skeletonBones.Items[bones[v]];
float vx = weights[b], vy = weights[b + 1], weight = weights[b + 2]; float vx = weights[b], vy = weights[b + 1], weight = weights[b + 2];
wx += (vx * bone.m00 + vy * bone.m01 + bone.worldX) * weight; wx += (vx * bone.m00 + vy * bone.m01 + bone.worldX) * weight;
wy += (vx * bone.m10 + vy * bone.m11 + bone.worldY) * weight; wy += (vx * bone.m10 + vy * bone.m11 + bone.worldY) * weight;
@ -119,7 +119,7 @@ namespace Spine {
float wx = 0, wy = 0; float wx = 0, wy = 0;
int nn = bones[v++] + v; int nn = bones[v++] + v;
for (; v < nn; v++, b += 3, f += 2) { for (; v < nn; v++, b += 3, f += 2) {
Bone bone = skeletonBones[bones[v]]; Bone bone = skeletonBones.Items[bones[v]];
float vx = weights[b] + ffd[f], vy = weights[b + 1] + ffd[f + 1], weight = weights[b + 2]; float vx = weights[b] + ffd[f], vy = weights[b + 1] + ffd[f + 1], weight = weights[b + 2];
wx += (vx * bone.m00 + vy * bone.m01 + bone.worldX) * weight; wx += (vx * bone.m00 + vy * bone.m01 + bone.worldX) * weight;
wy += (vx * bone.m10 + vy * bone.m11 + bone.worldY) * weight; wy += (vx * bone.m10 + vy * bone.m11 + bone.worldY) * weight;

View File

@ -39,7 +39,7 @@ namespace Spine {
internal BoneData data; internal BoneData data;
internal Skeleton skeleton; internal Skeleton skeleton;
internal Bone parent; internal Bone parent;
internal List<Bone> children = new List<Bone>(); internal ExposedList<Bone> children = new ExposedList<Bone>();
internal float x, y, rotation, rotationIK, scaleX, scaleY; internal float x, y, rotation, rotationIK, scaleX, scaleY;
internal bool flipX, flipY; internal bool flipX, flipY;
internal float m00, m01, m10, m11; internal float m00, m01, m10, m11;
@ -49,7 +49,7 @@ namespace Spine {
public BoneData Data { get { return data; } } public BoneData Data { get { return data; } }
public Skeleton Skeleton { get { return skeleton; } } public Skeleton Skeleton { get { return skeleton; } }
public Bone Parent { get { return parent; } } public Bone Parent { get { return parent; } }
public List<Bone> Children { get { return children; } } public ExposedList<Bone> Children { get { return children; } }
public float X { get { return x; } set { x = value; } } public float X { get { return x; } set { x = value; } }
public float Y { get { return y; } set { y = value; } } public float Y { get { return y; } set { y = value; } }
/// <summary>The forward kinetics rotation.</summary> /// <summary>The forward kinetics rotation.</summary>

View File

@ -0,0 +1,585 @@
//
// System.Collections.Generic.List
//
// Authors:
// Ben Maurer (bmaurer@ximian.com)
// Martin Baulig (martin@ximian.com)
// Carlos Alberto Cortez (calberto.cortez@gmail.com)
// David Waite (mass@akuma.org)
//
// Copyright (C) 2004-2005 Novell, Inc (http://www.novell.com)
// Copyright (C) 2005 David Waite
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// "Software"), to deal in the Software without restriction, including
// without limitation the rights to use, copy, modify, merge, publish,
// distribute, sublicense, and/or sell copies of the Software, and to
// permit persons to whom the Software is furnished to do so, subject to
// the following conditions:
//
// The above copyright notice and this permission notice shall be
// included in all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
namespace Spine {
[Serializable]
[DebuggerDisplay("Count={Count}")]
public class ExposedList<T> : IEnumerable<T> {
public T[] Items;
public int Count;
private const int DefaultCapacity = 4;
private static readonly T[] EmptyArray = new T[0];
private int version;
public ExposedList() {
Items = EmptyArray;
}
public ExposedList(IEnumerable<T> collection) {
CheckCollection(collection);
// initialize to needed size (if determinable)
ICollection<T> c = collection as ICollection<T>;
if (c == null) {
Items = EmptyArray;
AddEnumerable(collection);
} else {
Items = new T[c.Count];
AddCollection(c);
}
}
public ExposedList(int capacity) {
if (capacity < 0)
throw new ArgumentOutOfRangeException("capacity");
Items = new T[capacity];
}
internal ExposedList(T[] data, int size) {
Items = data;
Count = size;
}
public void Add(T item) {
// If we check to see if we need to grow before trying to grow
// we can speed things up by 25%
if (Count == Items.Length)
GrowIfNeeded(1);
Items[Count ++] = item;
version++;
}
public void GrowIfNeeded(int newCount) {
int minimumSize = Count + newCount;
if (minimumSize > Items.Length)
Capacity = Math.Max(Math.Max(Capacity * 2, DefaultCapacity), minimumSize);
}
private void CheckRange(int idx, int count) {
if (idx < 0)
throw new ArgumentOutOfRangeException("index");
if (count < 0)
throw new ArgumentOutOfRangeException("count");
if ((uint) idx + (uint) count > (uint) Count)
throw new ArgumentException("index and count exceed length of list");
}
private void AddCollection(ICollection<T> collection) {
int collectionCount = collection.Count;
if (collectionCount == 0)
return;
GrowIfNeeded(collectionCount);
collection.CopyTo(Items, Count);
Count += collectionCount;
}
private void AddEnumerable(IEnumerable<T> enumerable) {
foreach (T t in enumerable) {
Add(t);
}
}
public void AddRange(IEnumerable<T> collection) {
CheckCollection(collection);
ICollection<T> c = collection as ICollection<T>;
if (c != null)
AddCollection(c);
else
AddEnumerable(collection);
version++;
}
public int BinarySearch(T item) {
return Array.BinarySearch<T>(Items, 0, Count, item);
}
public int BinarySearch(T item, IComparer<T> comparer) {
return Array.BinarySearch<T>(Items, 0, Count, item, comparer);
}
public int BinarySearch(int index, int count, T item, IComparer<T> comparer) {
CheckRange(index, count);
return Array.BinarySearch<T>(Items, index, count, item, comparer);
}
public void Clear(bool clearArray = true) {
if (clearArray)
Array.Clear(Items, 0, Items.Length);
Count = 0;
version++;
}
public bool Contains(T item) {
return Array.IndexOf<T>(Items, item, 0, Count) != -1;
}
public ExposedList<TOutput> ConvertAll<TOutput>(Converter<T, TOutput> converter) {
if (converter == null)
throw new ArgumentNullException("converter");
ExposedList<TOutput> u = new ExposedList<TOutput>(Count);
for (int i = 0; i < Count; i++)
u.Items[i] = converter(Items[i]);
u.Count = Count;
return u;
}
public void CopyTo(T[] array) {
Array.Copy(Items, 0, array, 0, Count);
}
public void CopyTo(T[] array, int arrayIndex) {
Array.Copy(Items, 0, array, arrayIndex, Count);
}
public void CopyTo(int index, T[] array, int arrayIndex, int count) {
CheckRange(index, count);
Array.Copy(Items, index, array, arrayIndex, count);
}
public bool Exists(Predicate<T> match) {
CheckMatch(match);
return GetIndex(0, Count, match) != -1;
}
public T Find(Predicate<T> match) {
CheckMatch(match);
int i = GetIndex(0, Count, match);
return (i != -1) ? Items[i] : default (T);
}
private static void CheckMatch(Predicate<T> match) {
if (match == null)
throw new ArgumentNullException("match");
}
public ExposedList<T> FindAll(Predicate<T> match) {
CheckMatch(match);
return FindAllList(match);
}
private ExposedList<T> FindAllList(Predicate<T> match) {
ExposedList<T> results = new ExposedList<T>();
for (int i = 0; i < Count; i++)
if (match(Items[i]))
results.Add(Items[i]);
return results;
}
public int FindIndex(Predicate<T> match) {
CheckMatch(match);
return GetIndex(0, Count, match);
}
public int FindIndex(int startIndex, Predicate<T> match) {
CheckMatch(match);
CheckIndex(startIndex);
return GetIndex(startIndex, Count - startIndex, match);
}
public int FindIndex(int startIndex, int count, Predicate<T> match) {
CheckMatch(match);
CheckRange(startIndex, count);
return GetIndex(startIndex, count, match);
}
private int GetIndex(int startIndex, int count, Predicate<T> match) {
int end = startIndex + count;
for (int i = startIndex; i < end; i ++)
if (match(Items[i]))
return i;
return -1;
}
public T FindLast(Predicate<T> match) {
CheckMatch(match);
int i = GetLastIndex(0, Count, match);
return i == -1 ? default (T) : Items[i];
}
public int FindLastIndex(Predicate<T> match) {
CheckMatch(match);
return GetLastIndex(0, Count, match);
}
public int FindLastIndex(int startIndex, Predicate<T> match) {
CheckMatch(match);
CheckIndex(startIndex);
return GetLastIndex(0, startIndex + 1, match);
}
public int FindLastIndex(int startIndex, int count, Predicate<T> match) {
CheckMatch(match);
int start = startIndex - count + 1;
CheckRange(start, count);
return GetLastIndex(start, count, match);
}
private int GetLastIndex(int startIndex, int count, Predicate<T> match) {
// unlike FindLastIndex, takes regular params for search range
for (int i = startIndex + count; i != startIndex;)
if (match(Items[--i]))
return i;
return -1;
}
public void ForEach(Action<T> action) {
if (action == null)
throw new ArgumentNullException("action");
for (int i = 0; i < Count; i++)
action(Items[i]);
}
public Enumerator GetEnumerator() {
return new Enumerator(this);
}
public ExposedList<T> GetRange(int index, int count) {
CheckRange(index, count);
T[] tmpArray = new T[count];
Array.Copy(Items, index, tmpArray, 0, count);
return new ExposedList<T>(tmpArray, count);
}
public int IndexOf(T item) {
return Array.IndexOf<T>(Items, item, 0, Count);
}
public int IndexOf(T item, int index) {
CheckIndex(index);
return Array.IndexOf<T>(Items, item, index, Count - index);
}
public int IndexOf(T item, int index, int count) {
if (index < 0)
throw new ArgumentOutOfRangeException("index");
if (count < 0)
throw new ArgumentOutOfRangeException("count");
if ((uint) index + (uint) count > (uint) Count)
throw new ArgumentOutOfRangeException("index and count exceed length of list");
return Array.IndexOf<T>(Items, item, index, count);
}
private void Shift(int start, int delta) {
if (delta < 0)
start -= delta;
if (start < Count)
Array.Copy(Items, start, Items, start + delta, Count - start);
Count += delta;
if (delta < 0)
Array.Clear(Items, Count, -delta);
}
private void CheckIndex(int index) {
if (index < 0 || (uint) index > (uint) Count)
throw new ArgumentOutOfRangeException("index");
}
public void Insert(int index, T item) {
CheckIndex(index);
if (Count == Items.Length)
GrowIfNeeded(1);
Shift(index, 1);
Items[index] = item;
version++;
}
private void CheckCollection(IEnumerable<T> collection) {
if (collection == null)
throw new ArgumentNullException("collection");
}
public void InsertRange(int index, IEnumerable<T> collection) {
CheckCollection(collection);
CheckIndex(index);
if (collection == this) {
T[] buffer = new T[Count];
CopyTo(buffer, 0);
GrowIfNeeded(Count);
Shift(index, buffer.Length);
Array.Copy(buffer, 0, Items, index, buffer.Length);
} else {
ICollection<T> c = collection as ICollection<T>;
if (c != null)
InsertCollection(index, c);
else
InsertEnumeration(index, collection);
}
version++;
}
private void InsertCollection(int index, ICollection<T> collection) {
int collectionCount = collection.Count;
GrowIfNeeded(collectionCount);
Shift(index, collectionCount);
collection.CopyTo(Items, index);
}
private void InsertEnumeration(int index, IEnumerable<T> enumerable) {
foreach (T t in enumerable)
Insert(index++, t);
}
public int LastIndexOf(T item) {
return Array.LastIndexOf<T>(Items, item, Count - 1, Count);
}
public int LastIndexOf(T item, int index) {
CheckIndex(index);
return Array.LastIndexOf<T>(Items, item, index, index + 1);
}
public int LastIndexOf(T item, int index, int count) {
if (index < 0)
throw new ArgumentOutOfRangeException("index", index, "index is negative");
if (count < 0)
throw new ArgumentOutOfRangeException("count", count, "count is negative");
if (index - count + 1 < 0)
throw new ArgumentOutOfRangeException("count", count, "count is too large");
return Array.LastIndexOf<T>(Items, item, index, count);
}
public bool Remove(T item) {
int loc = IndexOf(item);
if (loc != -1)
RemoveAt(loc);
return loc != -1;
}
public int RemoveAll(Predicate<T> match) {
CheckMatch(match);
int i = 0;
int j = 0;
// Find the first item to remove
for (i = 0; i < Count; i++)
if (match(Items[i]))
break;
if (i == Count)
return 0;
version++;
// Remove any additional items
for (j = i + 1; j < Count; j++) {
if (!match(Items[j]))
Items[i++] = Items[j];
}
if (j - i > 0)
Array.Clear(Items, i, j - i);
Count = i;
return (j - i);
}
public void RemoveAt(int index) {
if (index < 0 || (uint) index >= (uint) Count)
throw new ArgumentOutOfRangeException("index");
Shift(index, -1);
Array.Clear(Items, Count, 1);
version++;
}
public void RemoveRange(int index, int count) {
CheckRange(index, count);
if (count > 0) {
Shift(index, -count);
Array.Clear(Items, Count, count);
version++;
}
}
public void Reverse() {
Array.Reverse(Items, 0, Count);
version++;
}
public void Reverse(int index, int count) {
CheckRange(index, count);
Array.Reverse(Items, index, count);
version++;
}
public void Sort() {
Array.Sort<T>(Items, 0, Count, Comparer<T>.Default);
version++;
}
public void Sort(IComparer<T> comparer) {
Array.Sort<T>(Items, 0, Count, comparer);
version++;
}
public void Sort(Comparison<T> comparison) {
Array.Sort<T>(Items, comparison);
version++;
}
public void Sort(int index, int count, IComparer<T> comparer) {
CheckRange(index, count);
Array.Sort<T>(Items, index, count, comparer);
version++;
}
public T[] ToArray() {
T[] t = new T[Count];
Array.Copy(Items, t, Count);
return t;
}
public void TrimExcess() {
Capacity = Count;
}
public bool TrueForAll(Predicate<T> match) {
CheckMatch(match);
for (int i = 0; i < Count; i++)
if (!match(Items[i]))
return false;
return true;
}
public int Capacity {
get {
return Items.Length;
}
set {
if ((uint) value < (uint) Count)
throw new ArgumentOutOfRangeException();
Array.Resize(ref Items, value);
}
}
#region Interface implementations.
IEnumerator<T> IEnumerable<T>.GetEnumerator() {
return GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return GetEnumerator();
}
#endregion
[Serializable]
public struct Enumerator : IEnumerator<T>, IDisposable {
private ExposedList<T> l;
private int next;
private int ver;
private T current;
internal Enumerator(ExposedList<T> l)
: this() {
this.l = l;
ver = l.version;
}
public void Dispose() {
l = null;
}
private void VerifyState() {
if (l == null)
throw new ObjectDisposedException(GetType().FullName);
if (ver != l.version)
throw new InvalidOperationException(
"Collection was modified; enumeration operation may not execute.");
}
public bool MoveNext() {
VerifyState();
if (next < 0)
return false;
if (next < l.Count) {
current = l.Items[next++];
return true;
}
next = -1;
return false;
}
public T Current {
get {
return current;
}
}
void IEnumerator.Reset() {
VerifyState();
next = 0;
}
object IEnumerator.Current {
get {
VerifyState();
if (next <= 0)
throw new InvalidOperationException();
return current;
}
}
}
}
}

View File

@ -37,13 +37,13 @@ namespace Spine {
private const float radDeg = 180 / (float)Math.PI; private const float radDeg = 180 / (float)Math.PI;
internal IkConstraintData data; internal IkConstraintData data;
internal List<Bone> bones = new List<Bone>(); internal ExposedList<Bone> bones = new ExposedList<Bone>();
internal Bone target; internal Bone target;
internal int bendDirection; internal int bendDirection;
internal float mix; internal float mix;
public IkConstraintData Data { get { return data; } } public IkConstraintData Data { get { return data; } }
public List<Bone> Bones { get { return bones; } } public ExposedList<Bone> Bones { get { return bones; } }
public Bone Target { get { return target; } set { target = value; } } public Bone Target { get { return target; } set { target = value; } }
public int BendDirection { get { return bendDirection; } set { bendDirection = value; } } public int BendDirection { get { return bendDirection; } set { bendDirection = value; } }
public float Mix { get { return mix; } set { mix = value; } } public float Mix { get { return mix; } set { mix = value; } }
@ -55,7 +55,7 @@ namespace Spine {
mix = data.mix; mix = data.mix;
bendDirection = data.bendDirection; bendDirection = data.bendDirection;
bones = new List<Bone>(data.bones.Count); bones = new ExposedList<Bone>(data.bones.Count);
foreach (BoneData boneData in data.bones) foreach (BoneData boneData in data.bones)
bones.Add(skeleton.FindBone(boneData.name)); bones.Add(skeleton.FindBone(boneData.name));
target = skeleton.FindBone(data.target.name); target = skeleton.FindBone(data.target.name);
@ -63,13 +63,13 @@ namespace Spine {
public void apply () { public void apply () {
Bone target = this.target; Bone target = this.target;
List<Bone> bones = this.bones; ExposedList<Bone> bones = this.bones;
switch (bones.Count) { switch (bones.Count) {
case 1: case 1:
apply(bones[0], target.worldX, target.worldY, mix); apply(bones.Items[0], target.worldX, target.worldY, mix);
break; break;
case 2: case 2:
apply(bones[0], bones[1], target.worldX, target.worldY, bendDirection, mix); apply(bones.Items[0], bones.Items[1], target.worldX, target.worldY, bendDirection, mix);
break; break;
} }
} }

View File

@ -35,11 +35,11 @@ using System.Collections.Generic;
namespace Spine { namespace Spine {
public class Skeleton { public class Skeleton {
internal SkeletonData data; internal SkeletonData data;
internal List<Bone> bones; internal ExposedList<Bone> bones;
internal List<Slot> slots; internal ExposedList<Slot> slots;
internal List<Slot> drawOrder; internal ExposedList<Slot> drawOrder;
internal List<IkConstraint> ikConstraints; internal ExposedList<IkConstraint> ikConstraints;
private List<List<Bone>> boneCache = new List<List<Bone>>(); private ExposedList<ExposedList<Bone>> boneCache = new ExposedList<ExposedList<Bone>>();
internal Skin skin; internal Skin skin;
internal float r = 1, g = 1, b = 1, a = 1; internal float r = 1, g = 1, b = 1, a = 1;
internal float time; internal float time;
@ -47,10 +47,10 @@ namespace Spine {
internal float x, y; internal float x, y;
public SkeletonData Data { get { return data; } } public SkeletonData Data { get { return data; } }
public List<Bone> Bones { get { return bones; } } public ExposedList<Bone> Bones { get { return bones; } }
public List<Slot> Slots { get { return slots; } } public ExposedList<Slot> Slots { get { return slots; } }
public List<Slot> DrawOrder { get { return drawOrder; } } public ExposedList<Slot> DrawOrder { get { return drawOrder; } }
public List<IkConstraint> IkConstraints { get { return ikConstraints; } set { ikConstraints = value; } } public ExposedList<IkConstraint> IkConstraints { get { return ikConstraints; } set { ikConstraints = value; } }
public Skin Skin { get { return skin; } set { skin = value; } } public Skin Skin { get { return skin; } set { skin = value; } }
public float R { get { return r; } set { r = value; } } public float R { get { return r; } set { r = value; } }
public float G { get { return g; } set { g = value; } } public float G { get { return g; } set { g = value; } }
@ -64,7 +64,7 @@ namespace Spine {
public Bone RootBone { public Bone RootBone {
get { get {
return bones.Count == 0 ? null : bones[0]; return bones.Count == 0 ? null : bones.Items[0];
} }
} }
@ -72,24 +72,24 @@ namespace Spine {
if (data == null) throw new ArgumentNullException("data cannot be null."); if (data == null) throw new ArgumentNullException("data cannot be null.");
this.data = data; this.data = data;
bones = new List<Bone>(data.bones.Count); bones = new ExposedList<Bone>(data.bones.Count);
foreach (BoneData boneData in data.bones) { foreach (BoneData boneData in data.bones) {
Bone parent = boneData.parent == null ? null : bones[data.bones.IndexOf(boneData.parent)]; Bone parent = boneData.parent == null ? null : bones.Items[data.bones.IndexOf(boneData.parent)];
Bone bone = new Bone(boneData, this, parent); Bone bone = new Bone(boneData, this, parent);
if (parent != null) parent.children.Add(bone); if (parent != null) parent.children.Add(bone);
bones.Add(bone); bones.Add(bone);
} }
slots = new List<Slot>(data.slots.Count); slots = new ExposedList<Slot>(data.slots.Count);
drawOrder = new List<Slot>(data.slots.Count); drawOrder = new ExposedList<Slot>(data.slots.Count);
foreach (SlotData slotData in data.slots) { foreach (SlotData slotData in data.slots) {
Bone bone = bones[data.bones.IndexOf(slotData.boneData)]; Bone bone = bones.Items[data.bones.IndexOf(slotData.boneData)];
Slot slot = new Slot(slotData, bone); Slot slot = new Slot(slotData, bone);
slots.Add(slot); slots.Add(slot);
drawOrder.Add(slot); drawOrder.Add(slot);
} }
ikConstraints = new List<IkConstraint>(data.ikConstraints.Count); ikConstraints = new ExposedList<IkConstraint>(data.ikConstraints.Count);
foreach (IkConstraintData ikConstraintData in data.ikConstraints) foreach (IkConstraintData ikConstraintData in data.ikConstraints)
ikConstraints.Add(new IkConstraint(ikConstraintData, this)); ikConstraints.Add(new IkConstraint(ikConstraintData, this));
@ -99,31 +99,31 @@ namespace Spine {
/// <summary>Caches information about bones and IK constraints. Must be called if bones or IK constraints are added or /// <summary>Caches information about bones and IK constraints. Must be called if bones or IK constraints are added or
/// removed.</summary> /// removed.</summary>
public void UpdateCache () { public void UpdateCache () {
List<List<Bone>> boneCache = this.boneCache; ExposedList<ExposedList<Bone>> boneCache = this.boneCache;
List<IkConstraint> ikConstraints = this.ikConstraints; ExposedList<IkConstraint> ikConstraints = this.ikConstraints;
int ikConstraintsCount = ikConstraints.Count; int ikConstraintsCount = ikConstraints.Count;
int arrayCount = ikConstraintsCount + 1; int arrayCount = ikConstraintsCount + 1;
if (boneCache.Count > arrayCount) boneCache.RemoveRange(arrayCount, boneCache.Count - arrayCount); if (boneCache.Count > arrayCount) boneCache.RemoveRange(arrayCount, boneCache.Count - arrayCount);
for (int i = 0, n = boneCache.Count; i < n; i++) for (int i = 0, n = boneCache.Count; i < n; i++)
boneCache[i].Clear(); boneCache.Items[i].Clear();
while (boneCache.Count < arrayCount) while (boneCache.Count < arrayCount)
boneCache.Add(new List<Bone>()); boneCache.Add(new ExposedList<Bone>());
List<Bone> nonIkBones = boneCache[0]; ExposedList<Bone> nonIkBones = boneCache.Items[0];
for (int i = 0, n = bones.Count; i < n; i++) { for (int i = 0, n = bones.Count; i < n; i++) {
Bone bone = bones[i]; Bone bone = bones.Items[i];
Bone current = bone; Bone current = bone;
do { do {
for (int ii = 0; ii < ikConstraintsCount; ii++) { for (int ii = 0; ii < ikConstraintsCount; ii++) {
IkConstraint ikConstraint = ikConstraints[ii]; IkConstraint ikConstraint = ikConstraints.Items[ii];
Bone parent = ikConstraint.bones[0]; Bone parent = ikConstraint.bones.Items[0];
Bone child = ikConstraint.bones[ikConstraint.bones.Count - 1]; Bone child = ikConstraint.bones.Items[ikConstraint.bones.Count - 1];
while (true) { while (true) {
if (current == child) { if (current == child) {
boneCache[ii].Add(bone); boneCache.Items[ii].Add(bone);
boneCache[ii + 1].Add(bone); boneCache.Items[ii + 1].Add(bone);
goto outer; goto outer;
} }
if (child == parent) break; if (child == parent) break;
@ -139,20 +139,20 @@ namespace Spine {
/// <summary>Updates the world transform for each bone and applies IK constraints.</summary> /// <summary>Updates the world transform for each bone and applies IK constraints.</summary>
public void UpdateWorldTransform () { public void UpdateWorldTransform () {
List<Bone> bones = this.bones; ExposedList<Bone> bones = this.bones;
for (int ii = 0, nn = bones.Count; ii < nn; ii++) { for (int ii = 0, nn = bones.Count; ii < nn; ii++) {
Bone bone = bones[ii]; Bone bone = bones.Items[ii];
bone.rotationIK = bone.rotation; bone.rotationIK = bone.rotation;
} }
List<List<Bone>> boneCache = this.boneCache; ExposedList<ExposedList<Bone>> boneCache = this.boneCache;
List<IkConstraint> ikConstraints = this.ikConstraints; ExposedList<IkConstraint> ikConstraints = this.ikConstraints;
int i = 0, last = boneCache.Count - 1; int i = 0, last = boneCache.Count - 1;
while (true) { while (true) {
List<Bone> updateBones = boneCache[i]; ExposedList<Bone> updateBones = boneCache.Items[i];
for (int ii = 0, nn = updateBones.Count; ii < nn; ii++) for (int ii = 0, nn = updateBones.Count; ii < nn; ii++)
updateBones[ii].UpdateWorldTransform(); updateBones.Items[ii].UpdateWorldTransform();
if (i == last) break; if (i == last) break;
ikConstraints[i].apply(); ikConstraints.Items[i].apply();
i++; i++;
} }
} }
@ -164,32 +164,34 @@ namespace Spine {
} }
public void SetBonesToSetupPose () { public void SetBonesToSetupPose () {
List<Bone> bones = this.bones; ExposedList<Bone> bones = this.bones;
for (int i = 0, n = bones.Count; i < n; i++) for (int i = 0, n = bones.Count; i < n; i++)
bones[i].SetToSetupPose(); bones.Items[i].SetToSetupPose();
List<IkConstraint> ikConstraints = this.ikConstraints; ExposedList<IkConstraint> ikConstraints = this.ikConstraints;
for (int i = 0, n = ikConstraints.Count; i < n; i++) { for (int i = 0, n = ikConstraints.Count; i < n; i++) {
IkConstraint ikConstraint = ikConstraints[i]; IkConstraint ikConstraint = ikConstraints.Items[i];
ikConstraint.bendDirection = ikConstraint.data.bendDirection; ikConstraint.bendDirection = ikConstraint.data.bendDirection;
ikConstraint.mix = ikConstraint.data.mix; ikConstraint.mix = ikConstraint.data.mix;
} }
} }
public void SetSlotsToSetupPose () { public void SetSlotsToSetupPose () {
List<Slot> slots = this.slots; ExposedList<Slot> slots = this.slots;
drawOrder.Clear(); drawOrder.Clear();
drawOrder.AddRange(slots);
for (int i = 0, n = slots.Count; i < n; i++) for (int i = 0, n = slots.Count; i < n; i++)
slots[i].SetToSetupPose(i); drawOrder.Add(slots.Items[i]);
for (int i = 0, n = slots.Count; i < n; i++)
slots.Items[i].SetToSetupPose(i);
} }
/// <returns>May be null.</returns> /// <returns>May be null.</returns>
public Bone FindBone (String boneName) { public Bone FindBone (String boneName) {
if (boneName == null) throw new ArgumentNullException("boneName cannot be null."); if (boneName == null) throw new ArgumentNullException("boneName cannot be null.");
List<Bone> bones = this.bones; ExposedList<Bone> bones = this.bones;
for (int i = 0, n = bones.Count; i < n; i++) { for (int i = 0, n = bones.Count; i < n; i++) {
Bone bone = bones[i]; Bone bone = bones.Items[i];
if (bone.data.name == boneName) return bone; if (bone.data.name == boneName) return bone;
} }
return null; return null;
@ -198,18 +200,18 @@ namespace Spine {
/// <returns>-1 if the bone was not found.</returns> /// <returns>-1 if the bone was not found.</returns>
public int FindBoneIndex (String boneName) { public int FindBoneIndex (String boneName) {
if (boneName == null) throw new ArgumentNullException("boneName cannot be null."); if (boneName == null) throw new ArgumentNullException("boneName cannot be null.");
List<Bone> bones = this.bones; ExposedList<Bone> bones = this.bones;
for (int i = 0, n = bones.Count; i < n; i++) for (int i = 0, n = bones.Count; i < n; i++)
if (bones[i].data.name == boneName) return i; if (bones.Items[i].data.name == boneName) return i;
return -1; return -1;
} }
/// <returns>May be null.</returns> /// <returns>May be null.</returns>
public Slot FindSlot (String slotName) { public Slot FindSlot (String slotName) {
if (slotName == null) throw new ArgumentNullException("slotName cannot be null."); if (slotName == null) throw new ArgumentNullException("slotName cannot be null.");
List<Slot> slots = this.slots; ExposedList<Slot> slots = this.slots;
for (int i = 0, n = slots.Count; i < n; i++) { for (int i = 0, n = slots.Count; i < n; i++) {
Slot slot = slots[i]; Slot slot = slots.Items[i];
if (slot.data.name == slotName) return slot; if (slot.data.name == slotName) return slot;
} }
return null; return null;
@ -218,9 +220,9 @@ namespace Spine {
/// <returns>-1 if the bone was not found.</returns> /// <returns>-1 if the bone was not found.</returns>
public int FindSlotIndex (String slotName) { public int FindSlotIndex (String slotName) {
if (slotName == null) throw new ArgumentNullException("slotName cannot be null."); if (slotName == null) throw new ArgumentNullException("slotName cannot be null.");
List<Slot> slots = this.slots; ExposedList<Slot> slots = this.slots;
for (int i = 0, n = slots.Count; i < n; i++) for (int i = 0, n = slots.Count; i < n; i++)
if (slots[i].data.name.Equals(slotName)) return i; if (slots.Items[i].data.name.Equals(slotName)) return i;
return -1; return -1;
} }
@ -240,9 +242,9 @@ namespace Spine {
if (skin != null) if (skin != null)
newSkin.AttachAll(this, skin); newSkin.AttachAll(this, skin);
else { else {
List<Slot> slots = this.slots; ExposedList<Slot> slots = this.slots;
for (int i = 0, n = slots.Count; i < n; i++) { for (int i = 0, n = slots.Count; i < n; i++) {
Slot slot = slots[i]; Slot slot = slots.Items[i];
String name = slot.data.attachmentName; String name = slot.data.attachmentName;
if (name != null) { if (name != null) {
Attachment attachment = newSkin.GetAttachment(i, name); Attachment attachment = newSkin.GetAttachment(i, name);
@ -273,9 +275,9 @@ namespace Spine {
/// <param name="attachmentName">May be null.</param> /// <param name="attachmentName">May be null.</param>
public void SetAttachment (String slotName, String attachmentName) { public void SetAttachment (String slotName, String attachmentName) {
if (slotName == null) throw new ArgumentNullException("slotName cannot be null."); if (slotName == null) throw new ArgumentNullException("slotName cannot be null.");
List<Slot> slots = this.slots; ExposedList<Slot> slots = this.slots;
for (int i = 0, n = slots.Count; i < n; i++) { for (int i = 0, n = slots.Count; i < n; i++) {
Slot slot = slots[i]; Slot slot = slots.Items[i];
if (slot.data.name == slotName) { if (slot.data.name == slotName) {
Attachment attachment = null; Attachment attachment = null;
if (attachmentName != null) { if (attachmentName != null) {
@ -292,9 +294,9 @@ namespace Spine {
/** @return May be null. */ /** @return May be null. */
public IkConstraint FindIkConstraint (String ikConstraintName) { public IkConstraint FindIkConstraint (String ikConstraintName) {
if (ikConstraintName == null) throw new ArgumentNullException("ikConstraintName cannot be null."); if (ikConstraintName == null) throw new ArgumentNullException("ikConstraintName cannot be null.");
List<IkConstraint> ikConstraints = this.ikConstraints; ExposedList<IkConstraint> ikConstraints = this.ikConstraints;
for (int i = 0, n = ikConstraints.Count; i < n; i++) { for (int i = 0, n = ikConstraints.Count; i < n; i++) {
IkConstraint ikConstraint = ikConstraints[i]; IkConstraint ikConstraint = ikConstraints.Items[i];
if (ikConstraint.data.name == ikConstraintName) return ikConstraint; if (ikConstraint.data.name == ikConstraintName) return ikConstraint;
} }
return null; return null;

View File

@ -119,7 +119,7 @@ namespace Spine {
String name = ReadString(input); String name = ReadString(input);
BoneData parent = null; BoneData parent = null;
int parentIndex = ReadInt(input, true) - 1; int parentIndex = ReadInt(input, true) - 1;
if (parentIndex != -1) parent = skeletonData.bones[parentIndex]; if (parentIndex != -1) parent = skeletonData.bones.Items[parentIndex];
BoneData boneData = new BoneData(name, parent); BoneData boneData = new BoneData(name, parent);
boneData.x = ReadFloat(input) * scale; boneData.x = ReadFloat(input) * scale;
boneData.y = ReadFloat(input) * scale; boneData.y = ReadFloat(input) * scale;
@ -139,8 +139,8 @@ namespace Spine {
for (int i = 0, n = ReadInt(input, true); i < n; i++) { for (int i = 0, n = ReadInt(input, true); i < n; i++) {
IkConstraintData ikConstraintData = new IkConstraintData(ReadString(input)); IkConstraintData ikConstraintData = new IkConstraintData(ReadString(input));
for (int ii = 0, nn = ReadInt(input, true); ii < nn; ii++) for (int ii = 0, nn = ReadInt(input, true); ii < nn; ii++)
ikConstraintData.bones.Add(skeletonData.bones[ReadInt(input, true)]); ikConstraintData.bones.Add(skeletonData.bones.Items[ReadInt(input, true)]);
ikConstraintData.target = skeletonData.bones[ReadInt(input, true)]; ikConstraintData.target = skeletonData.bones.Items[ReadInt(input, true)];
ikConstraintData.mix = ReadFloat(input); ikConstraintData.mix = ReadFloat(input);
ikConstraintData.bendDirection = ReadSByte(input); ikConstraintData.bendDirection = ReadSByte(input);
skeletonData.ikConstraints.Add(ikConstraintData); skeletonData.ikConstraints.Add(ikConstraintData);
@ -149,7 +149,7 @@ namespace Spine {
// Slots. // Slots.
for (int i = 0, n = ReadInt(input, true); i < n; i++) { for (int i = 0, n = ReadInt(input, true); i < n; i++) {
String slotName = ReadString(input); String slotName = ReadString(input);
BoneData boneData = skeletonData.bones[ReadInt(input, true)]; BoneData boneData = skeletonData.bones.Items[ReadInt(input, true)];
SlotData slotData = new SlotData(slotName, boneData); SlotData slotData = new SlotData(slotName, boneData);
int color = ReadInt(input); int color = ReadInt(input);
slotData.r = ((color & 0xff000000) >> 24) / 255f; slotData.r = ((color & 0xff000000) >> 24) / 255f;
@ -340,7 +340,7 @@ namespace Spine {
} }
private void ReadAnimation (String name, Stream input, SkeletonData skeletonData) { private void ReadAnimation (String name, Stream input, SkeletonData skeletonData) {
var timelines = new List<Timeline>(); var timelines = new ExposedList<Timeline>();
float scale = Scale; float scale = Scale;
float duration = 0; float duration = 0;
@ -436,7 +436,7 @@ namespace Spine {
// IK timelines. // IK timelines.
for (int i = 0, n = ReadInt(input, true); i < n; i++) { for (int i = 0, n = ReadInt(input, true); i < n; i++) {
IkConstraintData ikConstraint = skeletonData.ikConstraints[ReadInt(input, true)]; IkConstraintData ikConstraint = skeletonData.ikConstraints.Items[ReadInt(input, true)];
int frameCount = ReadInt(input, true); int frameCount = ReadInt(input, true);
IkConstraintTimeline timeline = new IkConstraintTimeline(frameCount); IkConstraintTimeline timeline = new IkConstraintTimeline(frameCount);
timeline.ikConstraintIndex = skeletonData.ikConstraints.IndexOf(ikConstraint); timeline.ikConstraintIndex = skeletonData.ikConstraints.IndexOf(ikConstraint);
@ -450,7 +450,7 @@ namespace Spine {
// FFD timelines. // FFD timelines.
for (int i = 0, n = ReadInt(input, true); i < n; i++) { for (int i = 0, n = ReadInt(input, true); i < n; i++) {
Skin skin = skeletonData.skins[ReadInt(input, true)]; Skin skin = skeletonData.skins.Items[ReadInt(input, true)];
for (int ii = 0, nn = ReadInt(input, true); ii < nn; ii++) { for (int ii = 0, nn = ReadInt(input, true); ii < nn; ii++) {
int slotIndex = ReadInt(input, true); int slotIndex = ReadInt(input, true);
for (int iii = 0, nnn = ReadInt(input, true); iii < nnn; iii++) { for (int iii = 0, nnn = ReadInt(input, true); iii < nnn; iii++) {
@ -540,7 +540,7 @@ namespace Spine {
EventTimeline timeline = new EventTimeline(eventCount); EventTimeline timeline = new EventTimeline(eventCount);
for (int i = 0; i < eventCount; i++) { for (int i = 0; i < eventCount; i++) {
float time = ReadFloat(input); float time = ReadFloat(input);
EventData eventData = skeletonData.events[ReadInt(input, true)]; EventData eventData = skeletonData.events.Items[ReadInt(input, true)];
Event e = new Event(eventData); Event e = new Event(eventData);
e.Int = ReadInt(input, false); e.Int = ReadInt(input, false);
e.Float = ReadFloat(input); e.Float = ReadFloat(input);

View File

@ -34,11 +34,11 @@ using System.Collections.Generic;
namespace Spine { namespace Spine {
public class SkeletonBounds { public class SkeletonBounds {
private List<Polygon> polygonPool = new List<Polygon>(); private ExposedList<Polygon> polygonPool = new ExposedList<Polygon>();
private float minX, minY, maxX, maxY; private float minX, minY, maxX, maxY;
public List<BoundingBoxAttachment> BoundingBoxes { get; private set; } public ExposedList<BoundingBoxAttachment> BoundingBoxes { get; private set; }
public List<Polygon> Polygons { get; private set; } public ExposedList<Polygon> Polygons { get; private set; }
public float MinX { get { return minX; } set { minX = value; } } public float MinX { get { return minX; } set { minX = value; } }
public float MinY { get { return minY; } set { minY = value; } } public float MinY { get { return minY; } set { minY = value; } }
public float MaxX { get { return maxX; } set { maxX = value; } } public float MaxX { get { return maxX; } set { maxX = value; } }
@ -47,23 +47,23 @@ namespace Spine {
public float Height { get { return maxY - minY; } } public float Height { get { return maxY - minY; } }
public SkeletonBounds () { public SkeletonBounds () {
BoundingBoxes = new List<BoundingBoxAttachment>(); BoundingBoxes = new ExposedList<BoundingBoxAttachment>();
Polygons = new List<Polygon>(); Polygons = new ExposedList<Polygon>();
} }
public void Update (Skeleton skeleton, bool updateAabb) { public void Update (Skeleton skeleton, bool updateAabb) {
List<BoundingBoxAttachment> boundingBoxes = BoundingBoxes; ExposedList<BoundingBoxAttachment> boundingBoxes = BoundingBoxes;
List<Polygon> polygons = Polygons; ExposedList<Polygon> polygons = Polygons;
List<Slot> slots = skeleton.slots; ExposedList<Slot> slots = skeleton.slots;
int slotCount = slots.Count; int slotCount = slots.Count;
boundingBoxes.Clear(); boundingBoxes.Clear();
foreach (Polygon polygon in polygons) for (int i = 0, n = polygons.Count; i < n; i++)
polygonPool.Add(polygon); polygonPool.Add(polygons.Items[i]);
polygons.Clear(); polygons.Clear();
for (int i = 0; i < slotCount; i++) { for (int i = 0; i < slotCount; i++) {
Slot slot = slots[i]; Slot slot = slots.Items[i];
BoundingBoxAttachment boundingBox = slot.attachment as BoundingBoxAttachment; BoundingBoxAttachment boundingBox = slot.attachment as BoundingBoxAttachment;
if (boundingBox == null) continue; if (boundingBox == null) continue;
boundingBoxes.Add(boundingBox); boundingBoxes.Add(boundingBox);
@ -71,7 +71,7 @@ namespace Spine {
Polygon polygon = null; Polygon polygon = null;
int poolCount = polygonPool.Count; int poolCount = polygonPool.Count;
if (poolCount > 0) { if (poolCount > 0) {
polygon = polygonPool[poolCount - 1]; polygon = polygonPool.Items[poolCount - 1];
polygonPool.RemoveAt(poolCount - 1); polygonPool.RemoveAt(poolCount - 1);
} else } else
polygon = new Polygon(); polygon = new Polygon();
@ -88,9 +88,9 @@ namespace Spine {
private void aabbCompute () { private void aabbCompute () {
float minX = int.MaxValue, minY = int.MaxValue, maxX = int.MinValue, maxY = int.MinValue; float minX = int.MaxValue, minY = int.MaxValue, maxX = int.MinValue, maxY = int.MinValue;
List<Polygon> polygons = Polygons; ExposedList<Polygon> polygons = Polygons;
for (int i = 0, n = polygons.Count; i < n; i++) { for (int i = 0, n = polygons.Count; i < n; i++) {
Polygon polygon = polygons[i]; Polygon polygon = polygons.Items[i];
float[] vertices = polygon.Vertices; float[] vertices = polygon.Vertices;
for (int ii = 0, nn = polygon.Count; ii < nn; ii += 2) { for (int ii = 0, nn = polygon.Count; ii < nn; ii += 2) {
float x = vertices[ii]; float x = vertices[ii];
@ -160,18 +160,18 @@ namespace Spine {
/// <summary>Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more /// <summary>Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more
/// efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true.</summary> /// efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true.</summary>
public BoundingBoxAttachment ContainsPoint (float x, float y) { public BoundingBoxAttachment ContainsPoint (float x, float y) {
List<Polygon> polygons = Polygons; ExposedList<Polygon> polygons = Polygons;
for (int i = 0, n = polygons.Count; i < n; i++) for (int i = 0, n = polygons.Count; i < n; i++)
if (ContainsPoint(polygons[i], x, y)) return BoundingBoxes[i]; if (ContainsPoint(polygons.Items[i], x, y)) return BoundingBoxes.Items[i];
return null; return null;
} }
/// <summary>Returns the first bounding box attachment that contains the line segment, or null. When doing many checks, it is usually /// <summary>Returns the first bounding box attachment that contains the line segment, or null. When doing many checks, it is usually
/// more efficient to only call this method if {@link #aabbIntersectsSegment(float, float, float, float)} returns true.</summary> /// more efficient to only call this method if {@link #aabbIntersectsSegment(float, float, float, float)} returns true.</summary>
public BoundingBoxAttachment IntersectsSegment (float x1, float y1, float x2, float y2) { public BoundingBoxAttachment IntersectsSegment (float x1, float y1, float x2, float y2) {
List<Polygon> polygons = Polygons; ExposedList<Polygon> polygons = Polygons;
for (int i = 0, n = polygons.Count; i < n; i++) for (int i = 0, n = polygons.Count; i < n; i++)
if (IntersectsSegment(polygons[i], x1, y1, x2, y2)) return BoundingBoxes[i]; if (IntersectsSegment(polygons.Items[i], x1, y1, x2, y2)) return BoundingBoxes.Items[i];
return null; return null;
} }
@ -201,7 +201,7 @@ namespace Spine {
public Polygon getPolygon (BoundingBoxAttachment attachment) { public Polygon getPolygon (BoundingBoxAttachment attachment) {
int index = BoundingBoxes.IndexOf(attachment); int index = BoundingBoxes.IndexOf(attachment);
return index == -1 ? null : Polygons[index]; return index == -1 ? null : Polygons.Items[index];
} }
} }

View File

@ -35,25 +35,25 @@ using System.Collections.Generic;
namespace Spine { namespace Spine {
public class SkeletonData { public class SkeletonData {
internal String name; internal String name;
internal List<BoneData> bones = new List<BoneData>(); internal ExposedList<BoneData> bones = new ExposedList<BoneData>();
internal List<SlotData> slots = new List<SlotData>(); internal ExposedList<SlotData> slots = new ExposedList<SlotData>();
internal List<Skin> skins = new List<Skin>(); internal ExposedList<Skin> skins = new ExposedList<Skin>();
internal Skin defaultSkin; internal Skin defaultSkin;
internal List<EventData> events = new List<EventData>(); internal ExposedList<EventData> events = new ExposedList<EventData>();
internal List<Animation> animations = new List<Animation>(); internal ExposedList<Animation> animations = new ExposedList<Animation>();
internal List<IkConstraintData> ikConstraints = new List<IkConstraintData>(); internal ExposedList<IkConstraintData> ikConstraints = new ExposedList<IkConstraintData>();
internal float width, height; internal float width, height;
internal String version, hash, imagesPath; internal String version, hash, imagesPath;
public String Name { get { return name; } set { name = value; } } public String Name { get { return name; } set { name = value; } }
public List<BoneData> Bones { get { return bones; } } // Ordered parents first. public ExposedList<BoneData> Bones { get { return bones; } } // Ordered parents first.
public List<SlotData> Slots { get { return slots; } } // Setup pose draw order. public ExposedList<SlotData> Slots { get { return slots; } } // Setup pose draw order.
public List<Skin> Skins { get { return skins; } set { skins = value; } } public ExposedList<Skin> Skins { get { return skins; } set { skins = value; } }
/// <summary>May be null.</summary> /// <summary>May be null.</summary>
public Skin DefaultSkin { get { return defaultSkin; } set { defaultSkin = value; } } public Skin DefaultSkin { get { return defaultSkin; } set { defaultSkin = value; } }
public List<EventData> Events { get { return events; } set { events = value; } } public ExposedList<EventData> Events { get { return events; } set { events = value; } }
public List<Animation> Animations { get { return animations; } set { animations = value; } } public ExposedList<Animation> Animations { get { return animations; } set { animations = value; } }
public List<IkConstraintData> IkConstraints { get { return ikConstraints; } set { ikConstraints = value; } } public ExposedList<IkConstraintData> IkConstraints { get { return ikConstraints; } set { ikConstraints = value; } }
public float Width { get { return width; } set { width = value; } } public float Width { get { return width; } set { width = value; } }
public float Height { get { return height; } set { height = value; } } public float Height { get { return height; } set { height = value; } }
/// <summary>The Spine version used to export this data.</summary> /// <summary>The Spine version used to export this data.</summary>
@ -65,9 +65,9 @@ namespace Spine {
/// <returns>May be null.</returns> /// <returns>May be null.</returns>
public BoneData FindBone (String boneName) { public BoneData FindBone (String boneName) {
if (boneName == null) throw new ArgumentNullException("boneName cannot be null."); if (boneName == null) throw new ArgumentNullException("boneName cannot be null.");
List<BoneData> bones = this.bones; ExposedList<BoneData> bones = this.bones;
for (int i = 0, n = bones.Count; i < n; i++) { for (int i = 0, n = bones.Count; i < n; i++) {
BoneData bone = bones[i]; BoneData bone = bones.Items[i];
if (bone.name == boneName) return bone; if (bone.name == boneName) return bone;
} }
return null; return null;
@ -76,9 +76,9 @@ namespace Spine {
/// <returns>-1 if the bone was not found.</returns> /// <returns>-1 if the bone was not found.</returns>
public int FindBoneIndex (String boneName) { public int FindBoneIndex (String boneName) {
if (boneName == null) throw new ArgumentNullException("boneName cannot be null."); if (boneName == null) throw new ArgumentNullException("boneName cannot be null.");
List<BoneData> bones = this.bones; ExposedList<BoneData> bones = this.bones;
for (int i = 0, n = bones.Count; i < n; i++) for (int i = 0, n = bones.Count; i < n; i++)
if (bones[i].name == boneName) return i; if (bones.Items[i].name == boneName) return i;
return -1; return -1;
} }
@ -87,9 +87,9 @@ namespace Spine {
/// <returns>May be null.</returns> /// <returns>May be null.</returns>
public SlotData FindSlot (String slotName) { public SlotData FindSlot (String slotName) {
if (slotName == null) throw new ArgumentNullException("slotName cannot be null."); if (slotName == null) throw new ArgumentNullException("slotName cannot be null.");
List<SlotData> slots = this.slots; ExposedList<SlotData> slots = this.slots;
for (int i = 0, n = slots.Count; i < n; i++) { for (int i = 0, n = slots.Count; i < n; i++) {
SlotData slot = slots[i]; SlotData slot = slots.Items[i];
if (slot.name == slotName) return slot; if (slot.name == slotName) return slot;
} }
return null; return null;
@ -98,9 +98,9 @@ namespace Spine {
/// <returns>-1 if the bone was not found.</returns> /// <returns>-1 if the bone was not found.</returns>
public int FindSlotIndex (String slotName) { public int FindSlotIndex (String slotName) {
if (slotName == null) throw new ArgumentNullException("slotName cannot be null."); if (slotName == null) throw new ArgumentNullException("slotName cannot be null.");
List<SlotData> slots = this.slots; ExposedList<SlotData> slots = this.slots;
for (int i = 0, n = slots.Count; i < n; i++) for (int i = 0, n = slots.Count; i < n; i++)
if (slots[i].name == slotName) return i; if (slots.Items[i].name == slotName) return i;
return -1; return -1;
} }
@ -129,9 +129,9 @@ namespace Spine {
/// <returns>May be null.</returns> /// <returns>May be null.</returns>
public Animation FindAnimation (String animationName) { public Animation FindAnimation (String animationName) {
if (animationName == null) throw new ArgumentNullException("animationName cannot be null."); if (animationName == null) throw new ArgumentNullException("animationName cannot be null.");
List<Animation> animations = this.animations; ExposedList<Animation> animations = this.animations;
for (int i = 0, n = animations.Count; i < n; i++) { for (int i = 0, n = animations.Count; i < n; i++) {
Animation animation = animations[i]; Animation animation = animations.Items[i];
if (animation.name == animationName) return animation; if (animation.name == animationName) return animation;
} }
return null; return null;
@ -142,9 +142,9 @@ namespace Spine {
/// <returns>May be null.</returns> /// <returns>May be null.</returns>
public IkConstraintData FindIkConstraint (String ikConstraintName) { public IkConstraintData FindIkConstraint (String ikConstraintName) {
if (ikConstraintName == null) throw new ArgumentNullException("ikConstraintName cannot be null."); if (ikConstraintName == null) throw new ArgumentNullException("ikConstraintName cannot be null.");
List<IkConstraintData> ikConstraints = this.ikConstraints; ExposedList<IkConstraintData> ikConstraints = this.ikConstraints;
for (int i = 0, n = ikConstraints.Count; i < n; i++) { for (int i = 0, n = ikConstraints.Count; i < n; i++) {
IkConstraintData ikConstraint = ikConstraints[i]; IkConstraintData ikConstraint = ikConstraints.Items[i];
if (ikConstraint.name == ikConstraintName) return ikConstraint; if (ikConstraint.name == ikConstraintName) return ikConstraint;
} }
return null; return null;

View File

@ -380,7 +380,7 @@ namespace Spine {
} }
private void ReadAnimation (String name, Dictionary<String, Object> map, SkeletonData skeletonData) { private void ReadAnimation (String name, Dictionary<String, Object> map, SkeletonData skeletonData) {
var timelines = new List<Timeline>(); var timelines = new ExposedList<Timeline>();
float duration = 0; float duration = 0;
float scale = Scale; float scale = Scale;

View File

@ -36,8 +36,8 @@ namespace Spine {
/// <summary>Stores attachments by slot index and attachment name.</summary> /// <summary>Stores attachments by slot index and attachment name.</summary>
public class Skin { public class Skin {
internal String name; internal String name;
private Dictionary<KeyValuePair<int, String>, Attachment> attachments = private Dictionary<AttachmentKeyTuple, Attachment> attachments =
new Dictionary<KeyValuePair<int, String>, Attachment>(AttachmentComparer.Instance); new Dictionary<AttachmentKeyTuple, Attachment>(AttachmentKeyTupleComparer.Instance);
public String Name { get { return name; } } public String Name { get { return name; } }
@ -48,26 +48,26 @@ namespace Spine {
public void AddAttachment (int slotIndex, String name, Attachment attachment) { public void AddAttachment (int slotIndex, String name, Attachment attachment) {
if (attachment == null) throw new ArgumentNullException("attachment cannot be null."); if (attachment == null) throw new ArgumentNullException("attachment cannot be null.");
attachments[new KeyValuePair<int, String>(slotIndex, name)] = attachment; attachments[new AttachmentKeyTuple(slotIndex, name)] = attachment;
} }
/// <returns>May be null.</returns> /// <returns>May be null.</returns>
public Attachment GetAttachment (int slotIndex, String name) { public Attachment GetAttachment (int slotIndex, String name) {
Attachment attachment; Attachment attachment;
attachments.TryGetValue(new KeyValuePair<int, String>(slotIndex, name), out attachment); attachments.TryGetValue(new AttachmentKeyTuple(slotIndex, name), out attachment);
return attachment; return attachment;
} }
public void FindNamesForSlot (int slotIndex, List<String> names) { public void FindNamesForSlot (int slotIndex, List<String> names) {
if (names == null) throw new ArgumentNullException("names cannot be null."); if (names == null) throw new ArgumentNullException("names cannot be null.");
foreach (KeyValuePair<int, String> key in attachments.Keys) foreach (AttachmentKeyTuple key in attachments.Keys)
if (key.Key == slotIndex) names.Add(key.Value); if (key.SlotIndex == slotIndex) names.Add(key.Name);
} }
public void FindAttachmentsForSlot (int slotIndex, List<Attachment> attachments) { public void FindAttachmentsForSlot (int slotIndex, List<Attachment> attachments) {
if (attachments == null) throw new ArgumentNullException("attachments cannot be null."); if (attachments == null) throw new ArgumentNullException("attachments cannot be null.");
foreach (KeyValuePair<KeyValuePair<int, String>, Attachment> entry in this.attachments) foreach (KeyValuePair<AttachmentKeyTuple, Attachment> entry in this.attachments)
if (entry.Key.Key == slotIndex) attachments.Add(entry.Value); if (entry.Key.SlotIndex == slotIndex) attachments.Add(entry.Value);
} }
override public String ToString () { override public String ToString () {
@ -76,27 +76,39 @@ namespace Spine {
/// <summary>Attach all attachments from this skin if the corresponding attachment from the old skin is currently attached.</summary> /// <summary>Attach all attachments from this skin if the corresponding attachment from the old skin is currently attached.</summary>
internal void AttachAll (Skeleton skeleton, Skin oldSkin) { internal void AttachAll (Skeleton skeleton, Skin oldSkin) {
foreach (KeyValuePair<KeyValuePair<int, String>, Attachment> entry in oldSkin.attachments) { foreach (KeyValuePair<AttachmentKeyTuple, Attachment> entry in oldSkin.attachments) {
int slotIndex = entry.Key.Key; int slotIndex = entry.Key.SlotIndex;
Slot slot = skeleton.slots[slotIndex]; Slot slot = skeleton.slots.Items[slotIndex];
if (slot.attachment == entry.Value) { if (slot.attachment == entry.Value) {
Attachment attachment = GetAttachment(slotIndex, entry.Key.Value); Attachment attachment = GetAttachment(slotIndex, entry.Key.Name);
if (attachment != null) slot.Attachment = attachment; if (attachment != null) slot.Attachment = attachment;
} }
} }
} }
// Avoids boxing in the dictionary. // Avoids boxing in the dictionary.
private class AttachmentComparer : IEqualityComparer<KeyValuePair<int, String>> { private class AttachmentKeyTupleComparer : IEqualityComparer<AttachmentKeyTuple> {
internal static readonly AttachmentComparer Instance = new AttachmentComparer(); internal static readonly AttachmentKeyTupleComparer Instance = new AttachmentKeyTupleComparer();
bool IEqualityComparer<KeyValuePair<int, string>>.Equals (KeyValuePair<int, string> o1, KeyValuePair<int, string> o2) { bool IEqualityComparer<AttachmentKeyTuple>.Equals (AttachmentKeyTuple o1, AttachmentKeyTuple o2) {
return o1.Key == o2.Key && o1.Value == o2.Value; return o1.SlotIndex == o2.SlotIndex && o1.NameHashCode == o2.NameHashCode && o1.Name == o2.Name;
} }
int IEqualityComparer<KeyValuePair<int, string>>.GetHashCode (KeyValuePair<int, string> o) { int IEqualityComparer<AttachmentKeyTuple>.GetHashCode (AttachmentKeyTuple o) {
return o.Key; return o.SlotIndex;
} }
} }
private class AttachmentKeyTuple {
public readonly int SlotIndex;
public readonly string Name;
public readonly int NameHashCode;
public AttachmentKeyTuple(int slotIndex, string name) {
SlotIndex = slotIndex;
Name = name;
NameHashCode = Name.GetHashCode();
}
}
} }
} }

View File

@ -77,7 +77,7 @@ public class SkeletonAnimationInspector : SkeletonRendererInspector {
animations[0] = "<None>"; animations[0] = "<None>";
int animationIndex = 0; int animationIndex = 0;
for (int i = 0; i < animations.Length - 1; i++) { for (int i = 0; i < animations.Length - 1; i++) {
String name = component.skeleton.Data.Animations[i].Name; String name = component.skeleton.Data.Animations.Items[i].Name;
animations[i + 1] = name; animations[i + 1] = name;
if (name == animationName.stringValue) if (name == animationName.stringValue)
animationIndex = i + 1; animationIndex = i + 1;

View File

@ -49,7 +49,7 @@ public static class SkeletonBaker {
/// </summary> /// </summary>
const float bakeIncrement = 1 / 60f; const float bakeIncrement = 1 / 60f;
public static void BakeToPrefab (SkeletonDataAsset skeletonDataAsset, List<Skin> skins, string outputPath = "", bool bakeAnimations = true, bool bakeIK = true, SendMessageOptions eventOptions = SendMessageOptions.DontRequireReceiver) { public static void BakeToPrefab (SkeletonDataAsset skeletonDataAsset, ExposedList<Skin> skins, string outputPath = "", bool bakeAnimations = true, bool bakeIK = true, SendMessageOptions eventOptions = SendMessageOptions.DontRequireReceiver) {
if (skeletonDataAsset == null || skeletonDataAsset.GetSkeletonData(true) == null) { if (skeletonDataAsset == null || skeletonDataAsset.GetSkeletonData(true) == null) {
Debug.LogError("Could not export Spine Skeleton because SkeletonDataAsset is null or invalid!"); Debug.LogError("Could not export Spine Skeleton because SkeletonDataAsset is null or invalid!");
return; return;
@ -108,7 +108,7 @@ public static class SkeletonBaker {
for (int s = 0; s < skeletonData.Slots.Count; s++) { for (int s = 0; s < skeletonData.Slots.Count; s++) {
List<string> attachmentNames = new List<string>(); List<string> attachmentNames = new List<string>();
for (int i = 0; i < skinCount; i++) { for (int i = 0; i < skinCount; i++) {
var skin = skins[i]; var skin = skins.Items[i];
List<string> temp = new List<string>(); List<string> temp = new List<string>();
skin.FindNamesForSlot(s, temp); skin.FindNamesForSlot(s, temp);
foreach (string str in temp) { foreach (string str in temp) {
@ -189,7 +189,7 @@ public static class SkeletonBaker {
//create bones //create bones
for (int i = 0; i < skeletonData.Bones.Count; i++) { for (int i = 0; i < skeletonData.Bones.Count; i++) {
var boneData = skeletonData.Bones[i]; var boneData = skeletonData.Bones.Items[i];
Transform boneTransform = new GameObject(boneData.Name).transform; Transform boneTransform = new GameObject(boneData.Name).transform;
boneTransform.parent = prefabRoot.transform; boneTransform.parent = prefabRoot.transform;
boneTable.Add(boneTransform.name, boneTransform); boneTable.Add(boneTransform.name, boneTransform);
@ -198,7 +198,7 @@ public static class SkeletonBaker {
for (int i = 0; i < skeletonData.Bones.Count; i++) { for (int i = 0; i < skeletonData.Bones.Count; i++) {
var boneData = skeletonData.Bones[i]; var boneData = skeletonData.Bones.Items[i];
Transform boneTransform = boneTable[boneData.Name]; Transform boneTransform = boneTable[boneData.Name];
Transform parentTransform = null; Transform parentTransform = null;
if (i > 0) if (i > 0)
@ -219,7 +219,7 @@ public static class SkeletonBaker {
//create slots and attachments //create slots and attachments
for (int i = 0; i < skeletonData.Slots.Count; i++) { for (int i = 0; i < skeletonData.Slots.Count; i++) {
var slotData = skeletonData.Slots[i]; var slotData = skeletonData.Slots.Items[i];
Transform slotTransform = new GameObject(slotData.Name).transform; Transform slotTransform = new GameObject(slotData.Name).transform;
slotTransform.parent = prefabRoot.transform; slotTransform.parent = prefabRoot.transform;
slotTable.Add(slotData.Name, slotTransform); slotTable.Add(slotData.Name, slotTransform);
@ -615,7 +615,7 @@ public static class SkeletonBaker {
skeleton.UpdateWorldTransform(); skeleton.UpdateWorldTransform();
float[] floatVerts = new float[attachment.UVs.Length]; float[] floatVerts = new float[attachment.UVs.Length];
attachment.ComputeWorldVertices(skeleton.Slots[slotIndex], floatVerts); attachment.ComputeWorldVertices(skeleton.Slots.Items[slotIndex], floatVerts);
Vector2[] uvs = ExtractUV(attachment.UVs); Vector2[] uvs = ExtractUV(attachment.UVs);
Vector3[] verts = ExtractVerts(floatVerts); Vector3[] verts = ExtractVerts(floatVerts);
@ -887,8 +887,8 @@ public static class SkeletonBaker {
static void ParseAttachmentTimeline (Skeleton skeleton, AttachmentTimeline timeline, Dictionary<int, List<string>> slotLookup, AnimationClip clip) { static void ParseAttachmentTimeline (Skeleton skeleton, AttachmentTimeline timeline, Dictionary<int, List<string>> slotLookup, AnimationClip clip) {
var attachmentNames = slotLookup[timeline.SlotIndex]; var attachmentNames = slotLookup[timeline.SlotIndex];
string bonePath = GetPath(skeleton.Slots[timeline.SlotIndex].Bone.Data); string bonePath = GetPath(skeleton.Slots.Items[timeline.SlotIndex].Bone.Data);
string slotPath = bonePath + "/" + skeleton.Slots[timeline.SlotIndex].Data.Name; string slotPath = bonePath + "/" + skeleton.Slots.Items[timeline.SlotIndex].Data.Name;
Dictionary<string, AnimationCurve> curveTable = new Dictionary<string, AnimationCurve>(); Dictionary<string, AnimationCurve> curveTable = new Dictionary<string, AnimationCurve>();
@ -899,7 +899,7 @@ public static class SkeletonBaker {
float[] frames = timeline.Frames; float[] frames = timeline.Frames;
if (frames[0] != 0) { if (frames[0] != 0) {
string startingName = skeleton.Slots[timeline.SlotIndex].Data.AttachmentName; string startingName = skeleton.Slots.Items[timeline.SlotIndex].Data.AttachmentName;
foreach (var pair in curveTable) { foreach (var pair in curveTable) {
if (startingName == "" || startingName == null) { if (startingName == "" || startingName == null) {
pair.Value.AddKey(new Keyframe(0, 0, float.PositiveInfinity, float.PositiveInfinity)); pair.Value.AddKey(new Keyframe(0, 0, float.PositiveInfinity, float.PositiveInfinity));
@ -1037,8 +1037,8 @@ public static class SkeletonBaker {
} }
static void ParseTranslateTimeline (Skeleton skeleton, TranslateTimeline timeline, AnimationClip clip) { static void ParseTranslateTimeline (Skeleton skeleton, TranslateTimeline timeline, AnimationClip clip) {
var boneData = skeleton.Data.Bones[timeline.BoneIndex]; var boneData = skeleton.Data.Bones.Items[timeline.BoneIndex];
var bone = skeleton.Bones[timeline.BoneIndex]; var bone = skeleton.Bones.Items[timeline.BoneIndex];
AnimationCurve xCurve = new AnimationCurve(); AnimationCurve xCurve = new AnimationCurve();
AnimationCurve yCurve = new AnimationCurve(); AnimationCurve yCurve = new AnimationCurve();
@ -1183,8 +1183,8 @@ public static class SkeletonBaker {
} }
static void ParseScaleTimeline (Skeleton skeleton, ScaleTimeline timeline, AnimationClip clip) { static void ParseScaleTimeline (Skeleton skeleton, ScaleTimeline timeline, AnimationClip clip) {
var boneData = skeleton.Data.Bones[timeline.BoneIndex]; var boneData = skeleton.Data.Bones.Items[timeline.BoneIndex];
var bone = skeleton.Bones[timeline.BoneIndex]; var bone = skeleton.Bones.Items[timeline.BoneIndex];
AnimationCurve xCurve = new AnimationCurve(); AnimationCurve xCurve = new AnimationCurve();
AnimationCurve yCurve = new AnimationCurve(); AnimationCurve yCurve = new AnimationCurve();
@ -1316,8 +1316,8 @@ public static class SkeletonBaker {
} }
static void ParseRotateTimeline (Skeleton skeleton, RotateTimeline timeline, AnimationClip clip) { static void ParseRotateTimeline (Skeleton skeleton, RotateTimeline timeline, AnimationClip clip) {
var boneData = skeleton.Data.Bones[timeline.BoneIndex]; var boneData = skeleton.Data.Bones.Items[timeline.BoneIndex];
var bone = skeleton.Bones[timeline.BoneIndex]; var bone = skeleton.Bones.Items[timeline.BoneIndex];
AnimationCurve curve = new AnimationCurve(); AnimationCurve curve = new AnimationCurve();

View File

@ -186,7 +186,7 @@ public class SkeletonDataAssetInspector : Editor {
Skin bakeSkin = m_skeletonAnimation.skeleton.Skin; Skin bakeSkin = m_skeletonAnimation.skeleton.Skin;
if (bakeSkin == null) { if (bakeSkin == null) {
skinName = "Default"; skinName = "Default";
bakeSkin = m_skeletonData.Skins[0]; bakeSkin = m_skeletonData.Skins.Items[0];
} else } else
skinName = m_skeletonAnimation.skeleton.Skin.Name; skinName = m_skeletonAnimation.skeleton.Skin.Name;
@ -195,7 +195,7 @@ public class SkeletonDataAssetInspector : Editor {
try { try {
GUILayout.BeginVertical(); GUILayout.BeginVertical();
if (GUILayout.Button(new GUIContent("Bake " + skinName, SpineEditorUtilities.Icons.unityIcon), GUILayout.Height(32), GUILayout.Width(250))) if (GUILayout.Button(new GUIContent("Bake " + skinName, SpineEditorUtilities.Icons.unityIcon), GUILayout.Height(32), GUILayout.Width(250)))
SkeletonBaker.BakeToPrefab(m_skeletonDataAsset, new List<Skin>(new Skin[] { bakeSkin }), "", bakeAnimations, bakeIK, bakeEventOptions); SkeletonBaker.BakeToPrefab(m_skeletonDataAsset, new ExposedList<Skin>(new Skin[] { bakeSkin }), "", bakeAnimations, bakeIK, bakeEventOptions);
GUILayout.BeginHorizontal(); GUILayout.BeginHorizontal();
GUILayout.Label(new GUIContent("Skins", SpineEditorUtilities.Icons.skinsRoot), GUILayout.Width(50)); GUILayout.Label(new GUIContent("Skins", SpineEditorUtilities.Icons.skinsRoot), GUILayout.Width(50));
@ -259,7 +259,7 @@ public class SkeletonDataAssetInspector : Editor {
// Animation names // Animation names
String[] animations = new String[m_skeletonData.Animations.Count]; String[] animations = new String[m_skeletonData.Animations.Count];
for (int i = 0; i < animations.Length; i++) for (int i = 0; i < animations.Length; i++)
animations[i] = m_skeletonData.Animations[i].Name; animations[i] = m_skeletonData.Animations.Items[i].Name;
for (int i = 0; i < fromAnimation.arraySize; i++) { for (int i = 0; i < fromAnimation.arraySize; i++) {
SerializedProperty from = fromAnimation.GetArrayElementAtIndex(i); SerializedProperty from = fromAnimation.GetArrayElementAtIndex(i);
@ -350,14 +350,14 @@ public class SkeletonDataAssetInspector : Editor {
List<Attachment> slotAttachments = new List<Attachment>(); List<Attachment> slotAttachments = new List<Attachment>();
List<string> slotAttachmentNames = new List<string>(); List<string> slotAttachmentNames = new List<string>();
List<string> defaultSkinAttachmentNames = new List<string>(); List<string> defaultSkinAttachmentNames = new List<string>();
var defaultSkin = m_skeletonData.Skins[0]; var defaultSkin = m_skeletonData.Skins.Items[0];
Skin skin = m_skeletonAnimation.skeleton.Skin; Skin skin = m_skeletonAnimation.skeleton.Skin;
if (skin == null) { if (skin == null) {
skin = defaultSkin; skin = defaultSkin;
} }
for (int i = m_skeletonAnimation.skeleton.Slots.Count - 1; i >= 0; i--) { for (int i = m_skeletonAnimation.skeleton.Slots.Count - 1; i >= 0; i--) {
Slot slot = m_skeletonAnimation.skeleton.Slots[i]; Slot slot = m_skeletonAnimation.skeleton.Slots.Items[i];
EditorGUILayout.LabelField(new GUIContent(slot.Data.Name, SpineEditorUtilities.Icons.slot)); EditorGUILayout.LabelField(new GUIContent(slot.Data.Name, SpineEditorUtilities.Icons.slot));
if (showAttachments) { if (showAttachments) {

View File

@ -92,7 +92,7 @@ public class SkeletonRendererInspector : Editor {
String[] skins = new String[component.skeleton.Data.Skins.Count]; String[] skins = new String[component.skeleton.Data.Skins.Count];
int skinIndex = 0; int skinIndex = 0;
for (int i = 0; i < skins.Length; i++) { for (int i = 0; i < skins.Length; i++) {
String name = component.skeleton.Data.Skins[i].Name; String name = component.skeleton.Data.Skins.Items[i].Name;
skins[i] = name; skins[i] = name;
if (name == initialSkinName.stringValue) if (name == initialSkinName.stringValue)
skinIndex = i; skinIndex = i;

View File

@ -85,7 +85,7 @@ public class SpineSlotDrawer : PropertyDrawer {
menu.AddSeparator(""); menu.AddSeparator("");
for (int i = 0; i < data.Slots.Count; i++) { for (int i = 0; i < data.Slots.Count; i++) {
string name = data.Slots[i].Name; string name = data.Slots.Items[i].Name;
if (name.StartsWith(attrib.startsWith)) { if (name.StartsWith(attrib.startsWith)) {
if (attrib.containsBoundingBoxes) { if (attrib.containsBoundingBoxes) {
@ -190,7 +190,7 @@ public class SpineSkinDrawer : PropertyDrawer {
menu.AddSeparator(""); menu.AddSeparator("");
for (int i = 0; i < data.Skins.Count; i++) { for (int i = 0; i < data.Skins.Count; i++) {
string name = data.Skins[i].Name; string name = data.Skins.Items[i].Name;
if (name.StartsWith(attrib.startsWith)) if (name.StartsWith(attrib.startsWith))
menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property));
} }
@ -330,7 +330,7 @@ public class SpineAnimationDrawer : PropertyDrawer {
var animations = skeletonDataAsset.GetAnimationStateData().SkeletonData.Animations; var animations = skeletonDataAsset.GetAnimationStateData().SkeletonData.Animations;
for (int i = 0; i < animations.Count; i++) { for (int i = 0; i < animations.Count; i++) {
string name = animations[i].Name; string name = animations.Items[i].Name;
if (name.StartsWith(attrib.startsWith)) if (name.StartsWith(attrib.startsWith))
menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property));
} }
@ -416,7 +416,7 @@ public class SpineAttachmentDrawer : PropertyDrawer {
if (skeletonRenderer.skeleton.Skin != null) { if (skeletonRenderer.skeleton.Skin != null) {
validSkins.Add(skeletonRenderer.skeleton.Skin); validSkins.Add(skeletonRenderer.skeleton.Skin);
} else { } else {
validSkins.Add(data.Skins[0]); validSkins.Add(data.Skins.Items[0]);
} }
} else { } else {
foreach (Skin skin in data.Skins) { foreach (Skin skin in data.Skins) {
@ -440,7 +440,7 @@ public class SpineAttachmentDrawer : PropertyDrawer {
menu.AddItem(new GUIContent("Null"), property.stringValue == "", HandleSelect, new SpineDrawerValuePair("", property)); menu.AddItem(new GUIContent("Null"), property.stringValue == "", HandleSelect, new SpineDrawerValuePair("", property));
menu.AddSeparator(""); menu.AddSeparator("");
Skin defaultSkin = data.Skins[0]; Skin defaultSkin = data.Skins.Items[0];
SerializedProperty slotProperty = property.serializedObject.FindProperty(attrib.slotField); SerializedProperty slotProperty = property.serializedObject.FindProperty(attrib.slotField);
string slotMatch = ""; string slotMatch = "";
@ -457,7 +457,7 @@ public class SpineAttachmentDrawer : PropertyDrawer {
prefix = skinPrefix; prefix = skinPrefix;
for (int i = 0; i < data.Slots.Count; i++) { for (int i = 0; i < data.Slots.Count; i++) {
if (slotMatch.Length > 0 && data.Slots[i].Name.ToLower().Contains(slotMatch) == false) if (slotMatch.Length > 0 && data.Slots.Items[i].Name.ToLower().Contains(slotMatch) == false)
continue; continue;
attachmentNames.Clear(); attachmentNames.Clear();
@ -473,11 +473,11 @@ public class SpineAttachmentDrawer : PropertyDrawer {
for (int a = 0; a < attachmentNames.Count; a++) { for (int a = 0; a < attachmentNames.Count; a++) {
string attachmentPath = attachmentNames[a]; string attachmentPath = attachmentNames[a];
string menuPath = prefix + data.Slots[i].Name + "/" + attachmentPath; string menuPath = prefix + data.Slots.Items[i].Name + "/" + attachmentPath;
string name = attachmentNames[a]; string name = attachmentNames[a];
if (attrib.returnAttachmentPath) if (attrib.returnAttachmentPath)
name = skin.Name + "/" + data.Slots[i].Name + "/" + attachmentPath; name = skin.Name + "/" + data.Slots.Items[i].Name + "/" + attachmentPath;
if (attrib.placeholdersOnly && placeholderNames.Contains(attachmentPath) == false) { if (attrib.placeholdersOnly && placeholderNames.Contains(attachmentPath) == false) {
menu.AddDisabledItem(new GUIContent(menuPath)); menu.AddDisabledItem(new GUIContent(menuPath));
@ -564,7 +564,7 @@ public class SpineBoneDrawer : PropertyDrawer {
menu.AddSeparator(""); menu.AddSeparator("");
for (int i = 0; i < data.Bones.Count; i++) { for (int i = 0; i < data.Bones.Count; i++) {
string name = data.Bones[i].Name; string name = data.Bones.Items[i].Name;
if (name.StartsWith(attrib.startsWith)) if (name.StartsWith(attrib.startsWith))
menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property)); menu.AddItem(new GUIContent(name), name == property.stringValue, HandleSelect, new SpineDrawerValuePair(name, property));
} }

View File

@ -949,7 +949,7 @@ public class SpineEditorUtilities : AssetPostprocessor {
skin = data.DefaultSkin; skin = data.DefaultSkin;
if (skin == null) if (skin == null)
skin = data.Skins[0]; skin = data.Skins.Items[0];
anim.Reset(); anim.Reset();
@ -1035,7 +1035,7 @@ public class SpineEditorUtilities : AssetPostprocessor {
skin = data.DefaultSkin; skin = data.DefaultSkin;
if (skin == null) if (skin == null)
skin = data.Skins[0]; skin = data.Skins.Items[0];
anim.Reset(); anim.Reset();

View File

@ -280,7 +280,7 @@ public class SkeletonRagdoll2D : MonoBehaviour {
if (colliders.Count == 0) { if (colliders.Count == 0) {
var box = go.AddComponent<BoxCollider2D>(); var box = go.AddComponent<BoxCollider2D>();
box.size = new Vector2(length, thickness); box.size = new Vector2(length, thickness);
#if UNITY_5_0 #if UNITY_5
box.offset = new Vector2((b.WorldFlipX ? -length : length) / 2, 0); box.offset = new Vector2((b.WorldFlipX ? -length : length) / 2, 0);
#else #else
box.center = new Vector2((b.WorldFlipX ? -length : length) / 2, 0); box.center = new Vector2((b.WorldFlipX ? -length : length) / 2, 0);

View File

@ -44,7 +44,8 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
} }
} }
Dictionary<string, Spine.Animation> animationTable = new Dictionary<string, Spine.Animation>(); Dictionary<int, Spine.Animation> animationTable = new Dictionary<int, Spine.Animation>();
Dictionary<AnimationClip, int> clipNameHashCodeTable = new Dictionary<AnimationClip, int>();
Animator animator; Animator animator;
float lastTime; float lastTime;
@ -54,11 +55,12 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
return; return;
animationTable.Clear(); animationTable.Clear();
clipNameHashCodeTable.Clear();
var data = skeletonDataAsset.GetSkeletonData(true); var data = skeletonDataAsset.GetSkeletonData(true);
foreach (var a in data.Animations) { foreach (var a in data.Animations) {
animationTable.Add(a.Name, a); animationTable.Add(a.Name.GetHashCode(), a);
} }
animator = GetComponent<Animator>(); animator = GetComponent<Animator>();
@ -106,7 +108,7 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
continue; continue;
float time = stateInfo.normalizedTime * info.clip.length; float time = stateInfo.normalizedTime * info.clip.length;
animationTable[info.clip.name].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, stateInfo.loop, null, weight); animationTable[GetAnimationClipNameHashCode(info.clip)].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, stateInfo.loop, null, weight);
} }
foreach (var info in nextClipInfo) { foreach (var info in nextClipInfo) {
@ -115,7 +117,7 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
continue; continue;
float time = nextStateInfo.normalizedTime * info.clip.length; float time = nextStateInfo.normalizedTime * info.clip.length;
animationTable[info.clip.name].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, nextStateInfo.loop, null, weight); animationTable[GetAnimationClipNameHashCode(info.clip)].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, nextStateInfo.loop, null, weight);
} }
} else if (mode >= MixMode.MixNext) { } else if (mode >= MixMode.MixNext) {
//apply first non-zero weighted clip //apply first non-zero weighted clip
@ -128,7 +130,7 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
continue; continue;
float time = stateInfo.normalizedTime * info.clip.length; float time = stateInfo.normalizedTime * info.clip.length;
animationTable[info.clip.name].Apply(skeleton, Mathf.Max(0, time - deltaTime), time, stateInfo.loop, null); animationTable[GetAnimationClipNameHashCode(info.clip)].Apply(skeleton, Mathf.Max(0, time - deltaTime), time, stateInfo.loop, null);
break; break;
} }
@ -140,7 +142,7 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
continue; continue;
float time = stateInfo.normalizedTime * info.clip.length; float time = stateInfo.normalizedTime * info.clip.length;
animationTable[info.clip.name].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, stateInfo.loop, null, weight); animationTable[GetAnimationClipNameHashCode(info.clip)].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, stateInfo.loop, null, weight);
} }
c = 0; c = 0;
@ -154,7 +156,7 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
continue; continue;
float time = nextStateInfo.normalizedTime * info.clip.length; float time = nextStateInfo.normalizedTime * info.clip.length;
animationTable[info.clip.name].Apply(skeleton, Mathf.Max(0, time - deltaTime), time, nextStateInfo.loop, null); animationTable[GetAnimationClipNameHashCode(info.clip)].Apply(skeleton, Mathf.Max(0, time - deltaTime), time, nextStateInfo.loop, null);
break; break;
} }
} }
@ -167,7 +169,7 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
continue; continue;
float time = nextStateInfo.normalizedTime * info.clip.length; float time = nextStateInfo.normalizedTime * info.clip.length;
animationTable[info.clip.name].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, nextStateInfo.loop, null, weight); animationTable[GetAnimationClipNameHashCode(info.clip)].Mix(skeleton, Mathf.Max(0, time - deltaTime), time, nextStateInfo.loop, null, weight);
} }
} }
} }
@ -188,4 +190,14 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
lastTime = Time.time; lastTime = Time.time;
} }
private int GetAnimationClipNameHashCode(AnimationClip clip) {
int clipNameHashCode;
if (!clipNameHashCodeTable.TryGetValue(clip, out clipNameHashCode)) {
clipNameHashCode = clip.name.GetHashCode();
clipNameHashCodeTable.Add(clip, clipNameHashCode);
}
return clipNameHashCode;
}
} }

View File

@ -30,7 +30,6 @@
*****************************************************************************/ *****************************************************************************/
using System; using System;
using System.IO;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
using Spine; using Spine;
@ -65,14 +64,14 @@ public class SkeletonRenderer : MonoBehaviour {
private Mesh mesh1, mesh2; private Mesh mesh1, mesh2;
private bool useMesh1; private bool useMesh1;
private float[] tempVertices = new float[8]; private float[] tempVertices = new float[8];
private int lastVertexCount;
private Vector3[] vertices; private Vector3[] vertices;
private Color32[] colors; private Color32[] colors;
private Vector2[] uvs; private Vector2[] uvs;
private Material[] sharedMaterials = new Material[0]; private Material[] sharedMaterials = new Material[0];
private readonly List<Material> submeshMaterials = new List<Material>(); private readonly ExposedList<Material> submeshMaterials = new ExposedList<Material>();
private readonly List<Submesh> submeshes = new List<Submesh>(); private readonly ExposedList<Submesh> submeshes = new ExposedList<Submesh>();
private SkeletonUtilitySubmeshRenderer[] submeshRenderers; private SkeletonUtilitySubmeshRenderer[] submeshRenderers;
private LastState lastState = new LastState();
public virtual void Reset () { public virtual void Reset () {
if (meshFilter != null) if (meshFilter != null)
@ -95,9 +94,9 @@ public class SkeletonRenderer : MonoBehaviour {
DestroyImmediate(mesh2); DestroyImmediate(mesh2);
} }
lastState = new LastState();
mesh1 = null; mesh1 = null;
mesh2 = null; mesh2 = null;
lastVertexCount = 0;
vertices = null; vertices = null;
colors = null; colors = null;
uvs = null; uvs = null;
@ -119,6 +118,7 @@ public class SkeletonRenderer : MonoBehaviour {
valid = true; valid = true;
meshFilter = GetComponent<MeshFilter>(); meshFilter = GetComponent<MeshFilter>();
meshRenderer = GetComponent<MeshRenderer>();
mesh1 = newMesh(); mesh1 = newMesh();
mesh2 = newMesh(); mesh2 = newMesh();
vertices = new Vector3[0]; vertices = new Vector3[0];
@ -178,40 +178,67 @@ public class SkeletonRenderer : MonoBehaviour {
public virtual void LateUpdate () { public virtual void LateUpdate () {
if (!valid) if (!valid)
return; return;
// Exit early if there is nothing to render
if (!meshRenderer.enabled && submeshRenderers.Length == 0)
return;
// Count vertices and submesh triangles. // Count vertices and submesh triangles.
int vertexCount = 0; int vertexCount = 0;
int submeshTriangleCount = 0, submeshFirstVertex = 0, submeshStartSlotIndex = 0; int submeshTriangleCount = 0, submeshFirstVertex = 0, submeshStartSlotIndex = 0;
Material lastMaterial = null; Material lastMaterial = null;
submeshMaterials.Clear(); ExposedList<Slot> drawOrder = skeleton.drawOrder;
List<Slot> drawOrder = skeleton.DrawOrder;
int drawOrderCount = drawOrder.Count; int drawOrderCount = drawOrder.Count;
int submeshSeparatorSlotsCount = submeshSeparatorSlots.Count;
bool renderMeshes = this.renderMeshes; bool renderMeshes = this.renderMeshes;
// Clear last state of attachments and submeshes
ExposedList<int> attachmentsTriangleCountTemp = lastState.attachmentsTriangleCountTemp;
attachmentsTriangleCountTemp.GrowIfNeeded(drawOrderCount);
attachmentsTriangleCountTemp.Count = drawOrderCount;
ExposedList<bool> attachmentsFlipStateTemp = lastState.attachmentsFlipStateTemp;
attachmentsFlipStateTemp.GrowIfNeeded(drawOrderCount);
attachmentsFlipStateTemp.Count = drawOrderCount;
ExposedList<LastState.AddSubmeshArguments> addSubmeshArgumentsTemp = lastState.addSubmeshArgumentsTemp;
addSubmeshArgumentsTemp.Clear(false);
for (int i = 0; i < drawOrderCount; i++) { for (int i = 0; i < drawOrderCount; i++) {
Slot slot = drawOrder[i]; Slot slot = drawOrder.Items[i];
Bone bone = slot.bone;
Attachment attachment = slot.attachment; Attachment attachment = slot.attachment;
object rendererObject; object rendererObject;
int attachmentVertexCount, attachmentTriangleCount; int attachmentVertexCount, attachmentTriangleCount;
bool worldScaleXIsPositive = bone.worldScaleX >= 0f;
bool worldScaleYIsPositive = bone.worldScaleY >= 0f;
bool worldScaleIsSameSigns = (worldScaleXIsPositive && worldScaleYIsPositive) ||
(!worldScaleXIsPositive && !worldScaleYIsPositive);
bool flip = frontFacing && ((bone.worldFlipX != bone.worldFlipY) == worldScaleIsSameSigns);
attachmentsFlipStateTemp.Items[i] = flip;
if (attachment is RegionAttachment) { attachmentsTriangleCountTemp.Items[i] = -1;
rendererObject = ((RegionAttachment)attachment).RendererObject; RegionAttachment regionAttachment = attachment as RegionAttachment;
if (regionAttachment != null) {
rendererObject = regionAttachment.RendererObject;
attachmentVertexCount = 4; attachmentVertexCount = 4;
attachmentTriangleCount = 6; attachmentTriangleCount = 6;
} else { } else {
if (!renderMeshes) if (!renderMeshes)
continue; continue;
if (attachment is MeshAttachment) { MeshAttachment meshAttachment = attachment as MeshAttachment;
MeshAttachment meshAttachment = (MeshAttachment)attachment; if (meshAttachment != null) {
rendererObject = meshAttachment.RendererObject; rendererObject = meshAttachment.RendererObject;
attachmentVertexCount = meshAttachment.vertices.Length >> 1; attachmentVertexCount = meshAttachment.vertices.Length >> 1;
attachmentTriangleCount = meshAttachment.triangles.Length; attachmentTriangleCount = meshAttachment.triangles.Length;
} else if (attachment is SkinnedMeshAttachment) { } else {
SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment; SkinnedMeshAttachment skinnedMeshAttachment = attachment as SkinnedMeshAttachment;
rendererObject = meshAttachment.RendererObject; if (skinnedMeshAttachment != null) {
attachmentVertexCount = meshAttachment.uvs.Length >> 1; rendererObject = skinnedMeshAttachment.RendererObject;
attachmentTriangleCount = meshAttachment.triangles.Length; attachmentVertexCount = skinnedMeshAttachment.uvs.Length >> 1;
} else attachmentTriangleCount = skinnedMeshAttachment.triangles.Length;
continue; } else
continue;
}
} }
// Populate submesh when material changes. // Populate submesh when material changes.
@ -220,9 +247,11 @@ public class SkeletonRenderer : MonoBehaviour {
#else #else
Material material = (rendererObject.GetType() == typeof(Material)) ? (Material)rendererObject : (Material)((AtlasRegion)rendererObject).page.rendererObject; Material material = (rendererObject.GetType() == typeof(Material)) ? (Material)rendererObject : (Material)((AtlasRegion)rendererObject).page.rendererObject;
#endif #endif
if ((lastMaterial != null && lastMaterial.GetInstanceID() != material.GetInstanceID()) ||
if ((lastMaterial != material && lastMaterial != null) || submeshSeparatorSlots.Contains(slot)) { (submeshSeparatorSlotsCount > 0 && submeshSeparatorSlots.Contains(slot))) {
AddSubmesh(lastMaterial, submeshStartSlotIndex, i, submeshTriangleCount, submeshFirstVertex, false); addSubmeshArgumentsTemp.Add(
new LastState.AddSubmeshArguments(lastMaterial, submeshStartSlotIndex, i, submeshTriangleCount, submeshFirstVertex, false)
);
submeshTriangleCount = 0; submeshTriangleCount = 0;
submeshFirstVertex = vertexCount; submeshFirstVertex = vertexCount;
submeshStartSlotIndex = i; submeshStartSlotIndex = i;
@ -231,15 +260,37 @@ public class SkeletonRenderer : MonoBehaviour {
submeshTriangleCount += attachmentTriangleCount; submeshTriangleCount += attachmentTriangleCount;
vertexCount += attachmentVertexCount; vertexCount += attachmentVertexCount;
}
AddSubmesh(lastMaterial, submeshStartSlotIndex, drawOrderCount, submeshTriangleCount, submeshFirstVertex, true);
// Set materials. attachmentsTriangleCountTemp.Items[i] = attachmentTriangleCount;
if (submeshMaterials.Count == sharedMaterials.Length) }
submeshMaterials.CopyTo(sharedMaterials); addSubmeshArgumentsTemp.Add(
else new LastState.AddSubmeshArguments(lastMaterial, submeshStartSlotIndex, drawOrderCount, submeshTriangleCount, submeshFirstVertex, true)
sharedMaterials = submeshMaterials.ToArray(); );
meshRenderer.sharedMaterials = sharedMaterials;
bool mustUpdateMeshStructure = CheckIfMustUpdateMeshStructure(attachmentsTriangleCountTemp, attachmentsFlipStateTemp, addSubmeshArgumentsTemp);
if (mustUpdateMeshStructure) {
submeshMaterials.Clear();
for (int i = 0, n = addSubmeshArgumentsTemp.Count; i < n; i++) {
LastState.AddSubmeshArguments arguments = addSubmeshArgumentsTemp.Items[i];
AddSubmesh(
arguments.material,
arguments.startSlot,
arguments.endSlot,
arguments.triangleCount,
arguments.firstVertex,
arguments.lastSubmesh,
attachmentsFlipStateTemp
);
}
// Set materials.
if (submeshMaterials.Count == sharedMaterials.Length)
submeshMaterials.CopyTo(sharedMaterials);
else
sharedMaterials = submeshMaterials.ToArray();
meshRenderer.sharedMaterials = sharedMaterials;
}
// Ensure mesh data is the right size. // Ensure mesh data is the right size.
Vector3[] vertices = this.vertices; Vector3[] vertices = this.vertices;
@ -254,31 +305,48 @@ public class SkeletonRenderer : MonoBehaviour {
} else { } else {
// Too many vertices, zero the extra. // Too many vertices, zero the extra.
Vector3 zero = Vector3.zero; Vector3 zero = Vector3.zero;
for (int i = vertexCount, n = lastVertexCount; i < n; i++) for (int i = vertexCount, n = lastState.vertexCount ; i < n; i++)
vertices[i] = zero; vertices[i] = zero;
} }
lastVertexCount = vertexCount; lastState.vertexCount = vertexCount;
// Setup mesh. // Setup mesh.
float zSpacing = this.zSpacing;
float[] tempVertices = this.tempVertices; float[] tempVertices = this.tempVertices;
Vector2[] uvs = this.uvs; Vector2[] uvs = this.uvs;
Color32[] colors = this.colors; Color32[] colors = this.colors;
int vertexIndex = 0; int vertexIndex = 0;
Color32 color = new Color32(); Color32 color;
float zSpacing = this.zSpacing;
float a = skeleton.a * 255, r = skeleton.r, g = skeleton.g, b = skeleton.b; float a = skeleton.a * 255, r = skeleton.r, g = skeleton.g, b = skeleton.b;
Vector3 meshBoundsMin;
meshBoundsMin.x = float.MaxValue;
meshBoundsMin.y = float.MaxValue;
meshBoundsMin.z = zSpacing > 0f ? 0f : zSpacing * (drawOrderCount - 1);
Vector3 meshBoundsMax;
meshBoundsMax.x = float.MinValue;
meshBoundsMax.y = float.MinValue;
meshBoundsMax.z = zSpacing < 0f ? 0f : zSpacing * (drawOrderCount - 1);
for (int i = 0; i < drawOrderCount; i++) { for (int i = 0; i < drawOrderCount; i++) {
Slot slot = drawOrder[i]; Slot slot = drawOrder.Items[i];
Attachment attachment = slot.attachment; Attachment attachment = slot.attachment;
if (attachment is RegionAttachment) { RegionAttachment regionAttachment = attachment as RegionAttachment;
RegionAttachment regionAttachment = (RegionAttachment)attachment; if (regionAttachment != null) {
regionAttachment.ComputeWorldVertices(slot.bone, tempVertices); regionAttachment.ComputeWorldVertices(slot.bone, tempVertices);
float z = i * zSpacing; float z = i * zSpacing;
vertices[vertexIndex] = new Vector3(tempVertices[RegionAttachment.X1], tempVertices[RegionAttachment.Y1], z); vertices[vertexIndex].x = tempVertices[RegionAttachment.X1];
vertices[vertexIndex + 1] = new Vector3(tempVertices[RegionAttachment.X4], tempVertices[RegionAttachment.Y4], z); vertices[vertexIndex].y = tempVertices[RegionAttachment.Y1];
vertices[vertexIndex + 2] = new Vector3(tempVertices[RegionAttachment.X2], tempVertices[RegionAttachment.Y2], z); vertices[vertexIndex].z = z;
vertices[vertexIndex + 3] = new Vector3(tempVertices[RegionAttachment.X3], tempVertices[RegionAttachment.Y3], z); vertices[vertexIndex + 1].x = tempVertices[RegionAttachment.X4];
vertices[vertexIndex + 1].y = tempVertices[RegionAttachment.Y4];
vertices[vertexIndex + 1].z = z;
vertices[vertexIndex + 2].x = tempVertices[RegionAttachment.X2];
vertices[vertexIndex + 2].y = tempVertices[RegionAttachment.Y2];
vertices[vertexIndex + 2].z = z;
vertices[vertexIndex + 3].x = tempVertices[RegionAttachment.X3];
vertices[vertexIndex + 3].y = tempVertices[RegionAttachment.Y3];
vertices[vertexIndex + 3].z = z;
color.a = (byte)(a * slot.a * regionAttachment.a); color.a = (byte)(a * slot.a * regionAttachment.a);
color.r = (byte)(r * slot.r * regionAttachment.r * color.a); color.r = (byte)(r * slot.r * regionAttachment.r * color.a);
@ -291,17 +359,57 @@ public class SkeletonRenderer : MonoBehaviour {
colors[vertexIndex + 3] = color; colors[vertexIndex + 3] = color;
float[] regionUVs = regionAttachment.uvs; float[] regionUVs = regionAttachment.uvs;
uvs[vertexIndex] = new Vector2(regionUVs[RegionAttachment.X1], regionUVs[RegionAttachment.Y1]); uvs[vertexIndex].x = regionUVs[RegionAttachment.X1];
uvs[vertexIndex + 1] = new Vector2(regionUVs[RegionAttachment.X4], regionUVs[RegionAttachment.Y4]); uvs[vertexIndex].y = regionUVs[RegionAttachment.Y1];
uvs[vertexIndex + 2] = new Vector2(regionUVs[RegionAttachment.X2], regionUVs[RegionAttachment.Y2]); uvs[vertexIndex + 1].x = regionUVs[RegionAttachment.X4];
uvs[vertexIndex + 3] = new Vector2(regionUVs[RegionAttachment.X3], regionUVs[RegionAttachment.Y3]); uvs[vertexIndex + 1].y = regionUVs[RegionAttachment.Y4];
uvs[vertexIndex + 2].x = regionUVs[RegionAttachment.X2];
uvs[vertexIndex + 2].y = regionUVs[RegionAttachment.Y2];
uvs[vertexIndex + 3].x = regionUVs[RegionAttachment.X3];
uvs[vertexIndex + 3].y = regionUVs[RegionAttachment.Y3];
// Calculate min/max X
if (tempVertices[RegionAttachment.X1] < meshBoundsMin.x)
meshBoundsMin.x = tempVertices[RegionAttachment.X1];
else if (tempVertices[RegionAttachment.X1] > meshBoundsMax.x)
meshBoundsMax.x = tempVertices[RegionAttachment.X1];
if (tempVertices[RegionAttachment.X2] < meshBoundsMin.x)
meshBoundsMin.x = tempVertices[RegionAttachment.X2];
else if (tempVertices[RegionAttachment.X2] > meshBoundsMax.x)
meshBoundsMax.x = tempVertices[RegionAttachment.X2];
if (tempVertices[RegionAttachment.X3] < meshBoundsMin.x)
meshBoundsMin.x = tempVertices[RegionAttachment.X3];
else if (tempVertices[RegionAttachment.X3] > meshBoundsMax.x)
meshBoundsMax.x = tempVertices[RegionAttachment.X3];
if (tempVertices[RegionAttachment.X4] < meshBoundsMin.x)
meshBoundsMin.x = tempVertices[RegionAttachment.X4];
else if (tempVertices[RegionAttachment.X4] > meshBoundsMax.x)
meshBoundsMax.x = tempVertices[RegionAttachment.X4];
// Calculate min/max Y
if (tempVertices[RegionAttachment.Y1] < meshBoundsMin.y)
meshBoundsMin.y = tempVertices[RegionAttachment.Y1];
else if (tempVertices[RegionAttachment.Y1] > meshBoundsMax.y)
meshBoundsMax.y = tempVertices[RegionAttachment.Y1];
if (tempVertices[RegionAttachment.Y2] < meshBoundsMin.y)
meshBoundsMin.y = tempVertices[RegionAttachment.Y2];
else if (tempVertices[RegionAttachment.Y2] > meshBoundsMax.y)
meshBoundsMax.y = tempVertices[RegionAttachment.Y2];
if (tempVertices[RegionAttachment.Y3] < meshBoundsMin.y)
meshBoundsMin.y = tempVertices[RegionAttachment.Y3];
else if (tempVertices[RegionAttachment.Y3] > meshBoundsMax.y)
meshBoundsMax.y = tempVertices[RegionAttachment.Y3];
if (tempVertices[RegionAttachment.Y4] < meshBoundsMin.y)
meshBoundsMin.y = tempVertices[RegionAttachment.Y4];
else if (tempVertices[RegionAttachment.Y4] > meshBoundsMax.y)
meshBoundsMax.y = tempVertices[RegionAttachment.Y4];
vertexIndex += 4; vertexIndex += 4;
} else { } else {
if (!renderMeshes) if (!renderMeshes)
continue; continue;
if (attachment is MeshAttachment) { MeshAttachment meshAttachment = attachment as MeshAttachment;
MeshAttachment meshAttachment = (MeshAttachment)attachment; if (meshAttachment != null) {
int meshVertexCount = meshAttachment.vertices.Length; int meshVertexCount = meshAttachment.vertices.Length;
if (tempVertices.Length < meshVertexCount) if (tempVertices.Length < meshVertexCount)
this.tempVertices = tempVertices = new float[meshVertexCount]; this.tempVertices = tempVertices = new float[meshVertexCount];
@ -316,29 +424,55 @@ public class SkeletonRenderer : MonoBehaviour {
float[] meshUVs = meshAttachment.uvs; float[] meshUVs = meshAttachment.uvs;
float z = i * zSpacing; float z = i * zSpacing;
for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) { for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) {
vertices[vertexIndex] = new Vector3(tempVertices[ii], tempVertices[ii + 1], z); vertices[vertexIndex].x = tempVertices[ii];
vertices[vertexIndex].y = tempVertices[ii + 1];
vertices[vertexIndex].z = z;
colors[vertexIndex] = color; colors[vertexIndex] = color;
uvs[vertexIndex] = new Vector2(meshUVs[ii], meshUVs[ii + 1]); uvs[vertexIndex].x = meshUVs[ii];
uvs[vertexIndex].y = meshUVs[ii + 1];
if (tempVertices[ii] < meshBoundsMin.x)
meshBoundsMin.x = tempVertices[ii];
else if (tempVertices[ii] > meshBoundsMax.x)
meshBoundsMax.x = tempVertices[ii];
if (tempVertices[ii + 1]< meshBoundsMin.y)
meshBoundsMin.y = tempVertices[ii + 1];
else if (tempVertices[ii + 1] > meshBoundsMax.y)
meshBoundsMax.y = tempVertices[ii + 1];
} }
} else if (attachment is SkinnedMeshAttachment) { } else {
SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment; SkinnedMeshAttachment skinnedMeshAttachment = attachment as SkinnedMeshAttachment;
int meshVertexCount = meshAttachment.uvs.Length; if (skinnedMeshAttachment != null) {
if (tempVertices.Length < meshVertexCount) int meshVertexCount = skinnedMeshAttachment.uvs.Length;
this.tempVertices = tempVertices = new float[meshVertexCount]; if (tempVertices.Length < meshVertexCount)
meshAttachment.ComputeWorldVertices(slot, tempVertices); this.tempVertices = tempVertices = new float[meshVertexCount];
skinnedMeshAttachment.ComputeWorldVertices(slot, tempVertices);
color.a = (byte)(a * slot.a * meshAttachment.a); color.a = (byte)(a * slot.a * skinnedMeshAttachment.a);
color.r = (byte)(r * slot.r * meshAttachment.r * color.a); color.r = (byte)(r * slot.r * skinnedMeshAttachment.r * color.a);
color.g = (byte)(g * slot.g * meshAttachment.g * color.a); color.g = (byte)(g * slot.g * skinnedMeshAttachment.g * color.a);
color.b = (byte)(b * slot.b * meshAttachment.b * color.a); color.b = (byte)(b * slot.b * skinnedMeshAttachment.b * color.a);
if (slot.data.blendMode == BlendMode.additive) color.a = 0; if (slot.data.blendMode == BlendMode.additive) color.a = 0;
float[] meshUVs = meshAttachment.uvs; float[] meshUVs = skinnedMeshAttachment.uvs;
float z = i * zSpacing; float z = i * zSpacing;
for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) { for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) {
vertices[vertexIndex] = new Vector3(tempVertices[ii], tempVertices[ii + 1], z); vertices[vertexIndex].x = tempVertices[ii];
colors[vertexIndex] = color; vertices[vertexIndex].y = tempVertices[ii + 1];
uvs[vertexIndex] = new Vector2(meshUVs[ii], meshUVs[ii + 1]); vertices[vertexIndex].z = z;
colors[vertexIndex] = color;
uvs[vertexIndex].x = meshUVs[ii];
uvs[vertexIndex].y = meshUVs[ii + 1];
if (tempVertices[ii] < meshBoundsMin.x)
meshBoundsMin.x = tempVertices[ii];
else if (tempVertices[ii] > meshBoundsMax.x)
meshBoundsMax.x = tempVertices[ii];
if (tempVertices[ii + 1]< meshBoundsMin.y)
meshBoundsMin.y = tempVertices[ii + 1];
else if (tempVertices[ii + 1] > meshBoundsMax.y)
meshBoundsMax.y = tempVertices[ii + 1];
}
} }
} }
} }
@ -352,11 +486,16 @@ public class SkeletonRenderer : MonoBehaviour {
mesh.colors32 = colors; mesh.colors32 = colors;
mesh.uv = uvs; mesh.uv = uvs;
int submeshCount = submeshMaterials.Count; if (mustUpdateMeshStructure) {
mesh.subMeshCount = submeshCount; int submeshCount = submeshMaterials.Count;
for (int i = 0; i < submeshCount; ++i) mesh.subMeshCount = submeshCount;
mesh.SetTriangles(submeshes[i].triangles, i); for (int i = 0; i < submeshCount; ++i)
mesh.RecalculateBounds(); mesh.SetTriangles(submeshes.Items[i].triangles, i);
}
Vector3 meshBoundsExtents = meshBoundsMax - meshBoundsMin;
Vector3 meshBoundsCenter = meshBoundsMin + meshBoundsExtents * 0.5f;
mesh.bounds = new Bounds(meshBoundsCenter, meshBoundsExtents);
if (newTriangles && calculateNormals) { if (newTriangles && calculateNormals) {
Vector3[] normals = new Vector3[vertexCount]; Vector3[] normals = new Vector3[vertexCount];
@ -377,21 +516,105 @@ public class SkeletonRenderer : MonoBehaviour {
} }
} }
// Update previous state
ExposedList<int> attachmentsTriangleCountCurrentMesh;
ExposedList<bool> attachmentsFlipStateCurrentMesh;
ExposedList<LastState.AddSubmeshArguments> addSubmeshArgumentsCurrentMesh;
if (useMesh1) {
attachmentsTriangleCountCurrentMesh = lastState.attachmentsTriangleCountMesh1;
addSubmeshArgumentsCurrentMesh = lastState.addSubmeshArgumentsMesh1;
attachmentsFlipStateCurrentMesh = lastState.attachmentsFlipStateMesh1;
lastState.immutableTrianglesMesh1 = immutableTriangles;
} else {
attachmentsTriangleCountCurrentMesh = lastState.attachmentsTriangleCountMesh2;
addSubmeshArgumentsCurrentMesh = lastState.addSubmeshArgumentsMesh2;
attachmentsFlipStateCurrentMesh = lastState.attachmentsFlipStateMesh2;
lastState.immutableTrianglesMesh2 = immutableTriangles;
}
attachmentsTriangleCountCurrentMesh.GrowIfNeeded(attachmentsTriangleCountTemp.Capacity);
attachmentsTriangleCountCurrentMesh.Count = attachmentsTriangleCountTemp.Count;
attachmentsTriangleCountTemp.CopyTo(attachmentsTriangleCountCurrentMesh.Items, 0);
attachmentsFlipStateCurrentMesh.GrowIfNeeded(attachmentsFlipStateTemp.Capacity);
attachmentsFlipStateCurrentMesh.Count = attachmentsFlipStateTemp.Count;
attachmentsFlipStateTemp.CopyTo(attachmentsFlipStateCurrentMesh.Items, 0);
addSubmeshArgumentsCurrentMesh.GrowIfNeeded(addSubmeshArgumentsTemp.Count);
addSubmeshArgumentsCurrentMesh.Count = addSubmeshArgumentsTemp.Count;
addSubmeshArgumentsTemp.CopyTo(addSubmeshArgumentsCurrentMesh.Items);
if (submeshRenderers.Length > 0) { if (submeshRenderers.Length > 0) {
foreach (var submeshRenderer in submeshRenderers) { for (int i = 0; i < submeshRenderers.Length; i++) {
if (submeshRenderer.submeshIndex < sharedMaterials.Length) SkeletonUtilitySubmeshRenderer submeshRenderer = submeshRenderers[i];
if (submeshRenderer.submeshIndex < sharedMaterials.Length) {
submeshRenderer.SetMesh(meshRenderer, useMesh1 ? mesh1 : mesh2, sharedMaterials[submeshRenderer.submeshIndex]); submeshRenderer.SetMesh(meshRenderer, useMesh1 ? mesh1 : mesh2, sharedMaterials[submeshRenderer.submeshIndex]);
else } else {
submeshRenderer.GetComponent<Renderer>().enabled = false; submeshRenderer.GetComponent<Renderer>().enabled = false;
}
} }
} }
useMesh1 = !useMesh1; useMesh1 = !useMesh1;
} }
/** Stores vertices and triangles for a single material. */ private bool CheckIfMustUpdateMeshStructure(ExposedList<int> attachmentsTriangleCountTemp, ExposedList<bool> attachmentsFlipStateTemp, ExposedList<LastState.AddSubmeshArguments> addSubmeshArgumentsTemp) {
private void AddSubmesh (Material material, int startSlot, int endSlot, int triangleCount, int firstVertex, bool lastSubmesh) { // Check if any mesh settings were changed
bool mustUpdateMeshStructure =
immutableTriangles != (useMesh1 ? lastState.immutableTrianglesMesh1 : lastState.immutableTrianglesMesh2);
#if UNITY_EDITOR
mustUpdateMeshStructure |= !Application.isPlaying;
#endif
if (mustUpdateMeshStructure)
return true;
// Check if any attachments were enabled/disabled
// or submesh structures has changed
ExposedList<int> attachmentsTriangleCountCurrentMesh;
ExposedList<bool> attachmentsFlipStateCurrentMesh;
ExposedList<LastState.AddSubmeshArguments> addSubmeshArgumentsCurrentMesh;
if (useMesh1) {
attachmentsTriangleCountCurrentMesh = lastState.attachmentsTriangleCountMesh1;
addSubmeshArgumentsCurrentMesh = lastState.addSubmeshArgumentsMesh1;
attachmentsFlipStateCurrentMesh = lastState.attachmentsFlipStateMesh1;
} else {
attachmentsTriangleCountCurrentMesh = lastState.attachmentsTriangleCountMesh2;
addSubmeshArgumentsCurrentMesh = lastState.addSubmeshArgumentsMesh2;
attachmentsFlipStateCurrentMesh = lastState.attachmentsFlipStateMesh2;
}
// Check attachments
int attachmentCount = attachmentsTriangleCountTemp.Count;
if (attachmentsTriangleCountCurrentMesh.Count != attachmentCount)
return true;
for (int i = 0; i < attachmentCount; i++) {
if (attachmentsTriangleCountCurrentMesh.Items[i] != attachmentsTriangleCountTemp.Items[i])
return true;
}
// Check flip state
for (int i = 0; i < attachmentCount; i++) {
if (attachmentsFlipStateCurrentMesh.Items[i] != attachmentsFlipStateTemp.Items[i])
return true;
}
// Check submeshes
int submeshCount = addSubmeshArgumentsTemp.Count;
if (addSubmeshArgumentsCurrentMesh.Count != submeshCount)
return true;
for (int i = 0; i < submeshCount; i++) {
if (!addSubmeshArgumentsCurrentMesh.Items[i].Equals(ref addSubmeshArgumentsTemp.Items[i]))
return true;
}
return false;
}
/** Stores vertices and triangles for a single material. */
private void AddSubmesh (Material material, int startSlot, int endSlot, int triangleCount, int firstVertex, bool lastSubmesh, ExposedList<bool> flipStates) {
int submeshIndex = submeshMaterials.Count; int submeshIndex = submeshMaterials.Count;
submeshMaterials.Add(material); submeshMaterials.Add(material);
@ -400,7 +623,7 @@ public class SkeletonRenderer : MonoBehaviour {
else if (immutableTriangles) else if (immutableTriangles)
return; return;
Submesh submesh = submeshes[submeshIndex]; Submesh submesh = submeshes.Items[submeshIndex];
int[] triangles = submesh.triangles; int[] triangles = submesh.triangles;
int trianglesCapacity = triangles.Length; int trianglesCapacity = triangles.Length;
@ -434,12 +657,12 @@ public class SkeletonRenderer : MonoBehaviour {
} }
// Store triangles. // Store triangles.
List<Slot> drawOrder = skeleton.DrawOrder; ExposedList<Slot> drawOrder = skeleton.DrawOrder;
for (int i = startSlot, triangleIndex = 0; i < endSlot; i++) { for (int i = startSlot, triangleIndex = 0; i < endSlot; i++) {
Slot slot = drawOrder[i]; Slot slot = drawOrder.Items[i];
Attachment attachment = slot.attachment; Attachment attachment = slot.attachment;
Bone bone = slot.bone;
bool flip = frontFacing && ((bone.WorldFlipX != bone.WorldFlipY) != (Mathf.Sign(bone.WorldScaleX) != Mathf.Sign(bone.WorldScaleY))); bool flip = flipStates.Items[i];
if (attachment is RegionAttachment) { if (attachment is RegionAttachment) {
if (!flip) { if (!flip) {
@ -464,16 +687,18 @@ public class SkeletonRenderer : MonoBehaviour {
} }
int[] attachmentTriangles; int[] attachmentTriangles;
int attachmentVertexCount; int attachmentVertexCount;
if (attachment is MeshAttachment) { MeshAttachment meshAttachment = attachment as MeshAttachment;
MeshAttachment meshAttachment = (MeshAttachment)attachment; if (meshAttachment != null) {
attachmentVertexCount = meshAttachment.vertices.Length >> 1; attachmentVertexCount = meshAttachment.vertices.Length >> 1;
attachmentTriangles = meshAttachment.triangles; attachmentTriangles = meshAttachment.triangles;
} else if (attachment is SkinnedMeshAttachment) { } else {
SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment; SkinnedMeshAttachment skinnedMeshAttachment = attachment as SkinnedMeshAttachment;
attachmentVertexCount = meshAttachment.uvs.Length >> 1; if (skinnedMeshAttachment != null) {
attachmentTriangles = meshAttachment.triangles; attachmentVertexCount = skinnedMeshAttachment.uvs.Length >> 1;
} else attachmentTriangles = skinnedMeshAttachment.triangles;
continue; } else
continue;
}
if (flip) { if (flip) {
for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii += 3, triangleIndex += 3) { for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii += 3, triangleIndex += 3) {
@ -494,24 +719,62 @@ public class SkeletonRenderer : MonoBehaviour {
#if UNITY_EDITOR #if UNITY_EDITOR
void OnDrawGizmos () { void OnDrawGizmos () {
// Make selection easier by drawing a clear gizmo over the skeleton. // Make selection easier by drawing a clear gizmo over the skeleton.
if (vertices == null) return; meshFilter = GetComponent<MeshFilter>();
Vector3 gizmosCenter = new Vector3(); if (meshFilter == null) return;
Vector3 gizmosSize = new Vector3();
Vector3 min = new Vector3(float.MaxValue, float.MaxValue, 0f); Mesh mesh = meshFilter.sharedMesh;
Vector3 max = new Vector3(float.MinValue, float.MinValue, 0f); if (mesh == null) return;
foreach (Vector3 vert in vertices) {
min = Vector3.Min(min, vert); Bounds meshBounds = mesh.bounds;
max = Vector3.Max(max, vert);
}
float width = max.x - min.x;
float height = max.y - min.y;
gizmosCenter = new Vector3(min.x + (width / 2f), min.y + (height / 2f), 0f);
gizmosSize = new Vector3(width, height, 1f);
Gizmos.color = Color.clear; Gizmos.color = Color.clear;
Gizmos.matrix = transform.localToWorldMatrix; Gizmos.matrix = transform.localToWorldMatrix;
Gizmos.DrawCube(gizmosCenter, gizmosSize); Gizmos.DrawCube(meshBounds.center, meshBounds.size);
} }
#endif #endif
private class LastState {
public bool immutableTrianglesMesh1;
public bool immutableTrianglesMesh2;
public int vertexCount;
public readonly ExposedList<bool> attachmentsFlipStateTemp = new ExposedList<bool>();
public readonly ExposedList<bool> attachmentsFlipStateMesh1 = new ExposedList<bool>();
public readonly ExposedList<bool> attachmentsFlipStateMesh2 = new ExposedList<bool>();
public readonly ExposedList<int> attachmentsTriangleCountTemp = new ExposedList<int>();
public readonly ExposedList<int> attachmentsTriangleCountMesh1 = new ExposedList<int>();
public readonly ExposedList<int> attachmentsTriangleCountMesh2 = new ExposedList<int>();
public readonly ExposedList<AddSubmeshArguments> addSubmeshArgumentsTemp = new ExposedList<AddSubmeshArguments>();
public readonly ExposedList<AddSubmeshArguments> addSubmeshArgumentsMesh1 = new ExposedList<AddSubmeshArguments>();
public readonly ExposedList<AddSubmeshArguments> addSubmeshArgumentsMesh2 = new ExposedList<AddSubmeshArguments>();
public struct AddSubmeshArguments {
public Material material;
public int startSlot;
public int endSlot;
public int triangleCount;
public int firstVertex;
public bool lastSubmesh;
public AddSubmeshArguments(Material material, int startSlot, int endSlot, int triangleCount, int firstVertex, bool lastSubmesh) {
this.material = material;
this.startSlot = startSlot;
this.endSlot = endSlot;
this.triangleCount = triangleCount;
this.firstVertex = firstVertex;
this.lastSubmesh = lastSubmesh;
}
public bool Equals(ref AddSubmeshArguments other) {
return
!ReferenceEquals(material, null) &&
!ReferenceEquals(other.material, null) &&
material.GetInstanceID() == other.material.GetInstanceID() &&
startSlot == other.startSlot &&
endSlot == other.endSlot &&
triangleCount == other.triangleCount &&
firstVertex == other.firstVertex;
}
}
}
} }
class Submesh { class Submesh {

View File

@ -61,7 +61,7 @@ public class SkeletonUtilityBoneInspector : Editor {
currentSkinName = skin.Name; currentSkinName = skin.Name;
for(int i = 0; i < slotCount; i++){ for(int i = 0; i < slotCount; i++){
Slot slot = skeletonUtility.skeletonRenderer.skeleton.Slots[i]; Slot slot = skeletonUtility.skeletonRenderer.skeleton.Slots.Items[i];
if (slot.Bone == utilityBone.bone) { if (slot.Bone == utilityBone.bone) {
List<Attachment> attachments = new List<Attachment>(); List<Attachment> attachments = new List<Attachment>();
@ -233,14 +233,14 @@ public class SkeletonUtilityBoneInspector : Editor {
} }
} }
void BoneSelectorContextMenu (string current, List<Bone> bones, string topValue, GenericMenu.MenuFunction2 callback) { void BoneSelectorContextMenu (string current, ExposedList<Bone> bones, string topValue, GenericMenu.MenuFunction2 callback) {
GenericMenu menu = new GenericMenu(); GenericMenu menu = new GenericMenu();
if (topValue != "") if (topValue != "")
menu.AddItem(new GUIContent(topValue), current == topValue, callback, null); menu.AddItem(new GUIContent(topValue), current == topValue, callback, null);
for (int i = 0; i < bones.Count; i++) { for (int i = 0; i < bones.Count; i++) {
menu.AddItem(new GUIContent(bones[i].Data.Name), bones[i].Data.Name == current, callback, bones[i]); menu.AddItem(new GUIContent(bones.Items[i].Data.Name), bones.Items[i].Data.Name == current, callback, bones.Items[i]);
} }
menu.ShowAsContext(); menu.ShowAsContext();

View File

@ -132,7 +132,7 @@ public class SkeletonUtilityInspector : Editor {
List<Attachment> attachments = new List<Attachment>(); List<Attachment> attachments = new List<Attachment>();
skin.FindAttachmentsForSlot(i, attachments); skin.FindAttachmentsForSlot(i, attachments);
attachmentTable.Add(skeleton.Slots[i], attachments); attachmentTable.Add(skeleton.Slots.Items[i], attachments);
} }
} }

View File

@ -224,9 +224,9 @@ public class SkeletonUtility : MonoBehaviour {
if (boneRoot != null) { if (boneRoot != null) {
List<string> constraintTargetNames = new List<string>(); List<string> constraintTargetNames = new List<string>();
foreach (IkConstraint c in skeletonRenderer.skeleton.IkConstraints) { ExposedList<IkConstraint> ikConstraints = skeletonRenderer.skeleton.IkConstraints;
constraintTargetNames.Add(c.Target.Data.Name); for (int i = 0, n = ikConstraints.Count; i < n; i++)
} constraintTargetNames.Add(ikConstraints.Items[i].Target.Data.Name);
foreach (var b in utilityBones) { foreach (var b in utilityBones) {
if (b.bone == null) { if (b.bone == null) {
@ -343,7 +343,9 @@ public class SkeletonUtility : MonoBehaviour {
public GameObject SpawnBoneRecursively (Bone bone, Transform parent, SkeletonUtilityBone.Mode mode, bool pos, bool rot, bool sca) { public GameObject SpawnBoneRecursively (Bone bone, Transform parent, SkeletonUtilityBone.Mode mode, bool pos, bool rot, bool sca) {
GameObject go = SpawnBone(bone, parent, mode, pos, rot, sca); GameObject go = SpawnBone(bone, parent, mode, pos, rot, sca);
foreach (Bone child in bone.Children) { ExposedList<Bone> childrenBones = bone.Children;
for (int i = 0, n = childrenBones.Count; i < n; i++) {
Bone child = childrenBones.Items[i];
SpawnBoneRecursively(child, go.transform, mode, pos, rot, sca); SpawnBoneRecursively(child, go.transform, mode, pos, rot, sca);
} }