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 {
public class Animation {
internal List<Timeline> timelines;
internal ExposedList<Timeline> timelines;
internal float duration;
internal String 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 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 (timelines == null) throw new ArgumentNullException("timelines cannot be null.");
this.name = name;
@ -53,7 +53,7 @@ namespace Spine {
/// <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="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 (loop && duration != 0) {
@ -61,16 +61,16 @@ namespace Spine {
lastTime %= duration;
}
List<Timeline> timelines = this.timelines;
ExposedList<Timeline> timelines = this.timelines;
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>
/// <param name="lastTime">The last time the animation was applied.</param>
/// <param name="events">Any triggered events are added.</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 (loop && duration != 0) {
@ -78,9 +78,9 @@ namespace Spine {
lastTime %= duration;
}
List<Timeline> timelines = this.timelines;
ExposedList<Timeline> timelines = this.timelines;
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>
@ -125,7 +125,7 @@ namespace Spine {
public interface Timeline {
/// <summary>Sets the value(s) for the specified time.</summary>
/// <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>
@ -140,7 +140,7 @@ namespace Spine {
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) {
curves[frameIndex * BEZIER_SIZE] = LINEAR;
@ -230,11 +230,11 @@ namespace Spine {
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;
if (time < frames[0]) return; // Time is before first frame.
Bone bone = skeleton.bones[boneIndex];
Bone bone = skeleton.bones.Items[boneIndex];
float amount;
@ -293,11 +293,11 @@ namespace Spine {
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;
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.
bone.x += (bone.data.x + frames[frames.Length - 2] - bone.x) * alpha;
@ -323,11 +323,11 @@ namespace Spine {
: 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;
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.
bone.scaleX += (bone.data.scaleX * frames[frames.Length - 2] - bone.scaleX) * alpha;
bone.scaleY += (bone.data.scaleY * frames[frames.Length - 1] - bone.scaleY) * alpha;
@ -375,7 +375,7 @@ namespace Spine {
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;
if (time < frames[0]) return; // Time is before first frame.
@ -403,7 +403,7 @@ namespace Spine {
b = prevFrameB + (frames[frameIndex + FRAME_B] - prevFrameB) * percent;
a = prevFrameA + (frames[frameIndex + FRAME_A] - prevFrameA) * percent;
}
Slot slot = skeleton.slots[slotIndex];
Slot slot = skeleton.slots.Items[slotIndex];
if (alpha < 1) {
slot.r += (r - slot.r) * alpha;
slot.g += (g - slot.g) * alpha;
@ -439,7 +439,7 @@ namespace Spine {
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;
if (time < frames[0]) {
if (lastTime > time) Apply(skeleton, lastTime, int.MaxValue, null, 0);
@ -451,7 +451,7 @@ namespace Spine {
if (frames[frameIndex] < lastTime) return;
String attachmentName = attachmentNames[frameIndex];
skeleton.slots[slotIndex].Attachment =
skeleton.slots.Items[slotIndex].Attachment =
attachmentName == null ? null : skeleton.GetAttachment(slotIndex, attachmentName);
}
}
@ -476,7 +476,7 @@ namespace Spine {
}
/// <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;
float[] frames = this.frames;
int frameCount = frames.Length;
@ -524,7 +524,7 @@ namespace Spine {
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;
if (time < frames[0]) return; // Time is before first frame.
@ -534,15 +534,16 @@ namespace Spine {
else
frameIndex = Animation.binarySearch(frames, time) - 1;
List<Slot> drawOrder = skeleton.drawOrder;
List<Slot> slots = skeleton.slots;
ExposedList<Slot> drawOrder = skeleton.drawOrder;
ExposedList<Slot> slots = skeleton.slots;
int[] drawOrderToSetupIndex = drawOrders[frameIndex];
if (drawOrderToSetupIndex == null) {
drawOrder.Clear();
drawOrder.AddRange(slots);
for (int i = 0, n = slots.Count; i < n; i++)
drawOrder.Add(slots.Items[i]);
} else {
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;
}
override public void Apply (Skeleton skeleton, float lastTime, float time, List<Event> firedEvents, float alpha) {
Slot slot = skeleton.slots[slotIndex];
override public void Apply (Skeleton skeleton, float lastTime, float time, ExposedList<Event> firedEvents, float alpha) {
Slot slot = skeleton.slots.Items[slotIndex];
if (slot.attachment != attachment) return;
float[] frames = this.frames;
@ -649,11 +650,11 @@ namespace Spine {
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;
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.
ikConstraint.mix += (frames[frames.Length - 2] - ikConstraint.mix) * alpha;
@ -693,7 +694,7 @@ namespace Spine {
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;
if (time < frames[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;
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) {

View File

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

View File

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

View File

@ -39,7 +39,7 @@ namespace Spine {
internal BoneData data;
internal Skeleton skeleton;
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 bool flipX, flipY;
internal float m00, m01, m10, m11;
@ -49,7 +49,7 @@ namespace Spine {
public BoneData Data { get { return data; } }
public Skeleton Skeleton { get { return skeleton; } }
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 Y { get { return y; } set { y = value; } }
/// <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;
internal IkConstraintData data;
internal List<Bone> bones = new List<Bone>();
internal ExposedList<Bone> bones = new ExposedList<Bone>();
internal Bone target;
internal int bendDirection;
internal float mix;
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 int BendDirection { get { return bendDirection; } set { bendDirection = value; } }
public float Mix { get { return mix; } set { mix = value; } }
@ -55,7 +55,7 @@ namespace Spine {
mix = data.mix;
bendDirection = data.bendDirection;
bones = new List<Bone>(data.bones.Count);
bones = new ExposedList<Bone>(data.bones.Count);
foreach (BoneData boneData in data.bones)
bones.Add(skeleton.FindBone(boneData.name));
target = skeleton.FindBone(data.target.name);
@ -63,13 +63,13 @@ namespace Spine {
public void apply () {
Bone target = this.target;
List<Bone> bones = this.bones;
ExposedList<Bone> bones = this.bones;
switch (bones.Count) {
case 1:
apply(bones[0], target.worldX, target.worldY, mix);
apply(bones.Items[0], target.worldX, target.worldY, mix);
break;
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;
}
}

View File

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

View File

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

View File

@ -34,11 +34,11 @@ using System.Collections.Generic;
namespace Spine {
public class SkeletonBounds {
private List<Polygon> polygonPool = new List<Polygon>();
private ExposedList<Polygon> polygonPool = new ExposedList<Polygon>();
private float minX, minY, maxX, maxY;
public List<BoundingBoxAttachment> BoundingBoxes { get; private set; }
public List<Polygon> Polygons { get; private set; }
public ExposedList<BoundingBoxAttachment> BoundingBoxes { get; private set; }
public ExposedList<Polygon> Polygons { get; private set; }
public float MinX { get { return minX; } set { minX = value; } }
public float MinY { get { return minY; } set { minY = value; } }
public float MaxX { get { return maxX; } set { maxX = value; } }
@ -47,23 +47,23 @@ namespace Spine {
public float Height { get { return maxY - minY; } }
public SkeletonBounds () {
BoundingBoxes = new List<BoundingBoxAttachment>();
Polygons = new List<Polygon>();
BoundingBoxes = new ExposedList<BoundingBoxAttachment>();
Polygons = new ExposedList<Polygon>();
}
public void Update (Skeleton skeleton, bool updateAabb) {
List<BoundingBoxAttachment> boundingBoxes = BoundingBoxes;
List<Polygon> polygons = Polygons;
List<Slot> slots = skeleton.slots;
ExposedList<BoundingBoxAttachment> boundingBoxes = BoundingBoxes;
ExposedList<Polygon> polygons = Polygons;
ExposedList<Slot> slots = skeleton.slots;
int slotCount = slots.Count;
boundingBoxes.Clear();
foreach (Polygon polygon in polygons)
polygonPool.Add(polygon);
for (int i = 0, n = polygons.Count; i < n; i++)
polygonPool.Add(polygons.Items[i]);
polygons.Clear();
for (int i = 0; i < slotCount; i++) {
Slot slot = slots[i];
Slot slot = slots.Items[i];
BoundingBoxAttachment boundingBox = slot.attachment as BoundingBoxAttachment;
if (boundingBox == null) continue;
boundingBoxes.Add(boundingBox);
@ -71,7 +71,7 @@ namespace Spine {
Polygon polygon = null;
int poolCount = polygonPool.Count;
if (poolCount > 0) {
polygon = polygonPool[poolCount - 1];
polygon = polygonPool.Items[poolCount - 1];
polygonPool.RemoveAt(poolCount - 1);
} else
polygon = new Polygon();
@ -88,9 +88,9 @@ namespace Spine {
private void aabbCompute () {
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++) {
Polygon polygon = polygons[i];
Polygon polygon = polygons.Items[i];
float[] vertices = polygon.Vertices;
for (int ii = 0, nn = polygon.Count; ii < nn; ii += 2) {
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
/// efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true.</summary>
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++)
if (ContainsPoint(polygons[i], x, y)) return BoundingBoxes[i];
if (ContainsPoint(polygons.Items[i], x, y)) return BoundingBoxes.Items[i];
return null;
}
/// <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>
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++)
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;
}
@ -201,7 +201,7 @@ namespace Spine {
public Polygon getPolygon (BoundingBoxAttachment 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 {
public class SkeletonData {
internal String name;
internal List<BoneData> bones = new List<BoneData>();
internal List<SlotData> slots = new List<SlotData>();
internal List<Skin> skins = new List<Skin>();
internal ExposedList<BoneData> bones = new ExposedList<BoneData>();
internal ExposedList<SlotData> slots = new ExposedList<SlotData>();
internal ExposedList<Skin> skins = new ExposedList<Skin>();
internal Skin defaultSkin;
internal List<EventData> events = new List<EventData>();
internal List<Animation> animations = new List<Animation>();
internal List<IkConstraintData> ikConstraints = new List<IkConstraintData>();
internal ExposedList<EventData> events = new ExposedList<EventData>();
internal ExposedList<Animation> animations = new ExposedList<Animation>();
internal ExposedList<IkConstraintData> ikConstraints = new ExposedList<IkConstraintData>();
internal float width, height;
internal String version, hash, imagesPath;
public String Name { get { return name; } set { name = value; } }
public List<BoneData> Bones { get { return bones; } } // Ordered parents first.
public List<SlotData> Slots { get { return slots; } } // Setup pose draw order.
public List<Skin> Skins { get { return skins; } set { skins = value; } }
public ExposedList<BoneData> Bones { get { return bones; } } // Ordered parents first.
public ExposedList<SlotData> Slots { get { return slots; } } // Setup pose draw order.
public ExposedList<Skin> Skins { get { return skins; } set { skins = value; } }
/// <summary>May be null.</summary>
public Skin DefaultSkin { get { return defaultSkin; } set { defaultSkin = value; } }
public List<EventData> Events { get { return events; } set { events = value; } }
public List<Animation> Animations { get { return animations; } set { animations = value; } }
public List<IkConstraintData> IkConstraints { get { return ikConstraints; } set { ikConstraints = value; } }
public ExposedList<EventData> Events { get { return events; } set { events = value; } }
public ExposedList<Animation> Animations { get { return animations; } set { animations = value; } }
public ExposedList<IkConstraintData> IkConstraints { get { return ikConstraints; } set { ikConstraints = value; } }
public float Width { get { return width; } set { width = value; } }
public float Height { get { return height; } set { height = value; } }
/// <summary>The Spine version used to export this data.</summary>
@ -65,9 +65,9 @@ namespace Spine {
/// <returns>May be null.</returns>
public BoneData FindBone (String boneName) {
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++) {
BoneData bone = bones[i];
BoneData bone = bones.Items[i];
if (bone.name == boneName) return bone;
}
return null;
@ -76,9 +76,9 @@ namespace Spine {
/// <returns>-1 if the bone was not found.</returns>
public int FindBoneIndex (String boneName) {
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++)
if (bones[i].name == boneName) return i;
if (bones.Items[i].name == boneName) return i;
return -1;
}
@ -87,9 +87,9 @@ namespace Spine {
/// <returns>May be null.</returns>
public SlotData FindSlot (String slotName) {
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++) {
SlotData slot = slots[i];
SlotData slot = slots.Items[i];
if (slot.name == slotName) return slot;
}
return null;
@ -98,9 +98,9 @@ namespace Spine {
/// <returns>-1 if the bone was not found.</returns>
public int FindSlotIndex (String slotName) {
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++)
if (slots[i].name == slotName) return i;
if (slots.Items[i].name == slotName) return i;
return -1;
}
@ -129,9 +129,9 @@ namespace Spine {
/// <returns>May be null.</returns>
public Animation FindAnimation (String animationName) {
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++) {
Animation animation = animations[i];
Animation animation = animations.Items[i];
if (animation.name == animationName) return animation;
}
return null;
@ -142,9 +142,9 @@ namespace Spine {
/// <returns>May be null.</returns>
public IkConstraintData FindIkConstraint (String ikConstraintName) {
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++) {
IkConstraintData ikConstraint = ikConstraints[i];
IkConstraintData ikConstraint = ikConstraints.Items[i];
if (ikConstraint.name == ikConstraintName) return ikConstraint;
}
return null;

View File

@ -380,7 +380,7 @@ namespace Spine {
}
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 scale = Scale;

View File

@ -36,8 +36,8 @@ namespace Spine {
/// <summary>Stores attachments by slot index and attachment name.</summary>
public class Skin {
internal String name;
private Dictionary<KeyValuePair<int, String>, Attachment> attachments =
new Dictionary<KeyValuePair<int, String>, Attachment>(AttachmentComparer.Instance);
private Dictionary<AttachmentKeyTuple, Attachment> attachments =
new Dictionary<AttachmentKeyTuple, Attachment>(AttachmentKeyTupleComparer.Instance);
public String Name { get { return name; } }
@ -48,26 +48,26 @@ namespace Spine {
public void AddAttachment (int slotIndex, String name, Attachment attachment) {
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>
public Attachment GetAttachment (int slotIndex, String name) {
Attachment attachment;
attachments.TryGetValue(new KeyValuePair<int, String>(slotIndex, name), out attachment);
attachments.TryGetValue(new AttachmentKeyTuple(slotIndex, name), out attachment);
return attachment;
}
public void FindNamesForSlot (int slotIndex, List<String> names) {
if (names == null) throw new ArgumentNullException("names cannot be null.");
foreach (KeyValuePair<int, String> key in attachments.Keys)
if (key.Key == slotIndex) names.Add(key.Value);
foreach (AttachmentKeyTuple key in attachments.Keys)
if (key.SlotIndex == slotIndex) names.Add(key.Name);
}
public void FindAttachmentsForSlot (int slotIndex, List<Attachment> attachments) {
if (attachments == null) throw new ArgumentNullException("attachments cannot be null.");
foreach (KeyValuePair<KeyValuePair<int, String>, Attachment> entry in this.attachments)
if (entry.Key.Key == slotIndex) attachments.Add(entry.Value);
foreach (KeyValuePair<AttachmentKeyTuple, Attachment> entry in this.attachments)
if (entry.Key.SlotIndex == slotIndex) attachments.Add(entry.Value);
}
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>
internal void AttachAll (Skeleton skeleton, Skin oldSkin) {
foreach (KeyValuePair<KeyValuePair<int, String>, Attachment> entry in oldSkin.attachments) {
int slotIndex = entry.Key.Key;
Slot slot = skeleton.slots[slotIndex];
foreach (KeyValuePair<AttachmentKeyTuple, Attachment> entry in oldSkin.attachments) {
int slotIndex = entry.Key.SlotIndex;
Slot slot = skeleton.slots.Items[slotIndex];
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;
}
}
}
// Avoids boxing in the dictionary.
private class AttachmentComparer : IEqualityComparer<KeyValuePair<int, String>> {
internal static readonly AttachmentComparer Instance = new AttachmentComparer();
private class AttachmentKeyTupleComparer : IEqualityComparer<AttachmentKeyTuple> {
internal static readonly AttachmentKeyTupleComparer Instance = new AttachmentKeyTupleComparer();
bool IEqualityComparer<KeyValuePair<int, string>>.Equals (KeyValuePair<int, string> o1, KeyValuePair<int, string> o2) {
return o1.Key == o2.Key && o1.Value == o2.Value;
bool IEqualityComparer<AttachmentKeyTuple>.Equals (AttachmentKeyTuple o1, AttachmentKeyTuple o2) {
return o1.SlotIndex == o2.SlotIndex && o1.NameHashCode == o2.NameHashCode && o1.Name == o2.Name;
}
int IEqualityComparer<KeyValuePair<int, string>>.GetHashCode (KeyValuePair<int, string> o) {
return o.Key;
int IEqualityComparer<AttachmentKeyTuple>.GetHashCode (AttachmentKeyTuple o) {
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>";
int animationIndex = 0;
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;
if (name == animationName.stringValue)
animationIndex = i + 1;

View File

@ -49,7 +49,7 @@ public static class SkeletonBaker {
/// </summary>
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) {
Debug.LogError("Could not export Spine Skeleton because SkeletonDataAsset is null or invalid!");
return;
@ -108,7 +108,7 @@ public static class SkeletonBaker {
for (int s = 0; s < skeletonData.Slots.Count; s++) {
List<string> attachmentNames = new List<string>();
for (int i = 0; i < skinCount; i++) {
var skin = skins[i];
var skin = skins.Items[i];
List<string> temp = new List<string>();
skin.FindNamesForSlot(s, temp);
foreach (string str in temp) {
@ -189,7 +189,7 @@ public static class SkeletonBaker {
//create bones
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;
boneTransform.parent = prefabRoot.transform;
boneTable.Add(boneTransform.name, boneTransform);
@ -198,7 +198,7 @@ public static class SkeletonBaker {
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 parentTransform = null;
if (i > 0)
@ -219,7 +219,7 @@ public static class SkeletonBaker {
//create slots and attachments
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;
slotTransform.parent = prefabRoot.transform;
slotTable.Add(slotData.Name, slotTransform);
@ -615,7 +615,7 @@ public static class SkeletonBaker {
skeleton.UpdateWorldTransform();
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);
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) {
var attachmentNames = slotLookup[timeline.SlotIndex];
string bonePath = GetPath(skeleton.Slots[timeline.SlotIndex].Bone.Data);
string slotPath = bonePath + "/" + skeleton.Slots[timeline.SlotIndex].Data.Name;
string bonePath = GetPath(skeleton.Slots.Items[timeline.SlotIndex].Bone.Data);
string slotPath = bonePath + "/" + skeleton.Slots.Items[timeline.SlotIndex].Data.Name;
Dictionary<string, AnimationCurve> curveTable = new Dictionary<string, AnimationCurve>();
@ -899,7 +899,7 @@ public static class SkeletonBaker {
float[] frames = timeline.Frames;
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) {
if (startingName == "" || startingName == null) {
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) {
var boneData = skeleton.Data.Bones[timeline.BoneIndex];
var bone = skeleton.Bones[timeline.BoneIndex];
var boneData = skeleton.Data.Bones.Items[timeline.BoneIndex];
var bone = skeleton.Bones.Items[timeline.BoneIndex];
AnimationCurve xCurve = new AnimationCurve();
AnimationCurve yCurve = new AnimationCurve();
@ -1183,8 +1183,8 @@ public static class SkeletonBaker {
}
static void ParseScaleTimeline (Skeleton skeleton, ScaleTimeline timeline, AnimationClip clip) {
var boneData = skeleton.Data.Bones[timeline.BoneIndex];
var bone = skeleton.Bones[timeline.BoneIndex];
var boneData = skeleton.Data.Bones.Items[timeline.BoneIndex];
var bone = skeleton.Bones.Items[timeline.BoneIndex];
AnimationCurve xCurve = new AnimationCurve();
AnimationCurve yCurve = new AnimationCurve();
@ -1316,8 +1316,8 @@ public static class SkeletonBaker {
}
static void ParseRotateTimeline (Skeleton skeleton, RotateTimeline timeline, AnimationClip clip) {
var boneData = skeleton.Data.Bones[timeline.BoneIndex];
var bone = skeleton.Bones[timeline.BoneIndex];
var boneData = skeleton.Data.Bones.Items[timeline.BoneIndex];
var bone = skeleton.Bones.Items[timeline.BoneIndex];
AnimationCurve curve = new AnimationCurve();

View File

@ -186,7 +186,7 @@ public class SkeletonDataAssetInspector : Editor {
Skin bakeSkin = m_skeletonAnimation.skeleton.Skin;
if (bakeSkin == null) {
skinName = "Default";
bakeSkin = m_skeletonData.Skins[0];
bakeSkin = m_skeletonData.Skins.Items[0];
} else
skinName = m_skeletonAnimation.skeleton.Skin.Name;
@ -195,7 +195,7 @@ public class SkeletonDataAssetInspector : Editor {
try {
GUILayout.BeginVertical();
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.Label(new GUIContent("Skins", SpineEditorUtilities.Icons.skinsRoot), GUILayout.Width(50));
@ -259,7 +259,7 @@ public class SkeletonDataAssetInspector : Editor {
// Animation names
String[] animations = new String[m_skeletonData.Animations.Count];
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++) {
SerializedProperty from = fromAnimation.GetArrayElementAtIndex(i);
@ -350,14 +350,14 @@ public class SkeletonDataAssetInspector : Editor {
List<Attachment> slotAttachments = new List<Attachment>();
List<string> slotAttachmentNames = 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;
if (skin == null) {
skin = defaultSkin;
}
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));
if (showAttachments) {

View File

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

View File

@ -85,7 +85,7 @@ public class SpineSlotDrawer : PropertyDrawer {
menu.AddSeparator("");
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 (attrib.containsBoundingBoxes) {
@ -190,7 +190,7 @@ public class SpineSkinDrawer : PropertyDrawer {
menu.AddSeparator("");
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))
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;
for (int i = 0; i < animations.Count; i++) {
string name = animations[i].Name;
string name = animations.Items[i].Name;
if (name.StartsWith(attrib.startsWith))
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) {
validSkins.Add(skeletonRenderer.skeleton.Skin);
} else {
validSkins.Add(data.Skins[0]);
validSkins.Add(data.Skins.Items[0]);
}
} else {
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.AddSeparator("");
Skin defaultSkin = data.Skins[0];
Skin defaultSkin = data.Skins.Items[0];
SerializedProperty slotProperty = property.serializedObject.FindProperty(attrib.slotField);
string slotMatch = "";
@ -457,7 +457,7 @@ public class SpineAttachmentDrawer : PropertyDrawer {
prefix = skinPrefix;
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;
attachmentNames.Clear();
@ -473,11 +473,11 @@ public class SpineAttachmentDrawer : PropertyDrawer {
for (int a = 0; a < attachmentNames.Count; 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];
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) {
menu.AddDisabledItem(new GUIContent(menuPath));
@ -564,7 +564,7 @@ public class SpineBoneDrawer : PropertyDrawer {
menu.AddSeparator("");
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))
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;
if (skin == null)
skin = data.Skins[0];
skin = data.Skins.Items[0];
anim.Reset();
@ -1035,7 +1035,7 @@ public class SpineEditorUtilities : AssetPostprocessor {
skin = data.DefaultSkin;
if (skin == null)
skin = data.Skins[0];
skin = data.Skins.Items[0];
anim.Reset();

View File

@ -280,7 +280,7 @@ public class SkeletonRagdoll2D : MonoBehaviour {
if (colliders.Count == 0) {
var box = go.AddComponent<BoxCollider2D>();
box.size = new Vector2(length, thickness);
#if UNITY_5_0
#if UNITY_5
box.offset = new Vector2((b.WorldFlipX ? -length : length) / 2, 0);
#else
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;
float lastTime;
@ -54,11 +55,12 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
return;
animationTable.Clear();
clipNameHashCodeTable.Clear();
var data = skeletonDataAsset.GetSkeletonData(true);
foreach (var a in data.Animations) {
animationTable.Add(a.Name, a);
animationTable.Add(a.Name.GetHashCode(), a);
}
animator = GetComponent<Animator>();
@ -106,7 +108,7 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
continue;
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) {
@ -115,7 +117,7 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
continue;
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) {
//apply first non-zero weighted clip
@ -128,7 +130,7 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
continue;
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;
}
@ -140,7 +142,7 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
continue;
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;
@ -154,7 +156,7 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
continue;
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;
}
}
@ -167,7 +169,7 @@ public class SkeletonAnimator : SkeletonRenderer, ISkeletonAnimation {
continue;
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;
}
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.IO;
using System.Collections.Generic;
using UnityEngine;
using Spine;
@ -65,14 +64,14 @@ public class SkeletonRenderer : MonoBehaviour {
private Mesh mesh1, mesh2;
private bool useMesh1;
private float[] tempVertices = new float[8];
private int lastVertexCount;
private Vector3[] vertices;
private Color32[] colors;
private Vector2[] uvs;
private Material[] sharedMaterials = new Material[0];
private readonly List<Material> submeshMaterials = new List<Material>();
private readonly List<Submesh> submeshes = new List<Submesh>();
private readonly ExposedList<Material> submeshMaterials = new ExposedList<Material>();
private readonly ExposedList<Submesh> submeshes = new ExposedList<Submesh>();
private SkeletonUtilitySubmeshRenderer[] submeshRenderers;
private LastState lastState = new LastState();
public virtual void Reset () {
if (meshFilter != null)
@ -95,9 +94,9 @@ public class SkeletonRenderer : MonoBehaviour {
DestroyImmediate(mesh2);
}
lastState = new LastState();
mesh1 = null;
mesh2 = null;
lastVertexCount = 0;
vertices = null;
colors = null;
uvs = null;
@ -119,6 +118,7 @@ public class SkeletonRenderer : MonoBehaviour {
valid = true;
meshFilter = GetComponent<MeshFilter>();
meshRenderer = GetComponent<MeshRenderer>();
mesh1 = newMesh();
mesh2 = newMesh();
vertices = new Vector3[0];
@ -178,40 +178,67 @@ public class SkeletonRenderer : MonoBehaviour {
public virtual void LateUpdate () {
if (!valid)
return;
// Exit early if there is nothing to render
if (!meshRenderer.enabled && submeshRenderers.Length == 0)
return;
// Count vertices and submesh triangles.
int vertexCount = 0;
int submeshTriangleCount = 0, submeshFirstVertex = 0, submeshStartSlotIndex = 0;
Material lastMaterial = null;
submeshMaterials.Clear();
List<Slot> drawOrder = skeleton.DrawOrder;
ExposedList<Slot> drawOrder = skeleton.drawOrder;
int drawOrderCount = drawOrder.Count;
int submeshSeparatorSlotsCount = submeshSeparatorSlots.Count;
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++) {
Slot slot = drawOrder[i];
Slot slot = drawOrder.Items[i];
Bone bone = slot.bone;
Attachment attachment = slot.attachment;
object rendererObject;
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) {
rendererObject = ((RegionAttachment)attachment).RendererObject;
attachmentsTriangleCountTemp.Items[i] = -1;
RegionAttachment regionAttachment = attachment as RegionAttachment;
if (regionAttachment != null) {
rendererObject = regionAttachment.RendererObject;
attachmentVertexCount = 4;
attachmentTriangleCount = 6;
} else {
if (!renderMeshes)
continue;
if (attachment is MeshAttachment) {
MeshAttachment meshAttachment = (MeshAttachment)attachment;
MeshAttachment meshAttachment = attachment as MeshAttachment;
if (meshAttachment != null) {
rendererObject = meshAttachment.RendererObject;
attachmentVertexCount = meshAttachment.vertices.Length >> 1;
attachmentTriangleCount = meshAttachment.triangles.Length;
} else if (attachment is SkinnedMeshAttachment) {
SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment;
rendererObject = meshAttachment.RendererObject;
attachmentVertexCount = meshAttachment.uvs.Length >> 1;
attachmentTriangleCount = meshAttachment.triangles.Length;
} else
continue;
} else {
SkinnedMeshAttachment skinnedMeshAttachment = attachment as SkinnedMeshAttachment;
if (skinnedMeshAttachment != null) {
rendererObject = skinnedMeshAttachment.RendererObject;
attachmentVertexCount = skinnedMeshAttachment.uvs.Length >> 1;
attachmentTriangleCount = skinnedMeshAttachment.triangles.Length;
} else
continue;
}
}
// Populate submesh when material changes.
@ -220,9 +247,11 @@ public class SkeletonRenderer : MonoBehaviour {
#else
Material material = (rendererObject.GetType() == typeof(Material)) ? (Material)rendererObject : (Material)((AtlasRegion)rendererObject).page.rendererObject;
#endif
if ((lastMaterial != material && lastMaterial != null) || submeshSeparatorSlots.Contains(slot)) {
AddSubmesh(lastMaterial, submeshStartSlotIndex, i, submeshTriangleCount, submeshFirstVertex, false);
if ((lastMaterial != null && lastMaterial.GetInstanceID() != material.GetInstanceID()) ||
(submeshSeparatorSlotsCount > 0 && submeshSeparatorSlots.Contains(slot))) {
addSubmeshArgumentsTemp.Add(
new LastState.AddSubmeshArguments(lastMaterial, submeshStartSlotIndex, i, submeshTriangleCount, submeshFirstVertex, false)
);
submeshTriangleCount = 0;
submeshFirstVertex = vertexCount;
submeshStartSlotIndex = i;
@ -231,15 +260,37 @@ public class SkeletonRenderer : MonoBehaviour {
submeshTriangleCount += attachmentTriangleCount;
vertexCount += attachmentVertexCount;
}
AddSubmesh(lastMaterial, submeshStartSlotIndex, drawOrderCount, submeshTriangleCount, submeshFirstVertex, true);
// Set materials.
if (submeshMaterials.Count == sharedMaterials.Length)
submeshMaterials.CopyTo(sharedMaterials);
else
sharedMaterials = submeshMaterials.ToArray();
meshRenderer.sharedMaterials = sharedMaterials;
attachmentsTriangleCountTemp.Items[i] = attachmentTriangleCount;
}
addSubmeshArgumentsTemp.Add(
new LastState.AddSubmeshArguments(lastMaterial, submeshStartSlotIndex, drawOrderCount, submeshTriangleCount, submeshFirstVertex, true)
);
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.
Vector3[] vertices = this.vertices;
@ -254,31 +305,48 @@ public class SkeletonRenderer : MonoBehaviour {
} else {
// Too many vertices, zero the extra.
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;
}
lastVertexCount = vertexCount;
lastState.vertexCount = vertexCount;
// Setup mesh.
float zSpacing = this.zSpacing;
float[] tempVertices = this.tempVertices;
Vector2[] uvs = this.uvs;
Color32[] colors = this.colors;
int vertexIndex = 0;
Color32 color = new Color32();
float zSpacing = this.zSpacing;
Color32 color;
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++) {
Slot slot = drawOrder[i];
Slot slot = drawOrder.Items[i];
Attachment attachment = slot.attachment;
if (attachment is RegionAttachment) {
RegionAttachment regionAttachment = (RegionAttachment)attachment;
RegionAttachment regionAttachment = attachment as RegionAttachment;
if (regionAttachment != null) {
regionAttachment.ComputeWorldVertices(slot.bone, tempVertices);
float z = i * zSpacing;
vertices[vertexIndex] = new Vector3(tempVertices[RegionAttachment.X1], tempVertices[RegionAttachment.Y1], z);
vertices[vertexIndex + 1] = new Vector3(tempVertices[RegionAttachment.X4], tempVertices[RegionAttachment.Y4], z);
vertices[vertexIndex + 2] = new Vector3(tempVertices[RegionAttachment.X2], tempVertices[RegionAttachment.Y2], z);
vertices[vertexIndex + 3] = new Vector3(tempVertices[RegionAttachment.X3], tempVertices[RegionAttachment.Y3], z);
vertices[vertexIndex].x = tempVertices[RegionAttachment.X1];
vertices[vertexIndex].y = tempVertices[RegionAttachment.Y1];
vertices[vertexIndex].z = 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.r = (byte)(r * slot.r * regionAttachment.r * color.a);
@ -291,17 +359,57 @@ public class SkeletonRenderer : MonoBehaviour {
colors[vertexIndex + 3] = color;
float[] regionUVs = regionAttachment.uvs;
uvs[vertexIndex] = new Vector2(regionUVs[RegionAttachment.X1], regionUVs[RegionAttachment.Y1]);
uvs[vertexIndex + 1] = new Vector2(regionUVs[RegionAttachment.X4], regionUVs[RegionAttachment.Y4]);
uvs[vertexIndex + 2] = new Vector2(regionUVs[RegionAttachment.X2], regionUVs[RegionAttachment.Y2]);
uvs[vertexIndex + 3] = new Vector2(regionUVs[RegionAttachment.X3], regionUVs[RegionAttachment.Y3]);
uvs[vertexIndex].x = regionUVs[RegionAttachment.X1];
uvs[vertexIndex].y = regionUVs[RegionAttachment.Y1];
uvs[vertexIndex + 1].x = regionUVs[RegionAttachment.X4];
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;
} else {
if (!renderMeshes)
continue;
if (attachment is MeshAttachment) {
MeshAttachment meshAttachment = (MeshAttachment)attachment;
MeshAttachment meshAttachment = attachment as MeshAttachment;
if (meshAttachment != null) {
int meshVertexCount = meshAttachment.vertices.Length;
if (tempVertices.Length < meshVertexCount)
this.tempVertices = tempVertices = new float[meshVertexCount];
@ -316,29 +424,55 @@ public class SkeletonRenderer : MonoBehaviour {
float[] meshUVs = meshAttachment.uvs;
float z = i * zSpacing;
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;
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) {
SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment;
int meshVertexCount = meshAttachment.uvs.Length;
if (tempVertices.Length < meshVertexCount)
this.tempVertices = tempVertices = new float[meshVertexCount];
meshAttachment.ComputeWorldVertices(slot, tempVertices);
} else {
SkinnedMeshAttachment skinnedMeshAttachment = attachment as SkinnedMeshAttachment;
if (skinnedMeshAttachment != null) {
int meshVertexCount = skinnedMeshAttachment.uvs.Length;
if (tempVertices.Length < meshVertexCount)
this.tempVertices = tempVertices = new float[meshVertexCount];
skinnedMeshAttachment.ComputeWorldVertices(slot, tempVertices);
color.a = (byte)(a * slot.a * meshAttachment.a);
color.r = (byte)(r * slot.r * meshAttachment.r * color.a);
color.g = (byte)(g * slot.g * meshAttachment.g * color.a);
color.b = (byte)(b * slot.b * meshAttachment.b * color.a);
if (slot.data.blendMode == BlendMode.additive) color.a = 0;
color.a = (byte)(a * slot.a * skinnedMeshAttachment.a);
color.r = (byte)(r * slot.r * skinnedMeshAttachment.r * color.a);
color.g = (byte)(g * slot.g * skinnedMeshAttachment.g * color.a);
color.b = (byte)(b * slot.b * skinnedMeshAttachment.b * color.a);
if (slot.data.blendMode == BlendMode.additive) color.a = 0;
float[] meshUVs = meshAttachment.uvs;
float z = i * zSpacing;
for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) {
vertices[vertexIndex] = new Vector3(tempVertices[ii], tempVertices[ii + 1], z);
colors[vertexIndex] = color;
uvs[vertexIndex] = new Vector2(meshUVs[ii], meshUVs[ii + 1]);
float[] meshUVs = skinnedMeshAttachment.uvs;
float z = i * zSpacing;
for (int ii = 0; ii < meshVertexCount; ii += 2, vertexIndex++) {
vertices[vertexIndex].x = tempVertices[ii];
vertices[vertexIndex].y = tempVertices[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.uv = uvs;
int submeshCount = submeshMaterials.Count;
mesh.subMeshCount = submeshCount;
for (int i = 0; i < submeshCount; ++i)
mesh.SetTriangles(submeshes[i].triangles, i);
mesh.RecalculateBounds();
if (mustUpdateMeshStructure) {
int submeshCount = submeshMaterials.Count;
mesh.subMeshCount = submeshCount;
for (int i = 0; i < submeshCount; ++i)
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) {
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) {
foreach (var submeshRenderer in submeshRenderers) {
if (submeshRenderer.submeshIndex < sharedMaterials.Length)
for (int i = 0; i < submeshRenderers.Length; i++) {
SkeletonUtilitySubmeshRenderer submeshRenderer = submeshRenderers[i];
if (submeshRenderer.submeshIndex < sharedMaterials.Length) {
submeshRenderer.SetMesh(meshRenderer, useMesh1 ? mesh1 : mesh2, sharedMaterials[submeshRenderer.submeshIndex]);
else
} else {
submeshRenderer.GetComponent<Renderer>().enabled = false;
}
}
}
useMesh1 = !useMesh1;
}
private bool CheckIfMustUpdateMeshStructure(ExposedList<int> attachmentsTriangleCountTemp, ExposedList<bool> attachmentsFlipStateTemp, ExposedList<LastState.AddSubmeshArguments> addSubmeshArgumentsTemp) {
// 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) {
private void AddSubmesh (Material material, int startSlot, int endSlot, int triangleCount, int firstVertex, bool lastSubmesh, ExposedList<bool> flipStates) {
int submeshIndex = submeshMaterials.Count;
submeshMaterials.Add(material);
@ -400,7 +623,7 @@ public class SkeletonRenderer : MonoBehaviour {
else if (immutableTriangles)
return;
Submesh submesh = submeshes[submeshIndex];
Submesh submesh = submeshes.Items[submeshIndex];
int[] triangles = submesh.triangles;
int trianglesCapacity = triangles.Length;
@ -434,12 +657,12 @@ public class SkeletonRenderer : MonoBehaviour {
}
// Store triangles.
List<Slot> drawOrder = skeleton.DrawOrder;
ExposedList<Slot> drawOrder = skeleton.DrawOrder;
for (int i = startSlot, triangleIndex = 0; i < endSlot; i++) {
Slot slot = drawOrder[i];
Slot slot = drawOrder.Items[i];
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 (!flip) {
@ -464,16 +687,18 @@ public class SkeletonRenderer : MonoBehaviour {
}
int[] attachmentTriangles;
int attachmentVertexCount;
if (attachment is MeshAttachment) {
MeshAttachment meshAttachment = (MeshAttachment)attachment;
MeshAttachment meshAttachment = attachment as MeshAttachment;
if (meshAttachment != null) {
attachmentVertexCount = meshAttachment.vertices.Length >> 1;
attachmentTriangles = meshAttachment.triangles;
} else if (attachment is SkinnedMeshAttachment) {
SkinnedMeshAttachment meshAttachment = (SkinnedMeshAttachment)attachment;
attachmentVertexCount = meshAttachment.uvs.Length >> 1;
attachmentTriangles = meshAttachment.triangles;
} else
continue;
} else {
SkinnedMeshAttachment skinnedMeshAttachment = attachment as SkinnedMeshAttachment;
if (skinnedMeshAttachment != null) {
attachmentVertexCount = skinnedMeshAttachment.uvs.Length >> 1;
attachmentTriangles = skinnedMeshAttachment.triangles;
} else
continue;
}
if (flip) {
for (int ii = 0, nn = attachmentTriangles.Length; ii < nn; ii += 3, triangleIndex += 3) {
@ -494,24 +719,62 @@ public class SkeletonRenderer : MonoBehaviour {
#if UNITY_EDITOR
void OnDrawGizmos () {
// Make selection easier by drawing a clear gizmo over the skeleton.
if (vertices == null) return;
Vector3 gizmosCenter = new Vector3();
Vector3 gizmosSize = new Vector3();
Vector3 min = new Vector3(float.MaxValue, float.MaxValue, 0f);
Vector3 max = new Vector3(float.MinValue, float.MinValue, 0f);
foreach (Vector3 vert in vertices) {
min = Vector3.Min(min, vert);
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);
meshFilter = GetComponent<MeshFilter>();
if (meshFilter == null) return;
Mesh mesh = meshFilter.sharedMesh;
if (mesh == null) return;
Bounds meshBounds = mesh.bounds;
Gizmos.color = Color.clear;
Gizmos.matrix = transform.localToWorldMatrix;
Gizmos.DrawCube(gizmosCenter, gizmosSize);
Gizmos.DrawCube(meshBounds.center, meshBounds.size);
}
#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 {

View File

@ -61,7 +61,7 @@ public class SkeletonUtilityBoneInspector : Editor {
currentSkinName = skin.Name;
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) {
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();
if (topValue != "")
menu.AddItem(new GUIContent(topValue), current == topValue, callback, null);
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();
@ -344,4 +344,4 @@ public class SkeletonUtilityBoneInspector : Editor {
utilBone.gameObject.AddComponent<Rigidbody>();
}
}
}

View File

@ -132,7 +132,7 @@ public class SkeletonUtilityInspector : Editor {
List<Attachment> attachments = new List<Attachment>();
skin.FindAttachmentsForSlot(i, attachments);
attachmentTable.Add(skeleton.Slots[i], attachments);
attachmentTable.Add(skeleton.Slots.Items[i], attachments);
}
}
@ -280,4 +280,4 @@ public class SkeletonUtilityInspector : Editor {
Selection.activeGameObject = skeletonUtility.SpawnRoot(SkeletonUtilityBone.Mode.Override, true, true, true);
AttachIconsToChildren(skeletonUtility.boneRoot);
}
}
}

View File

@ -224,9 +224,9 @@ public class SkeletonUtility : MonoBehaviour {
if (boneRoot != null) {
List<string> constraintTargetNames = new List<string>();
foreach (IkConstraint c in skeletonRenderer.skeleton.IkConstraints) {
constraintTargetNames.Add(c.Target.Data.Name);
}
ExposedList<IkConstraint> ikConstraints = skeletonRenderer.skeleton.IkConstraints;
for (int i = 0, n = ikConstraints.Count; i < n; i++)
constraintTargetNames.Add(ikConstraints.Items[i].Target.Data.Name);
foreach (var b in utilityBones) {
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) {
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);
}
@ -399,4 +401,4 @@ public class SkeletonUtility : MonoBehaviour {
if (disablePrimaryRenderer)
GetComponent<Renderer>().enabled = false;
}
}
}