mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-06 07:14:55 +08:00
Merge pull request #375 from LostPolygon/optimizations
A bunch of optimizations
This commit is contained in:
commit
054e303d2e
@ -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) {
|
||||
|
||||
@ -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());
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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>
|
||||
|
||||
585
spine-csharp/src/ExposedList.cs
Normal file
585
spine-csharp/src/ExposedList.cs
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
|
||||
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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));
|
||||
}
|
||||
|
||||
@ -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();
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -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 {
|
||||
|
||||
@ -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>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user