mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-25 22:23:42 +08:00
[haxe] Port latest libgdx timeline, sequence, draw order, and follow-up fixes. See #2989.
This commit is contained in:
parent
f7ed100aa8
commit
2ba91231f3
@ -29,20 +29,14 @@
|
|||||||
|
|
||||||
package spine;
|
package spine;
|
||||||
|
|
||||||
interface HasTextureRegion {
|
interface HasSequence {
|
||||||
/** The name used to find the region. */
|
|
||||||
public var path:String;
|
public var path:String;
|
||||||
|
|
||||||
/** Sets the region used to draw the attachment. After setting the region or if the region's properties are changed,
|
|
||||||
* updateRegion() must be called. */
|
|
||||||
public var region:TextureRegion;
|
|
||||||
|
|
||||||
/** The color to tint the attachment. */
|
/** The color to tint the attachment. */
|
||||||
public var color:Color;
|
public var color:Color;
|
||||||
|
|
||||||
public var sequence:Sequence;
|
public var sequence:Sequence;
|
||||||
|
|
||||||
/** Updates any values the attachment calculates using the region. Must be called after setting the
|
/** Calls Sequence.update() on this attachment's sequence. */
|
||||||
* region or if the region's properties are changed. */
|
public function updateSequence():Void;
|
||||||
public function updateRegion():Void;
|
|
||||||
}
|
}
|
||||||
@ -29,7 +29,11 @@
|
|||||||
|
|
||||||
package spine;
|
package spine;
|
||||||
|
|
||||||
/** A sequence for an attachment with multiple texture regions, which can be used for animation. */
|
import spine.attachments.MeshAttachment;
|
||||||
|
import spine.attachments.RegionAttachment;
|
||||||
|
|
||||||
|
/** Holds texture regions, UVs, and vertex offsets for rendering a region or mesh attachment. Regions must
|
||||||
|
* be populated and update() called before use. */
|
||||||
class Sequence {
|
class Sequence {
|
||||||
private static var _nextID = 0;
|
private static var _nextID = 0;
|
||||||
|
|
||||||
@ -37,49 +41,109 @@ class Sequence {
|
|||||||
public var id = _nextID++;
|
public var id = _nextID++;
|
||||||
|
|
||||||
public var regions:Array<TextureRegion>;
|
public var regions:Array<TextureRegion>;
|
||||||
|
public var pathSuffix:Bool;
|
||||||
|
public var uvs:Array<Array<Float>>;
|
||||||
|
public var offsets:Array<Array<Float>>;
|
||||||
public var start = 0;
|
public var start = 0;
|
||||||
public var digits = 0;
|
public var digits = 0;
|
||||||
|
|
||||||
/** The index of the region to show for the setup pose. */
|
/** The index of the region to show for the setup pose. */
|
||||||
public var setupIndex = 0;
|
public var setupIndex = 0;
|
||||||
|
|
||||||
public function new(count:Int) {
|
public function new(count:Int, pathSuffix:Bool) {
|
||||||
this.regions = new Array<TextureRegion>();
|
this.regions = new Array<TextureRegion>();
|
||||||
this.regions.resize(count);
|
this.regions.resize(count);
|
||||||
|
this.pathSuffix = pathSuffix;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Copy constructor. */
|
/** Copy constructor. */
|
||||||
public function copy():Sequence {
|
public function copy():Sequence {
|
||||||
var copy = new Sequence(this.regions.length);
|
var regionCount = this.regions.length;
|
||||||
for (i in 0...this.regions.length) {
|
var copy = new Sequence(regionCount, this.pathSuffix);
|
||||||
|
for (i in 0...regionCount)
|
||||||
copy.regions[i] = this.regions[i];
|
copy.regions[i] = this.regions[i];
|
||||||
}
|
|
||||||
copy.start = this.start;
|
copy.start = this.start;
|
||||||
copy.digits = this.digits;
|
copy.digits = this.digits;
|
||||||
copy.setupIndex = this.setupIndex;
|
copy.setupIndex = this.setupIndex;
|
||||||
|
|
||||||
|
if (this.uvs != null) {
|
||||||
|
var length = this.uvs[0].length;
|
||||||
|
copy.uvs = new Array<Array<Float>>();
|
||||||
|
copy.uvs.resize(regionCount);
|
||||||
|
for (i in 0...regionCount) {
|
||||||
|
copy.uvs[i] = new Array<Float>();
|
||||||
|
copy.uvs[i].resize(length);
|
||||||
|
for (j in 0...length)
|
||||||
|
copy.uvs[i][j] = this.uvs[i][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (this.offsets != null) {
|
||||||
|
copy.offsets = new Array<Array<Float>>();
|
||||||
|
copy.offsets.resize(regionCount);
|
||||||
|
for (i in 0...regionCount) {
|
||||||
|
copy.offsets[i] = new Array<Float>();
|
||||||
|
copy.offsets[i].resize(8);
|
||||||
|
for (j in 0...8)
|
||||||
|
copy.offsets[i][j] = this.offsets[i][j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function apply(slot:SlotPose, attachment:HasTextureRegion) {
|
/** Computes UVs and offsets for the specified attachment. Must be called if the regions or attachment properties are
|
||||||
var index:Int = slot.sequenceIndex;
|
* changed. */
|
||||||
if (index == -1)
|
public function update(attachment:HasSequence):Void {
|
||||||
index = this.setupIndex;
|
var regionCount = this.regions.length;
|
||||||
if (index >= this.regions.length)
|
if (Std.isOfType(attachment, RegionAttachment)) {
|
||||||
index = this.regions.length - 1;
|
var region:RegionAttachment = cast(attachment, RegionAttachment);
|
||||||
var region = this.regions[index];
|
this.uvs = new Array<Array<Float>>();
|
||||||
if (attachment.region != region) {
|
this.uvs.resize(regionCount);
|
||||||
attachment.region = region;
|
this.offsets = new Array<Array<Float>>();
|
||||||
attachment.updateRegion();
|
this.offsets.resize(regionCount);
|
||||||
|
for (i in 0...regionCount) {
|
||||||
|
this.uvs[i] = new Array<Float>();
|
||||||
|
this.uvs[i].resize(8);
|
||||||
|
this.offsets[i] = new Array<Float>();
|
||||||
|
this.offsets[i].resize(8);
|
||||||
|
RegionAttachment.computeUVs(this.regions[i], region.x, region.y, region.scaleX, region.scaleY, region.rotation,
|
||||||
|
region.width, region.height, this.offsets[i], this.uvs[i]);
|
||||||
|
}
|
||||||
|
} else if (Std.isOfType(attachment, MeshAttachment)) {
|
||||||
|
var mesh:MeshAttachment = cast(attachment, MeshAttachment);
|
||||||
|
var regionUVs = mesh.regionUVs;
|
||||||
|
this.uvs = new Array<Array<Float>>();
|
||||||
|
this.uvs.resize(regionCount);
|
||||||
|
this.offsets = null;
|
||||||
|
for (i in 0...regionCount) {
|
||||||
|
this.uvs[i] = new Array<Float>();
|
||||||
|
this.uvs[i].resize(regionUVs.length);
|
||||||
|
MeshAttachment.computeUVs(this.regions[i], regionUVs, this.uvs[i]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function resolveIndex(pose:SlotPose):Int {
|
||||||
|
var index:Int = pose.sequenceIndex;
|
||||||
|
if (index == -1) index = this.setupIndex;
|
||||||
|
if (index >= this.regions.length) index = this.regions.length - 1;
|
||||||
|
return index;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getUVs(index:Int):Array<Float> {
|
||||||
|
return this.uvs[index];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function getHasPathSuffix():Bool {
|
||||||
|
return this.pathSuffix;
|
||||||
|
}
|
||||||
|
|
||||||
public function getPath(basePath:String, index:Int):String {
|
public function getPath(basePath:String, index:Int):String {
|
||||||
|
if (!this.pathSuffix) return basePath;
|
||||||
var result = basePath;
|
var result = basePath;
|
||||||
var frame = Std.string(this.start + index);
|
var frame = Std.string(this.start + index);
|
||||||
|
for (i in 0...(this.digits - frame.length))
|
||||||
for (i in 0...(this.digits - frame.length)) {
|
|
||||||
result += "0";
|
result += "0";
|
||||||
}
|
|
||||||
result += frame;
|
result += frame;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -443,7 +443,8 @@ class Skeleton {
|
|||||||
verticesLength = 8;
|
verticesLength = 8;
|
||||||
_tempVertices.resize(verticesLength);
|
_tempVertices.resize(verticesLength);
|
||||||
vertices = _tempVertices;
|
vertices = _tempVertices;
|
||||||
cast(attachment, RegionAttachment).computeWorldVertices(slot, vertices, 0, 2);
|
var region:RegionAttachment = cast(attachment, RegionAttachment);
|
||||||
|
region.computeWorldVertices(slot, region.getOffsets(slot.applied), vertices, 0, 2);
|
||||||
triangles = Skeleton.quadTriangles;
|
triangles = Skeleton.quadTriangles;
|
||||||
} else if (Std.isOfType(attachment, MeshAttachment)) {
|
} else if (Std.isOfType(attachment, MeshAttachment)) {
|
||||||
var mesh:MeshAttachment = cast(attachment, MeshAttachment);
|
var mesh:MeshAttachment = cast(attachment, MeshAttachment);
|
||||||
|
|||||||
@ -41,6 +41,7 @@ import spine.animation.BoneTimeline2;
|
|||||||
import spine.animation.CurveTimeline1;
|
import spine.animation.CurveTimeline1;
|
||||||
import spine.animation.CurveTimeline;
|
import spine.animation.CurveTimeline;
|
||||||
import spine.animation.DeformTimeline;
|
import spine.animation.DeformTimeline;
|
||||||
|
import spine.animation.DrawOrderFolderTimeline;
|
||||||
import spine.animation.DrawOrderTimeline;
|
import spine.animation.DrawOrderTimeline;
|
||||||
import spine.animation.EventTimeline;
|
import spine.animation.EventTimeline;
|
||||||
import spine.animation.IkConstraintTimeline;
|
import spine.animation.IkConstraintTimeline;
|
||||||
@ -349,7 +350,7 @@ class SkeletonBinary {
|
|||||||
data.slot = slots[input.readInt(true)];
|
data.slot = slots[input.readInt(true)];
|
||||||
var flags = input.readByte();
|
var flags = input.readByte();
|
||||||
data.skinRequired = (flags & 1) != 0;
|
data.skinRequired = (flags & 1) != 0;
|
||||||
data.positionMode = PositionMode.values[(flags >> 1) & 2];
|
data.positionMode = PositionMode.values[(flags >> 1) & 1];
|
||||||
data.spacingMode = SpacingMode.values[(flags >> 2) & 3];
|
data.spacingMode = SpacingMode.values[(flags >> 2) & 3];
|
||||||
data.rotateMode = RotateMode.values[(flags >> 4) & 3];
|
data.rotateMode = RotateMode.values[(flags >> 4) & 3];
|
||||||
if ((flags & 128) != 0)
|
if ((flags & 128) != 0)
|
||||||
@ -467,8 +468,7 @@ class SkeletonBinary {
|
|||||||
throw new SpineException("Parent mesh not found: " + linkedMesh.parent);
|
throw new SpineException("Parent mesh not found: " + linkedMesh.parent);
|
||||||
linkedMesh.mesh.timelineAttachment = linkedMesh.inheritTimeline ? cast(parent, VertexAttachment) : linkedMesh.mesh;
|
linkedMesh.mesh.timelineAttachment = linkedMesh.inheritTimeline ? cast(parent, VertexAttachment) : linkedMesh.mesh;
|
||||||
linkedMesh.mesh.parentMesh = cast(parent, MeshAttachment);
|
linkedMesh.mesh.parentMesh = cast(parent, MeshAttachment);
|
||||||
if (linkedMesh.mesh.region != null)
|
linkedMesh.mesh.updateSequence();
|
||||||
linkedMesh.mesh.updateRegion();
|
|
||||||
}
|
}
|
||||||
linkedMeshes.resize(0);
|
linkedMeshes.resize(0);
|
||||||
|
|
||||||
@ -546,8 +546,10 @@ class SkeletonBinary {
|
|||||||
return skin;
|
return skin;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function readSequence(input:BinaryInput):Sequence {
|
private function readSequence(input:BinaryInput, hasPathSuffix:Bool):Sequence {
|
||||||
var sequence = new Sequence(input.readInt(true));
|
if (!hasPathSuffix)
|
||||||
|
return new Sequence(1, false);
|
||||||
|
var sequence = new Sequence(input.readInt(true), true);
|
||||||
sequence.start = input.readInt(true);
|
sequence.start = input.readInt(true);
|
||||||
sequence.digits = input.readInt(true);
|
sequence.digits = input.readInt(true);
|
||||||
sequence.setupIndex = input.readInt(true);
|
sequence.setupIndex = input.readInt(true);
|
||||||
@ -574,7 +576,7 @@ class SkeletonBinary {
|
|||||||
case AttachmentType.region:
|
case AttachmentType.region:
|
||||||
path = (flags & 16) != 0 ? input.readStringRef() : null;
|
path = (flags & 16) != 0 ? input.readStringRef() : null;
|
||||||
color = (flags & 32) != 0 ? input.readInt32() : 0xffffffff;
|
color = (flags & 32) != 0 ? input.readInt32() : 0xffffffff;
|
||||||
var sequence = (flags & 64) != 0 ? readSequence(input) : null;
|
var sequence = readSequence(input, (flags & 64) != 0);
|
||||||
rotation = (flags & 128) != 0 ? input.readFloat() : 0;
|
rotation = (flags & 128) != 0 ? input.readFloat() : 0;
|
||||||
x = input.readFloat();
|
x = input.readFloat();
|
||||||
y = input.readFloat();
|
y = input.readFloat();
|
||||||
@ -597,9 +599,7 @@ class SkeletonBinary {
|
|||||||
region.width = width * scale;
|
region.width = width * scale;
|
||||||
region.height = height * scale;
|
region.height = height * scale;
|
||||||
region.color.setFromRgba8888(color);
|
region.color.setFromRgba8888(color);
|
||||||
region.sequence = sequence;
|
region.updateSequence();
|
||||||
if (region.region != null)
|
|
||||||
region.updateRegion();
|
|
||||||
return region;
|
return region;
|
||||||
case AttachmentType.boundingbox:
|
case AttachmentType.boundingbox:
|
||||||
vertices = readVertices(input, (flags & 16) != 0);
|
vertices = readVertices(input, (flags & 16) != 0);
|
||||||
@ -618,7 +618,7 @@ class SkeletonBinary {
|
|||||||
case AttachmentType.mesh:
|
case AttachmentType.mesh:
|
||||||
path = (flags & 16) != 0 ? input.readStringRef() : name;
|
path = (flags & 16) != 0 ? input.readStringRef() : name;
|
||||||
color = (flags & 32) != 0 ? input.readInt32() : 0xffffffff;
|
color = (flags & 32) != 0 ? input.readInt32() : 0xffffffff;
|
||||||
var sequence = (flags & 64) != 0 ? readSequence(input) : null;
|
var sequence = readSequence(input, (flags & 64) != 0);
|
||||||
var hullLength = input.readInt(true);
|
var hullLength = input.readInt(true);
|
||||||
vertices = readVertices(input, (flags & 128) != 0);
|
vertices = readVertices(input, (flags & 128) != 0);
|
||||||
var uvs:Array<Float> = readFloatArray(input, vertices.length, 1);
|
var uvs:Array<Float> = readFloatArray(input, vertices.length, 1);
|
||||||
@ -637,28 +637,26 @@ class SkeletonBinary {
|
|||||||
return null;
|
return null;
|
||||||
mesh.path = path;
|
mesh.path = path;
|
||||||
mesh.color.setFromRgba8888(color);
|
mesh.color.setFromRgba8888(color);
|
||||||
|
mesh.hullLength = hullLength << 1;
|
||||||
if (vertices.bones.length > 0)
|
if (vertices.bones.length > 0)
|
||||||
mesh.bones = vertices.bones;
|
mesh.bones = vertices.bones;
|
||||||
mesh.vertices = vertices.vertices;
|
mesh.vertices = vertices.vertices;
|
||||||
mesh.worldVerticesLength = vertices.length;
|
mesh.worldVerticesLength = vertices.length;
|
||||||
mesh.triangles = triangles;
|
|
||||||
mesh.regionUVs = uvs;
|
mesh.regionUVs = uvs;
|
||||||
if (mesh.region != null)
|
mesh.triangles = triangles;
|
||||||
mesh.updateRegion();
|
|
||||||
mesh.hullLength = hullLength << 1;
|
|
||||||
mesh.sequence = sequence;
|
|
||||||
if (nonessential) {
|
if (nonessential) {
|
||||||
mesh.edges = edges;
|
mesh.edges = edges;
|
||||||
mesh.width = width * scale;
|
mesh.width = width * scale;
|
||||||
mesh.height = height * scale;
|
mesh.height = height * scale;
|
||||||
}
|
}
|
||||||
|
mesh.updateSequence();
|
||||||
return mesh;
|
return mesh;
|
||||||
case AttachmentType.linkedmesh:
|
case AttachmentType.linkedmesh:
|
||||||
path = (flags & 16) != 0 ? input.readStringRef() : name;
|
path = (flags & 16) != 0 ? input.readStringRef() : name;
|
||||||
if (path == null)
|
if (path == null)
|
||||||
throw new SpineException("Path of linked mesh must not be null");
|
throw new SpineException("Path of linked mesh must not be null");
|
||||||
color = (flags & 32) != 0 ? input.readInt32() : 0xffffffff;
|
color = (flags & 32) != 0 ? input.readInt32() : 0xffffffff;
|
||||||
var sequence = (flags & 64) != 0 ? this.readSequence(input) : null;
|
var sequence = readSequence(input, (flags & 64) != 0);
|
||||||
var inheritTimelines:Bool = (flags & 128) != 0;
|
var inheritTimelines:Bool = (flags & 128) != 0;
|
||||||
var skinIndex = input.readInt(true);
|
var skinIndex = input.readInt(true);
|
||||||
var parent:String = input.readStringRef();
|
var parent:String = input.readStringRef();
|
||||||
@ -672,7 +670,6 @@ class SkeletonBinary {
|
|||||||
return null;
|
return null;
|
||||||
mesh.path = path;
|
mesh.path = path;
|
||||||
mesh.color.setFromRgba8888(color);
|
mesh.color.setFromRgba8888(color);
|
||||||
mesh.sequence = sequence;
|
|
||||||
if (nonessential) {
|
if (nonessential) {
|
||||||
mesh.width = width * scale;
|
mesh.width = width * scale;
|
||||||
mesh.height = height * scale;
|
mesh.height = height * scale;
|
||||||
@ -746,23 +743,54 @@ class SkeletonBinary {
|
|||||||
vertices.vertices = readFloatArray(input, vertices.length, scale);
|
vertices.vertices = readFloatArray(input, vertices.length, scale);
|
||||||
return vertices;
|
return vertices;
|
||||||
}
|
}
|
||||||
|
var n:Int = input.readInt(true);
|
||||||
|
var bones:Array<Int> = new Array<Int>();
|
||||||
var weights:Array<Float> = new Array<Float>();
|
var weights:Array<Float> = new Array<Float>();
|
||||||
var bonesArray:Array<Int> = new Array<Int>();
|
var b:Int = 0, w:Int = 0;
|
||||||
for (i in 0...vertexCount) {
|
while (b < n) {
|
||||||
var boneCount:Int = input.readInt(true);
|
var boneCount:Int = input.readInt(true);
|
||||||
bonesArray.push(boneCount);
|
bones[b++] = boneCount;
|
||||||
for (ii in 0...boneCount) {
|
for (ii in 0...boneCount) {
|
||||||
bonesArray.push(input.readInt(true));
|
bones[b++] = input.readInt(true);
|
||||||
weights.push(input.readFloat() * scale);
|
weights[w] = input.readFloat() * scale;
|
||||||
weights.push(input.readFloat() * scale);
|
weights[w + 1] = input.readFloat() * scale;
|
||||||
weights.push(input.readFloat());
|
weights[w + 2] = input.readFloat();
|
||||||
|
w += 3;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
vertices.vertices = weights;
|
vertices.vertices = weights;
|
||||||
vertices.bones = bonesArray;
|
vertices.bones = bones;
|
||||||
return vertices;
|
return vertices;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function readDrawOrder(input:BinaryInput, slotCount:Int):Array<Int> {
|
||||||
|
var changeCount:Int = input.readInt(true);
|
||||||
|
if (changeCount == 0)
|
||||||
|
return null;
|
||||||
|
var drawOrder:Array<Int> = new Array<Int>();
|
||||||
|
drawOrder.resize(slotCount);
|
||||||
|
for (i in 0...slotCount)
|
||||||
|
drawOrder[i] = -1;
|
||||||
|
var unchanged:Array<Int> = new Array<Int>();
|
||||||
|
unchanged.resize(slotCount - changeCount);
|
||||||
|
var originalIndex:Int = 0, unchangedIndex:Int = 0;
|
||||||
|
for (i in 0...changeCount) {
|
||||||
|
var slotIndex:Int = input.readInt(true);
|
||||||
|
while (originalIndex != slotIndex)
|
||||||
|
unchanged[unchangedIndex++] = originalIndex++;
|
||||||
|
drawOrder[originalIndex + input.readInt(true)] = originalIndex++;
|
||||||
|
}
|
||||||
|
while (originalIndex < slotCount)
|
||||||
|
unchanged[unchangedIndex++] = originalIndex++;
|
||||||
|
var i:Int = slotCount - 1;
|
||||||
|
while (i >= 0) {
|
||||||
|
if (drawOrder[i] == -1)
|
||||||
|
drawOrder[i] = unchanged[--unchangedIndex];
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
return drawOrder;
|
||||||
|
}
|
||||||
|
|
||||||
private function readFloatArray(input:BinaryInput, n:Int, scale:Float):Array<Float> {
|
private function readFloatArray(input:BinaryInput, n:Int, scale:Float):Array<Float> {
|
||||||
var array:Array<Float> = new Array<Float>();
|
var array:Array<Float> = new Array<Float>();
|
||||||
if (scale == 1) {
|
if (scale == 1) {
|
||||||
@ -1337,7 +1365,7 @@ class SkeletonBinary {
|
|||||||
}
|
}
|
||||||
timelines.push(deformTimeline);
|
timelines.push(deformTimeline);
|
||||||
case ATTACHMENT_SEQUENCE:
|
case ATTACHMENT_SEQUENCE:
|
||||||
var timeline = new SequenceTimeline(frameCount, slotIndex, cast(attachment, HasTextureRegion));
|
var timeline = new SequenceTimeline(frameCount, slotIndex, cast(attachment, HasSequence));
|
||||||
for (frame in 0...frameCount) {
|
for (frame in 0...frameCount) {
|
||||||
var time = input.readFloat();
|
var time = input.readFloat();
|
||||||
var modeAndIndex = input.readInt32();
|
var modeAndIndex = input.readInt32();
|
||||||
@ -1350,48 +1378,31 @@ class SkeletonBinary {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw order timelines.
|
// Draw order timeline.
|
||||||
|
var slotCount:Int = skeletonData.slots.length;
|
||||||
var drawOrderCount:Int = input.readInt(true);
|
var drawOrderCount:Int = input.readInt(true);
|
||||||
if (drawOrderCount > 0) {
|
if (drawOrderCount > 0) {
|
||||||
var drawOrderTimeline:DrawOrderTimeline = new DrawOrderTimeline(drawOrderCount);
|
var drawOrderTimeline:DrawOrderTimeline = new DrawOrderTimeline(drawOrderCount);
|
||||||
var slotCount:Int = skeletonData.slots.length;
|
for (i in 0...drawOrderCount)
|
||||||
for (i in 0...drawOrderCount) {
|
drawOrderTimeline.setFrame(i, input.readFloat(), readDrawOrder(input, slotCount));
|
||||||
time = input.readFloat();
|
|
||||||
var offsetCount:Int = input.readInt(true);
|
|
||||||
var drawOrder:Array<Int> = new Array<Int>();
|
|
||||||
drawOrder.resize(slotCount);
|
|
||||||
var ii:Int = slotCount - 1;
|
|
||||||
while (ii >= 0) {
|
|
||||||
drawOrder[ii--] = -1;
|
|
||||||
}
|
|
||||||
var unchanged:Array<Int> = new Array<Int>();
|
|
||||||
unchanged.resize(slotCount - offsetCount);
|
|
||||||
var originalIndex:Int = 0, unchangedIndex:Int = 0;
|
|
||||||
for (ii in 0...offsetCount) {
|
|
||||||
slotIndex = input.readInt(true);
|
|
||||||
// Collect unchanged items.
|
|
||||||
while (originalIndex != slotIndex) {
|
|
||||||
unchanged[unchangedIndex++] = originalIndex++;
|
|
||||||
}
|
|
||||||
// Set changed items.
|
|
||||||
drawOrder[originalIndex + input.readInt(true)] = originalIndex++;
|
|
||||||
}
|
|
||||||
// Collect remaining unchanged items.
|
|
||||||
while (originalIndex < slotCount) {
|
|
||||||
unchanged[unchangedIndex++] = originalIndex++;
|
|
||||||
}
|
|
||||||
// Fill in unchanged items.
|
|
||||||
ii = slotCount - 1;
|
|
||||||
while (ii >= 0) {
|
|
||||||
if (drawOrder[ii] == -1)
|
|
||||||
drawOrder[ii] = unchanged[--unchangedIndex];
|
|
||||||
ii--;
|
|
||||||
}
|
|
||||||
drawOrderTimeline.setFrame(i, time, drawOrder);
|
|
||||||
}
|
|
||||||
timelines.push(drawOrderTimeline);
|
timelines.push(drawOrderTimeline);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw order folder timelines.
|
||||||
|
var folderCount:Int = input.readInt(true);
|
||||||
|
for (i in 0...folderCount) {
|
||||||
|
var folderSlotCount:Int = input.readInt(true);
|
||||||
|
var folderSlots:Array<Int> = new Array<Int>();
|
||||||
|
folderSlots.resize(folderSlotCount);
|
||||||
|
for (ii in 0...folderSlotCount)
|
||||||
|
folderSlots[ii] = input.readInt(true);
|
||||||
|
var keyCount:Int = input.readInt(true);
|
||||||
|
var folderTimeline = new DrawOrderFolderTimeline(keyCount, folderSlots, slotCount);
|
||||||
|
for (ii in 0...keyCount)
|
||||||
|
folderTimeline.setFrame(ii, input.readFloat(), readDrawOrder(input, folderSlotCount));
|
||||||
|
timelines.push(folderTimeline);
|
||||||
|
}
|
||||||
|
|
||||||
// Event timelines.
|
// Event timelines.
|
||||||
var eventCount:Int = input.readInt(true);
|
var eventCount:Int = input.readInt(true);
|
||||||
if (eventCount > 0) {
|
if (eventCount > 0) {
|
||||||
|
|||||||
@ -33,6 +33,7 @@ import haxe.io.Bytes;
|
|||||||
import spine.animation.Animation;
|
import spine.animation.Animation;
|
||||||
import spine.atlas.TextureAtlas;
|
import spine.atlas.TextureAtlas;
|
||||||
import spine.attachments.AtlasAttachmentLoader;
|
import spine.attachments.AtlasAttachmentLoader;
|
||||||
|
import spine.SliderData;
|
||||||
|
|
||||||
/** Stores the setup pose and all of the stateless data for a skeleton.
|
/** Stores the setup pose and all of the stateless data for a skeleton.
|
||||||
*
|
*
|
||||||
@ -191,6 +192,20 @@ class SkeletonData {
|
|||||||
|
|
||||||
// --- Animations.
|
// --- Animations.
|
||||||
|
|
||||||
|
/** Collects animations used by slider constraints.
|
||||||
|
* Slider animations are designed to be applied by slider constraints rather than on their own. Applications that have a user
|
||||||
|
* choose an animation may want to exclude them. */
|
||||||
|
public function findSliderAnimations(animations:Array<Animation>):Array<Animation> {
|
||||||
|
for (constraint in constraints) {
|
||||||
|
if (Std.isOfType(constraint, SliderData)) {
|
||||||
|
var data:SliderData = cast(constraint, SliderData);
|
||||||
|
if (data.animation != null)
|
||||||
|
animations.push(data.animation);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return animations;
|
||||||
|
}
|
||||||
|
|
||||||
/** Finds an animation by comparing each animation's name. It is more efficient to cache the results of this method than to
|
/** Finds an animation by comparing each animation's name. It is more efficient to cache the results of this method than to
|
||||||
* call it multiple times.
|
* call it multiple times.
|
||||||
* @param animationName The name of the animation to find.
|
* @param animationName The name of the animation to find.
|
||||||
|
|||||||
@ -42,6 +42,7 @@ import spine.animation.AttachmentTimeline;
|
|||||||
import spine.animation.CurveTimeline1;
|
import spine.animation.CurveTimeline1;
|
||||||
import spine.animation.CurveTimeline;
|
import spine.animation.CurveTimeline;
|
||||||
import spine.animation.DeformTimeline;
|
import spine.animation.DeformTimeline;
|
||||||
|
import spine.animation.DrawOrderFolderTimeline;
|
||||||
import spine.animation.DrawOrderTimeline;
|
import spine.animation.DrawOrderTimeline;
|
||||||
import spine.animation.EventTimeline;
|
import spine.animation.EventTimeline;
|
||||||
import spine.animation.IkConstraintTimeline;
|
import spine.animation.IkConstraintTimeline;
|
||||||
@ -497,8 +498,7 @@ class SkeletonJson {
|
|||||||
throw new SpineException("Parent mesh not found: " + linkedMesh.parent);
|
throw new SpineException("Parent mesh not found: " + linkedMesh.parent);
|
||||||
linkedMesh.mesh.timelineAttachment = linkedMesh.inheritTimeline ? cast(parentMesh, VertexAttachment) : linkedMesh.mesh;
|
linkedMesh.mesh.timelineAttachment = linkedMesh.inheritTimeline ? cast(parentMesh, VertexAttachment) : linkedMesh.mesh;
|
||||||
linkedMesh.mesh.parentMesh = cast(parentMesh, MeshAttachment);
|
linkedMesh.mesh.parentMesh = cast(parentMesh, MeshAttachment);
|
||||||
if (linkedMesh.mesh.region != null)
|
linkedMesh.mesh.updateSequence();
|
||||||
linkedMesh.mesh.updateRegion();
|
|
||||||
}
|
}
|
||||||
linkedMeshes.resize(0);
|
linkedMeshes.resize(0);
|
||||||
|
|
||||||
@ -592,14 +592,11 @@ class SkeletonJson {
|
|||||||
region.rotation = getFloat(map, "rotation");
|
region.rotation = getFloat(map, "rotation");
|
||||||
region.width = getFloat(map, "width") * scale;
|
region.width = getFloat(map, "width") * scale;
|
||||||
region.height = getFloat(map, "height") * scale;
|
region.height = getFloat(map, "height") * scale;
|
||||||
region.sequence = sequence;
|
|
||||||
|
|
||||||
color = Reflect.getProperty(map, "color");
|
color = Reflect.getProperty(map, "color");
|
||||||
if (color != null) {
|
if (color != null) {
|
||||||
region.color.setFromString(color);
|
region.color.setFromString(color);
|
||||||
}
|
}
|
||||||
if (region.region != null)
|
region.updateSequence();
|
||||||
region.updateRegion();
|
|
||||||
return region;
|
return region;
|
||||||
case AttachmentType.mesh, AttachmentType.linkedmesh:
|
case AttachmentType.mesh, AttachmentType.linkedmesh:
|
||||||
var path = getString(map, "path", name);
|
var path = getString(map, "path", name);
|
||||||
@ -616,7 +613,6 @@ class SkeletonJson {
|
|||||||
|
|
||||||
mesh.width = getFloat(map, "width") * scale;
|
mesh.width = getFloat(map, "width") * scale;
|
||||||
mesh.height = getFloat(map, "height") * scale;
|
mesh.height = getFloat(map, "height") * scale;
|
||||||
mesh.sequence = sequence;
|
|
||||||
|
|
||||||
if (Reflect.field(map, "parent") != null) {
|
if (Reflect.field(map, "parent") != null) {
|
||||||
var inheritTimelines:Bool = Reflect.hasField(map, "timelines") ? cast(Reflect.field(map, "timelines"), Bool) : true;
|
var inheritTimelines:Bool = Reflect.hasField(map, "timelines") ? cast(Reflect.field(map, "timelines"), Bool) : true;
|
||||||
@ -628,12 +624,11 @@ class SkeletonJson {
|
|||||||
readVertices(map, mesh, uvs.length);
|
readVertices(map, mesh, uvs.length);
|
||||||
mesh.triangles = getIntArray(map, "triangles");
|
mesh.triangles = getIntArray(map, "triangles");
|
||||||
mesh.regionUVs = uvs;
|
mesh.regionUVs = uvs;
|
||||||
if (mesh.region != null)
|
|
||||||
mesh.updateRegion();
|
|
||||||
|
|
||||||
if (Reflect.field(map, "edges") != null)
|
if (Reflect.field(map, "edges") != null)
|
||||||
mesh.edges = getIntArray(map, "edges");
|
mesh.edges = getIntArray(map, "edges");
|
||||||
mesh.hullLength = getInt(map, "hull") * 2;
|
mesh.hullLength = getInt(map, "hull") * 2;
|
||||||
|
mesh.updateSequence();
|
||||||
return mesh;
|
return mesh;
|
||||||
case AttachmentType.boundingbox:
|
case AttachmentType.boundingbox:
|
||||||
var box:BoundingBoxAttachment = attachmentLoader.newBoundingBoxAttachment(skin, name);
|
var box:BoundingBoxAttachment = attachmentLoader.newBoundingBoxAttachment(skin, name);
|
||||||
@ -689,14 +684,55 @@ class SkeletonJson {
|
|||||||
|
|
||||||
private function readSequence(map:Dynamic) {
|
private function readSequence(map:Dynamic) {
|
||||||
if (map == null)
|
if (map == null)
|
||||||
return null;
|
return new Sequence(1, false);
|
||||||
var sequence = new Sequence(getInt(map, "count", 0));
|
var sequence = new Sequence(getInt(map, "count", 0), true);
|
||||||
sequence.start = getInt(map, "start", 1);
|
sequence.start = getInt(map, "start", 1);
|
||||||
sequence.digits = getInt(map, "digits", 0);
|
sequence.digits = getInt(map, "digits", 0);
|
||||||
sequence.setupIndex = getInt(map, "setup", 0);
|
sequence.setupIndex = getInt(map, "setup", 0);
|
||||||
return sequence;
|
return sequence;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** @param folderSlots Slot names are resolved to positions within this array. If null, slot indices are used as positions. */
|
||||||
|
private function readDrawOrder(skeletonData:SkeletonData, keyMap:Dynamic, slotCount:Int, folderSlots:Array<Int>):Array<Int> {
|
||||||
|
var changes:Array<Dynamic> = Reflect.getProperty(keyMap, "offsets");
|
||||||
|
if (changes == null) return null;
|
||||||
|
var drawOrder:Array<Int> = new Array<Int>();
|
||||||
|
drawOrder.resize(slotCount);
|
||||||
|
for (i in 0...slotCount)
|
||||||
|
drawOrder[i] = -1;
|
||||||
|
var unchanged:Array<Int> = new Array<Int>();
|
||||||
|
unchanged.resize(slotCount - changes.length);
|
||||||
|
var originalIndex:Int = 0, unchangedIndex:Int = 0;
|
||||||
|
for (offsetMap in changes) {
|
||||||
|
var slot = skeletonData.findSlot(Reflect.getProperty(offsetMap, "slot"));
|
||||||
|
if (slot == null) throw new SpineException("Draw order slot not found: " + Reflect.getProperty(offsetMap, "slot"));
|
||||||
|
var index:Int;
|
||||||
|
if (folderSlots == null)
|
||||||
|
index = slot.index;
|
||||||
|
else {
|
||||||
|
index = -1;
|
||||||
|
for (i in 0...slotCount) {
|
||||||
|
if (folderSlots[i] == slot.index) {
|
||||||
|
index = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (index == -1) throw new SpineException("Slot not in folder: " + Reflect.getProperty(offsetMap, "slot"));
|
||||||
|
}
|
||||||
|
while (originalIndex != index)
|
||||||
|
unchanged[unchangedIndex++] = originalIndex++;
|
||||||
|
drawOrder[originalIndex + Reflect.getProperty(offsetMap, "offset")] = originalIndex++;
|
||||||
|
}
|
||||||
|
while (originalIndex < slotCount)
|
||||||
|
unchanged[unchangedIndex++] = originalIndex++;
|
||||||
|
var i:Int = slotCount - 1;
|
||||||
|
while (i >= 0) {
|
||||||
|
if (drawOrder[i] == -1) drawOrder[i] = unchanged[--unchangedIndex];
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
return drawOrder;
|
||||||
|
}
|
||||||
|
|
||||||
private function readVertices(map:Dynamic, attachment:VertexAttachment, verticesLength:Int):Void {
|
private function readVertices(map:Dynamic, attachment:VertexAttachment, verticesLength:Int):Void {
|
||||||
attachment.worldVerticesLength = verticesLength;
|
attachment.worldVerticesLength = verticesLength;
|
||||||
var vertices:Array<Float> = getFloatArray(map, "vertices");
|
var vertices:Array<Float> = getFloatArray(map, "vertices");
|
||||||
@ -1222,7 +1258,7 @@ class SkeletonJson {
|
|||||||
slotMap = Reflect.field(attachmentsMap, slotMapName);
|
slotMap = Reflect.field(attachmentsMap, slotMapName);
|
||||||
slotIndex = skeletonData.findSlot(slotMapName).index;
|
slotIndex = skeletonData.findSlot(slotMapName).index;
|
||||||
if (slotIndex == -1)
|
if (slotIndex == -1)
|
||||||
throw new SpineException("Slot not found: " + slotMapName);
|
throw new SpineException("Attachment slot not found: " + slotMapName);
|
||||||
for (attachmentMapName in Reflect.fields(slotMap)) {
|
for (attachmentMapName in Reflect.fields(slotMap)) {
|
||||||
var attachmentMap = Reflect.field(slotMap, attachmentMapName);
|
var attachmentMap = Reflect.field(slotMap, attachmentMapName);
|
||||||
var attachment:Attachment = skin.getAttachment(slotIndex, attachmentMapName);
|
var attachment:Attachment = skin.getAttachment(slotIndex, attachmentMapName);
|
||||||
@ -1295,7 +1331,7 @@ class SkeletonJson {
|
|||||||
|
|
||||||
timelines.push(deformTimeline);
|
timelines.push(deformTimeline);
|
||||||
case "sequence":
|
case "sequence":
|
||||||
var timeline = new SequenceTimeline(timelineMap.length, slotIndex, cast(attachment, HasTextureRegion));
|
var timeline = new SequenceTimeline(timelineMap.length, slotIndex, cast(attachment, HasSequence));
|
||||||
var lastDelay:Float = 0;
|
var lastDelay:Float = 0;
|
||||||
var frame:Int = 0;
|
var frame:Int = 0;
|
||||||
while (frame < timelineMap.length) {
|
while (frame < timelineMap.length) {
|
||||||
@ -1316,54 +1352,44 @@ class SkeletonJson {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw order timelines.
|
// Draw order timelines.
|
||||||
|
// Draw order timeline.
|
||||||
if (Reflect.hasField(map, "drawOrder")) {
|
if (Reflect.hasField(map, "drawOrder")) {
|
||||||
var drawOrders:Array<Dynamic> = cast(Reflect.field(map, "drawOrder"), Array<Dynamic>);
|
var drawOrders:Array<Dynamic> = cast(Reflect.field(map, "drawOrder"), Array<Dynamic>);
|
||||||
if (drawOrders != null) {
|
if (drawOrders != null) {
|
||||||
var drawOrderTimeline:DrawOrderTimeline = new DrawOrderTimeline(drawOrders.length);
|
var drawOrderTimeline:DrawOrderTimeline = new DrawOrderTimeline(drawOrders.length);
|
||||||
var slotCount:Int = skeletonData.slots.length;
|
var slotCount:Int = skeletonData.slots.length;
|
||||||
frame = 0;
|
frame = 0;
|
||||||
for (drawOrderMap in drawOrders) {
|
for (drawOrderMap in drawOrders)
|
||||||
var drawOrder:Array<Int> = null;
|
drawOrderTimeline.setFrame(frame++, getFloat(drawOrderMap, "time"), readDrawOrder(skeletonData, drawOrderMap, slotCount, null));
|
||||||
var offsets:Array<Dynamic> = Reflect.getProperty(drawOrderMap, "offsets");
|
|
||||||
if (offsets != null) {
|
|
||||||
drawOrder = new Array<Int>();
|
|
||||||
drawOrder.resize(slotCount);
|
|
||||||
var i = slotCount - 1;
|
|
||||||
while (i >= 0) {
|
|
||||||
drawOrder[i--] = -1;
|
|
||||||
}
|
|
||||||
var unchanged:Array<Int> = new Array<Int>();
|
|
||||||
unchanged.resize(slotCount - offsets.length);
|
|
||||||
var originalIndex:Int = 0, unchangedIndex:Int = 0;
|
|
||||||
for (offsetMap in offsets) {
|
|
||||||
slotIndex = skeletonData.findSlot(Reflect.getProperty(offsetMap, "slot")).index;
|
|
||||||
if (slotIndex == -1)
|
|
||||||
throw new SpineException("Slot not found: " + Reflect.getProperty(offsetMap, "slot"));
|
|
||||||
// Collect unchanged items.
|
|
||||||
while (originalIndex != slotIndex) {
|
|
||||||
unchanged[unchangedIndex++] = originalIndex++;
|
|
||||||
}
|
|
||||||
// Set changed items.
|
|
||||||
drawOrder[originalIndex + Reflect.getProperty(offsetMap, "offset")] = originalIndex++;
|
|
||||||
}
|
|
||||||
// Collect remaining unchanged items.
|
|
||||||
while (originalIndex < slotCount) {
|
|
||||||
unchanged[unchangedIndex++] = originalIndex++;
|
|
||||||
}
|
|
||||||
// Fill in unchanged items.
|
|
||||||
i = slotCount - 1;
|
|
||||||
while (i >= 0) {
|
|
||||||
if (drawOrder[i] == -1)
|
|
||||||
drawOrder[i] = unchanged[--unchangedIndex];
|
|
||||||
i--;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
drawOrderTimeline.setFrame(frame++, getFloat(drawOrderMap, "time"), drawOrder);
|
|
||||||
}
|
|
||||||
timelines.push(drawOrderTimeline);
|
timelines.push(drawOrderTimeline);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Draw order folder timelines.
|
||||||
|
if (Reflect.hasField(map, "drawOrderFolder")) {
|
||||||
|
var drawOrderFolders:Array<Dynamic> = cast(Reflect.field(map, "drawOrderFolder"), Array<Dynamic>);
|
||||||
|
if (drawOrderFolders != null) {
|
||||||
|
for (timelineMap in drawOrderFolders) {
|
||||||
|
var slotEntries:Array<Dynamic> = cast(Reflect.field(timelineMap, "slots"), Array<Dynamic>);
|
||||||
|
var folderSlots:Array<Int> = new Array<Int>();
|
||||||
|
folderSlots.resize(slotEntries.length);
|
||||||
|
var ii:Int = 0;
|
||||||
|
for (slotEntry in slotEntries) {
|
||||||
|
var slot = skeletonData.findSlot(cast(slotEntry, String));
|
||||||
|
if (slot == null) throw new SpineException("Draw order folder slot not found: " + cast(slotEntry, String));
|
||||||
|
folderSlots[ii++] = slot.index;
|
||||||
|
}
|
||||||
|
|
||||||
|
var keys:Array<Dynamic> = cast(Reflect.field(timelineMap, "keys"), Array<Dynamic>);
|
||||||
|
var folderTimeline = new DrawOrderFolderTimeline(keys.length, folderSlots, skeletonData.slots.length);
|
||||||
|
frame = 0;
|
||||||
|
for (keyMap in keys)
|
||||||
|
folderTimeline.setFrame(frame++, getFloat(keyMap, "time"), readDrawOrder(skeletonData, keyMap, folderSlots.length, folderSlots));
|
||||||
|
timelines.push(folderTimeline);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Event timelines.
|
// Event timelines.
|
||||||
if (Reflect.hasField(map, "events")) {
|
if (Reflect.hasField(map, "events")) {
|
||||||
var eventsMap:Array<Dynamic> = cast(Reflect.field(map, "events"), Array<Dynamic>);
|
var eventsMap:Array<Dynamic> = cast(Reflect.field(map, "events"), Array<Dynamic>);
|
||||||
|
|||||||
@ -142,7 +142,7 @@ class Skin {
|
|||||||
continue;
|
continue;
|
||||||
if (Std.isOfType(attachment.attachment, MeshAttachment)) {
|
if (Std.isOfType(attachment.attachment, MeshAttachment)) {
|
||||||
var mesh = cast(attachment.attachment, MeshAttachment);
|
var mesh = cast(attachment.attachment, MeshAttachment);
|
||||||
attachment.attachment = new MeshAttachment(mesh.name, mesh.path).newLinkedMesh();
|
attachment.attachment = mesh.newLinkedMesh();
|
||||||
setAttachment(attachment.slotIndex, attachment.name, attachment.attachment);
|
setAttachment(attachment.slotIndex, attachment.name, attachment.attachment);
|
||||||
} else {
|
} else {
|
||||||
attachment.attachment = attachment.attachment.copy();
|
attachment.attachment = attachment.attachment.copy();
|
||||||
|
|||||||
@ -62,24 +62,28 @@ class AlphaTimeline extends CurveTimeline1 implements SlotTimeline {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
var color = (appliedPose ? slot.applied : slot.pose).color;
|
var color = (appliedPose ? slot.applied : slot.pose).color;
|
||||||
|
var a:Float = 0;
|
||||||
if (time < frames[0]) {
|
if (time < frames[0]) {
|
||||||
var setup:Color = slot.data.setup.color;
|
var setup:Color = slot.data.setup.color;
|
||||||
switch (blend) {
|
switch (blend) {
|
||||||
case MixBlend.setup:
|
case MixBlend.setup:
|
||||||
color.a = setup.a;
|
color.a = setup.a;
|
||||||
|
return;
|
||||||
case MixBlend.first:
|
case MixBlend.first:
|
||||||
color.a += (setup.a - color.a) * alpha;
|
a = color.a + (setup.a - color.a) * alpha;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var a:Float = getCurveValue(time);
|
|
||||||
if (alpha == 1) {
|
|
||||||
color.a = a;
|
|
||||||
} else {
|
} else {
|
||||||
if (blend == MixBlend.setup)
|
a = getCurveValue(time);
|
||||||
color.a = slot.data.setup.color.a;
|
if (alpha != 1) {
|
||||||
color.a += (a - color.a) * alpha;
|
if (blend == MixBlend.setup) {
|
||||||
|
var setup = slot.data.setup.color;
|
||||||
|
a = setup.a + (a - setup.a) * alpha;
|
||||||
|
} else
|
||||||
|
a = color.a + (a - color.a) * alpha;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
color.a = a < 0 ? 0 : (a > 1 ? 1 : a);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -266,7 +266,7 @@ class AnimationState {
|
|||||||
attachments = true;
|
attachments = true;
|
||||||
for (timeline in timelines) {
|
for (timeline in timelines) {
|
||||||
if (Std.isOfType(timeline, AttachmentTimeline)) {
|
if (Std.isOfType(timeline, AttachmentTimeline)) {
|
||||||
applyAttachmentTimeline(cast(timeline, AttachmentTimeline), skeleton, applyTime, blend, attachments);
|
applyAttachmentTimeline(cast(timeline, AttachmentTimeline), skeleton, applyTime, blend, false, attachments);
|
||||||
} else {
|
} else {
|
||||||
timeline.apply(skeleton, animationLast, applyTime, applyEvents, alpha, blend, MixDirection.mixIn, false);
|
timeline.apply(skeleton, animationLast, applyTime, applyEvents, alpha, blend, MixDirection.mixIn, false);
|
||||||
}
|
}
|
||||||
@ -286,7 +286,7 @@ class AnimationState {
|
|||||||
this.applyRotateTimeline(cast(timeline, RotateTimeline), skeleton, applyTime, alpha, timelineBlend, current.timelinesRotation,
|
this.applyRotateTimeline(cast(timeline, RotateTimeline), skeleton, applyTime, alpha, timelineBlend, current.timelinesRotation,
|
||||||
ii << 1, firstFrame);
|
ii << 1, firstFrame);
|
||||||
} else if (Std.isOfType(timeline, AttachmentTimeline)) {
|
} else if (Std.isOfType(timeline, AttachmentTimeline)) {
|
||||||
this.applyAttachmentTimeline(cast(timeline, AttachmentTimeline), skeleton, applyTime, blend, attachments);
|
this.applyAttachmentTimeline(cast(timeline, AttachmentTimeline), skeleton, applyTime, blend, false, attachments);
|
||||||
} else {
|
} else {
|
||||||
timeline.apply(skeleton, animationLast, applyTime, applyEvents, alpha, timelineBlend, MixDirection.mixIn, false);
|
timeline.apply(skeleton, animationLast, applyTime, applyEvents, alpha, timelineBlend, MixDirection.mixIn, false);
|
||||||
}
|
}
|
||||||
@ -366,7 +366,6 @@ class AnimationState {
|
|||||||
from.totalAlpha = 0;
|
from.totalAlpha = 0;
|
||||||
for (i in 0...timelineCount) {
|
for (i in 0...timelineCount) {
|
||||||
var timeline:Timeline = timelines[i];
|
var timeline:Timeline = timelines[i];
|
||||||
var direction:MixDirection = MixDirection.mixOut;
|
|
||||||
var timelineBlend:MixBlend;
|
var timelineBlend:MixBlend;
|
||||||
var alpha:Float = 0;
|
var alpha:Float = 0;
|
||||||
switch (timelineMode[i]) {
|
switch (timelineMode[i]) {
|
||||||
@ -395,8 +394,9 @@ class AnimationState {
|
|||||||
applyRotateTimeline(cast(timeline, RotateTimeline), skeleton, applyTime, alpha, timelineBlend, from.timelinesRotation, i << 1, firstFrame);
|
applyRotateTimeline(cast(timeline, RotateTimeline), skeleton, applyTime, alpha, timelineBlend, from.timelinesRotation, i << 1, firstFrame);
|
||||||
} else if (Std.isOfType(timeline, AttachmentTimeline)) {
|
} else if (Std.isOfType(timeline, AttachmentTimeline)) {
|
||||||
applyAttachmentTimeline(cast(timeline, AttachmentTimeline), skeleton, applyTime,
|
applyAttachmentTimeline(cast(timeline, AttachmentTimeline), skeleton, applyTime,
|
||||||
timelineBlend, attachments && alpha >= from.alphaAttachmentThreshold);
|
timelineBlend, true, attachments && alpha >= from.alphaAttachmentThreshold);
|
||||||
} else {
|
} else {
|
||||||
|
var direction = MixDirection.mixOut;
|
||||||
if (drawOrder && Std.isOfType(timeline, DrawOrderTimeline) && timelineBlend == MixBlend.setup)
|
if (drawOrder && Std.isOfType(timeline, DrawOrderTimeline) && timelineBlend == MixBlend.setup)
|
||||||
direction = MixDirection.mixIn;
|
direction = MixDirection.mixIn;
|
||||||
timeline.apply(skeleton, animationLast, applyTime, events, alpha, timelineBlend, direction, false);
|
timeline.apply(skeleton, animationLast, applyTime, events, alpha, timelineBlend, direction, false);
|
||||||
@ -419,12 +419,14 @@ class AnimationState {
|
|||||||
* is not the last timeline to set the slot's attachment. In that case the timeline is applied only so subsequent
|
* is not the last timeline to set the slot's attachment. In that case the timeline is applied only so subsequent
|
||||||
* timelines see any deform.
|
* timelines see any deform.
|
||||||
*/
|
*/
|
||||||
public function applyAttachmentTimeline(timeline:AttachmentTimeline, skeleton:Skeleton, time:Float, blend:MixBlend, attachments:Bool) {
|
public function applyAttachmentTimeline(timeline:AttachmentTimeline, skeleton:Skeleton, time:Float, blend:MixBlend, out:Bool, attachments:Bool) {
|
||||||
var slot = skeleton.slots[timeline.slotIndex];
|
var slot = skeleton.slots[timeline.slotIndex];
|
||||||
if (!slot.bone.active)
|
if (!slot.bone.active)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (time < timeline.frames[0]) { // Time is before first frame.
|
if (out) {
|
||||||
|
if (blend == MixBlend.setup) this.setAttachment(skeleton, slot, slot.data.attachmentName, attachments);
|
||||||
|
} else if (time < timeline.frames[0]) { // Time is before first frame.
|
||||||
if (blend == MixBlend.setup || blend == MixBlend.first)
|
if (blend == MixBlend.setup || blend == MixBlend.first)
|
||||||
this.setAttachment(skeleton, slot, slot.data.attachmentName, attachments);
|
this.setAttachment(skeleton, slot, slot.data.attachmentName, attachments);
|
||||||
} else
|
} else
|
||||||
@ -889,6 +891,7 @@ class AnimationState {
|
|||||||
} else if (to == null
|
} else if (to == null
|
||||||
|| Std.isOfType(timeline, AttachmentTimeline)
|
|| Std.isOfType(timeline, AttachmentTimeline)
|
||||||
|| Std.isOfType(timeline, DrawOrderTimeline)
|
|| Std.isOfType(timeline, DrawOrderTimeline)
|
||||||
|
|| Std.isOfType(timeline, DrawOrderFolderTimeline)
|
||||||
|| Std.isOfType(timeline, EventTimeline)
|
|| Std.isOfType(timeline, EventTimeline)
|
||||||
|| !to.animation.hasTimeline(ids)) {
|
|| !to.animation.hasTimeline(ids)) {
|
||||||
timelineMode[i] = FIRST;
|
timelineMode[i] = FIRST;
|
||||||
|
|||||||
126
spine-haxe/spine-haxe/spine/animation/DrawOrderFolderTimeline.hx
Normal file
126
spine-haxe/spine-haxe/spine/animation/DrawOrderFolderTimeline.hx
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* Spine Runtimes License Agreement
|
||||||
|
* Last updated April 5, 2025. Replaces all prior versions.
|
||||||
|
*
|
||||||
|
* Copyright (c) 2013-2025, Esoteric Software LLC
|
||||||
|
*
|
||||||
|
* Integration of the Spine Runtimes into software or otherwise creating
|
||||||
|
* derivative works of the Spine Runtimes is permitted under the terms and
|
||||||
|
* conditions of Section 2 of the Spine Editor License Agreement:
|
||||||
|
* http://esotericsoftware.com/spine-editor-license
|
||||||
|
*
|
||||||
|
* Otherwise, it is permitted to integrate the Spine Runtimes into software
|
||||||
|
* or otherwise create derivative works of the Spine Runtimes (collectively,
|
||||||
|
* "Products"), provided that each user of the Products must obtain their own
|
||||||
|
* Spine Editor license and redistribution of the Products in any form must
|
||||||
|
* include this license and copyright notice.
|
||||||
|
*
|
||||||
|
* THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
|
||||||
|
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
* DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
|
||||||
|
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
|
||||||
|
* BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
|
||||||
|
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||||
|
* THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*****************************************************************************/
|
||||||
|
|
||||||
|
package spine.animation;
|
||||||
|
|
||||||
|
import spine.Event;
|
||||||
|
import spine.Skeleton;
|
||||||
|
import spine.Slot;
|
||||||
|
|
||||||
|
/** Changes a subset of a skeleton's spine.Skeleton.drawOrder. */
|
||||||
|
class DrawOrderFolderTimeline extends Timeline {
|
||||||
|
private var slots:Array<Int>;
|
||||||
|
private var inFolder:Array<Bool>;
|
||||||
|
private var drawOrders:Array<Array<Int>>;
|
||||||
|
|
||||||
|
/** @param slots spine.Skeleton.slots indices controlled by this timeline, in setup order.
|
||||||
|
* @param slotCount The maximum number of slots in the skeleton. */
|
||||||
|
public function new(frameCount:Int, slots:Array<Int>, slotCount:Int) {
|
||||||
|
super(frameCount, Property.drawOrder);
|
||||||
|
this.slots = slots;
|
||||||
|
drawOrders = new Array<Array<Int>>();
|
||||||
|
drawOrders.resize(frameCount);
|
||||||
|
inFolder = new Array<Bool>();
|
||||||
|
inFolder.resize(slotCount);
|
||||||
|
for (i in 0...slotCount)
|
||||||
|
inFolder[i] = false;
|
||||||
|
for (i in slots)
|
||||||
|
inFolder[i] = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
public var frameCount(get, never):Int;
|
||||||
|
|
||||||
|
private function get_frameCount():Int {
|
||||||
|
return frames.length;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The spine.Skeleton.slots indices that this timeline affects, in setup order. */
|
||||||
|
public function getSlots():Array<Int> {
|
||||||
|
return slots;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The draw order for each frame. See setFrame(). */
|
||||||
|
public function getDrawOrders():Array<Array<Int>> {
|
||||||
|
return drawOrders;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets the time and draw order for the specified frame.
|
||||||
|
* @param frame Between 0 and frameCount, inclusive.
|
||||||
|
* @param time The frame time in seconds.
|
||||||
|
* @param drawOrder Ordered getSlots() indices, or null to use setup pose order. */
|
||||||
|
public function setFrame(frame:Int, time:Float, drawOrder:Array<Int>):Void {
|
||||||
|
frames[frame] = time;
|
||||||
|
drawOrders[frame] = drawOrder;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend, direction:MixDirection,
|
||||||
|
appliedPose:Bool) {
|
||||||
|
if (direction == MixDirection.mixOut) {
|
||||||
|
if (blend == MixBlend.setup) setupApply(skeleton);
|
||||||
|
} else if (time < frames[0]) {
|
||||||
|
if (blend == MixBlend.setup || blend == MixBlend.first) setupApply(skeleton);
|
||||||
|
} else {
|
||||||
|
var order = drawOrders[Timeline.search1(frames, time)];
|
||||||
|
if (order == null)
|
||||||
|
setupApply(skeleton);
|
||||||
|
else
|
||||||
|
orderApply(skeleton, order);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function setupApply(skeleton:Skeleton):Void {
|
||||||
|
var drawOrder = skeleton.drawOrder;
|
||||||
|
var allSlots = skeleton.slots;
|
||||||
|
var found = 0, done = slots.length;
|
||||||
|
var i = 0;
|
||||||
|
while (true) {
|
||||||
|
if (inFolder[drawOrder[i].data.index]) {
|
||||||
|
drawOrder[i] = allSlots[slots[found]];
|
||||||
|
found++;
|
||||||
|
if (found == done) break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private function orderApply(skeleton:Skeleton, order:Array<Int>):Void {
|
||||||
|
var drawOrder = skeleton.drawOrder;
|
||||||
|
var allSlots = skeleton.slots;
|
||||||
|
var found = 0, done = slots.length;
|
||||||
|
var i = 0;
|
||||||
|
while (true) {
|
||||||
|
if (inFolder[drawOrder[i].data.index]) {
|
||||||
|
drawOrder[i] = allSlots[slots[order[found]]];
|
||||||
|
found++;
|
||||||
|
if (found == done) break;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -53,7 +53,7 @@ class DrawOrderTimeline extends Timeline {
|
|||||||
/** Sets the time and draw order for the specified frame.
|
/** Sets the time and draw order for the specified frame.
|
||||||
* @param frame Between 0 and frameCount, inclusive.
|
* @param frame Between 0 and frameCount, inclusive.
|
||||||
* @param time The frame time in seconds.
|
* @param time The frame time in seconds.
|
||||||
* @param drawOrder For each slot in spine.Skeleton.slots, the index of the slot in the new draw order. May be null to use setup pose draw order. */
|
* @param drawOrder Ordered spine.Skeleton.slots indices, or null to use setup pose order. */
|
||||||
public function setFrame(frame:Int, time:Float, drawOrder:Array<Int>):Void {
|
public function setFrame(frame:Int, time:Float, drawOrder:Array<Int>):Void {
|
||||||
frames[frame] = time;
|
frames[frame] = time;
|
||||||
drawOrders[frame] = drawOrder;
|
drawOrders[frame] = drawOrder;
|
||||||
|
|||||||
@ -115,27 +115,21 @@ class IkConstraintTimeline extends CurveTimeline implements ConstraintTimeline {
|
|||||||
softness = getBezierValue(time, i, SOFTNESS, curveType + CurveTimeline.BEZIER_SIZE - CurveTimeline.BEZIER);
|
softness = getBezierValue(time, i, SOFTNESS, curveType + CurveTimeline.BEZIER_SIZE - CurveTimeline.BEZIER);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (blend) {
|
if (blend == MixBlend.setup) {
|
||||||
case MixBlend.setup:
|
var setup = constraint.data.setup;
|
||||||
var setup = constraint.data.setup;
|
pose.mix = setup.mix + (mix - setup.mix) * alpha;
|
||||||
pose.mix = setup.mix + (mix - setup.mix) * alpha;
|
pose.softness = setup.softness + (softness - setup.softness) * alpha;
|
||||||
pose.softness = setup.softness + (softness - setup.softness) * alpha;
|
if (direction == MixDirection.mixOut) {
|
||||||
if (direction == MixDirection.mixOut) {
|
pose.bendDirection = setup.bendDirection;
|
||||||
pose.bendDirection = setup.bendDirection;
|
pose.compress = setup.compress;
|
||||||
pose.compress = setup.compress;
|
pose.stretch = setup.stretch;
|
||||||
pose.stretch = setup.stretch;
|
return;
|
||||||
return;
|
}
|
||||||
}
|
} else {
|
||||||
case MixBlend.first, MixBlend.replace:
|
pose.mix += (mix - pose.mix) * alpha;
|
||||||
pose.mix += (mix - pose.mix) * alpha;
|
pose.softness += (softness - pose.softness) * alpha;
|
||||||
pose.softness += (softness - pose.softness) * alpha;
|
if (direction == MixDirection.mixOut)
|
||||||
if (direction == MixDirection.mixOut)
|
return;
|
||||||
return;
|
|
||||||
case MixBlend.add:
|
|
||||||
pose.mix += mix * alpha;
|
|
||||||
pose.softness += softness * alpha;
|
|
||||||
if (direction == MixDirection.mixOut)
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
pose.bendDirection = Std.int(frames[i + BEND_DIRECTION]);
|
pose.bendDirection = Std.int(frames[i + BEND_DIRECTION]);
|
||||||
pose.compress = frames[i + COMPRESS] != 0;
|
pose.compress = frames[i + COMPRESS] != 0;
|
||||||
|
|||||||
@ -114,20 +114,15 @@ class PathConstraintMixTimeline extends CurveTimeline implements ConstraintTimel
|
|||||||
y = getBezierValue(time, i, Y, curveType + CurveTimeline.BEZIER_SIZE * 2 - CurveTimeline.BEZIER);
|
y = getBezierValue(time, i, Y, curveType + CurveTimeline.BEZIER_SIZE * 2 - CurveTimeline.BEZIER);
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (blend) {
|
if (blend == MixBlend.setup) {
|
||||||
case MixBlend.setup:
|
var setup = constraint.data.setup;
|
||||||
var setup = constraint.data.setup;
|
pose.mixRotate = setup.mixRotate + (rotate - setup.mixRotate) * alpha;
|
||||||
pose.mixRotate = setup.mixRotate + (rotate - setup.mixRotate) * alpha;
|
pose.mixX = setup.mixX + (x - setup.mixX) * alpha;
|
||||||
pose.mixX = setup.mixX + (x - setup.mixX) * alpha;
|
pose.mixY = setup.mixY + (y - setup.mixY) * alpha;
|
||||||
pose.mixY = setup.mixY + (y - setup.mixY) * alpha;
|
} else {
|
||||||
case MixBlend.first, MixBlend.replace:
|
pose.mixRotate += (rotate - pose.mixRotate) * alpha;
|
||||||
pose.mixRotate += (rotate - pose.mixRotate) * alpha;
|
pose.mixX += (x - pose.mixX) * alpha;
|
||||||
pose.mixX += (x - pose.mixX) * alpha;
|
pose.mixY += (y - pose.mixY) * alpha;
|
||||||
pose.mixY += (y - pose.mixY) * alpha;
|
|
||||||
case MixBlend.add:
|
|
||||||
pose.mixRotate += rotate * alpha;
|
|
||||||
pose.mixX += x * alpha;
|
|
||||||
pose.mixY += y * alpha;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -44,7 +44,7 @@ class PathConstraintSpacingTimeline extends ConstraintTimeline1 {
|
|||||||
var constraint = cast(skeleton.constraints[constraintIndex], PathConstraint);
|
var constraint = cast(skeleton.constraints[constraintIndex], PathConstraint);
|
||||||
if (constraint.active) {
|
if (constraint.active) {
|
||||||
var pose = appliedPose ? constraint.applied : constraint.pose;
|
var pose = appliedPose ? constraint.applied : constraint.pose;
|
||||||
pose.spacing = getAbsoluteValue(time, alpha, blend, pose.spacing, constraint.data.setup.spacing);
|
pose.spacing = getAbsoluteValue(time, alpha, blend == MixBlend.add ? MixBlend.replace : blend, pose.spacing, constraint.data.setup.spacing);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,6 +33,7 @@ package spine.animation;
|
|||||||
class PhysicsConstraintGravityTimeline extends PhysicsConstraintTimeline {
|
class PhysicsConstraintGravityTimeline extends PhysicsConstraintTimeline {
|
||||||
public function new(frameCount:Int, bezierCount:Int, constraintIndex:Int) {
|
public function new(frameCount:Int, bezierCount:Int, constraintIndex:Int) {
|
||||||
super(frameCount, bezierCount, constraintIndex, Property.physicsConstraintGravity);
|
super(frameCount, bezierCount, constraintIndex, Property.physicsConstraintGravity);
|
||||||
|
this.additive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get(pose:PhysicsConstraintPose):Float {
|
public function get(pose:PhysicsConstraintPose):Float {
|
||||||
|
|||||||
@ -35,6 +35,8 @@ import spine.Skeleton;
|
|||||||
|
|
||||||
/** The base class for most spine.PhysicsConstraint timelines. */
|
/** The base class for most spine.PhysicsConstraint timelines. */
|
||||||
abstract class PhysicsConstraintTimeline extends ConstraintTimeline1 {
|
abstract class PhysicsConstraintTimeline extends ConstraintTimeline1 {
|
||||||
|
public var additive:Bool = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param constraintIndex -1 for all physics constraints in the skeleton.
|
* @param constraintIndex -1 for all physics constraints in the skeleton.
|
||||||
*/
|
*/
|
||||||
@ -44,6 +46,7 @@ abstract class PhysicsConstraintTimeline extends ConstraintTimeline1 {
|
|||||||
|
|
||||||
public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend, direction:MixDirection,
|
public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend, direction:MixDirection,
|
||||||
appliedPose:Bool) {
|
appliedPose:Bool) {
|
||||||
|
if (blend == MixBlend.add && !additive) blend = MixBlend.replace;
|
||||||
if (constraintIndex == -1) {
|
if (constraintIndex == -1) {
|
||||||
var value:Float = time >= frames[0] ? getCurveValue(time) : 0;
|
var value:Float = time >= frames[0] ? getCurveValue(time) : 0;
|
||||||
for (constraint in skeleton.physics) {
|
for (constraint in skeleton.physics) {
|
||||||
|
|||||||
@ -33,6 +33,7 @@ package spine.animation;
|
|||||||
class PhysicsConstraintWindTimeline extends PhysicsConstraintTimeline {
|
class PhysicsConstraintWindTimeline extends PhysicsConstraintTimeline {
|
||||||
public function new(frameCount:Int, bezierCount:Int, constraintIndex:Int) {
|
public function new(frameCount:Int, bezierCount:Int, constraintIndex:Int) {
|
||||||
super(frameCount, bezierCount, constraintIndex, Property.physicsConstraintWind);
|
super(frameCount, bezierCount, constraintIndex, Property.physicsConstraintWind);
|
||||||
|
this.additive = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function get(pose:PhysicsConstraintPose):Float {
|
public function get(pose:PhysicsConstraintPose):Float {
|
||||||
|
|||||||
@ -63,9 +63,10 @@ class RGB2Timeline extends SlotCurveTimeline {
|
|||||||
|
|
||||||
public function apply1(slot:Slot, pose:SlotPose, time:Float, alpha:Float, blend:MixBlend) {
|
public function apply1(slot:Slot, pose:SlotPose, time:Float, alpha:Float, blend:MixBlend) {
|
||||||
var light:Color = pose.color, dark:Color = pose.darkColor;
|
var light:Color = pose.color, dark:Color = pose.darkColor;
|
||||||
|
var r:Float = 0, g:Float = 0, b:Float = 0, r2:Float = 0, g2:Float = 0, b2:Float = 0;
|
||||||
if (time < frames[0]) {
|
if (time < frames[0]) {
|
||||||
var setup = slot.data.setup;
|
var setup = slot.data.setup;
|
||||||
var setupLight = setup.color, setupDark = setup.darkColor;
|
var setupLight:Color = setup.color, setupDark:Color = setup.darkColor;
|
||||||
switch (blend) {
|
switch (blend) {
|
||||||
case MixBlend.setup:
|
case MixBlend.setup:
|
||||||
light.r = setupLight.r;
|
light.r = setupLight.r;
|
||||||
@ -74,76 +75,78 @@ class RGB2Timeline extends SlotCurveTimeline {
|
|||||||
dark.r = setupDark.r;
|
dark.r = setupDark.r;
|
||||||
dark.g = setupDark.g;
|
dark.g = setupDark.g;
|
||||||
dark.b = setupDark.b;
|
dark.b = setupDark.b;
|
||||||
|
return;
|
||||||
case MixBlend.first:
|
case MixBlend.first:
|
||||||
light.r += (setupLight.r - light.r) * alpha;
|
r = light.r + (setupLight.r - light.r) * alpha;
|
||||||
light.g += (setupLight.g - light.g) * alpha;
|
g = light.g + (setupLight.g - light.g) * alpha;
|
||||||
light.b += (setupLight.b - light.b) * alpha;
|
b = light.b + (setupLight.b - light.b) * alpha;
|
||||||
dark.r += (setupDark.r - dark.r) * alpha;
|
r2 = dark.r + (setupDark.r - dark.r) * alpha;
|
||||||
dark.g += (setupDark.g - dark.g) * alpha;
|
g2 = dark.g + (setupDark.g - dark.g) * alpha;
|
||||||
dark.b += (setupDark.b - dark.b) * alpha;
|
b2 = dark.b + (setupDark.b - dark.b) * alpha;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var r:Float = 0, g:Float = 0, b:Float = 0, a:Float = 0, r2:Float = 0, g2:Float = 0, b2:Float = 0;
|
|
||||||
var i:Int = Timeline.search(frames, time, ENTRIES);
|
|
||||||
var curveType:Int = Std.int(curves[Std.int(i / ENTRIES)]);
|
|
||||||
switch (curveType) {
|
|
||||||
case CurveTimeline.LINEAR:
|
|
||||||
var before:Float = frames[i];
|
|
||||||
r = frames[i + R];
|
|
||||||
g = frames[i + G];
|
|
||||||
b = frames[i + B];
|
|
||||||
r2 = frames[i + R2];
|
|
||||||
g2 = frames[i + G2];
|
|
||||||
b2 = frames[i + B2];
|
|
||||||
var t:Float = (time - before) / (frames[i + ENTRIES] - before);
|
|
||||||
r += (frames[i + ENTRIES + R] - r) * t;
|
|
||||||
g += (frames[i + ENTRIES + G] - g) * t;
|
|
||||||
b += (frames[i + ENTRIES + B] - b) * t;
|
|
||||||
r2 += (frames[i + ENTRIES + R2] - r2) * t;
|
|
||||||
g2 += (frames[i + ENTRIES + G2] - g2) * t;
|
|
||||||
b2 += (frames[i + ENTRIES + B2] - b2) * t;
|
|
||||||
case CurveTimeline.STEPPED:
|
|
||||||
r = frames[i + R];
|
|
||||||
g = frames[i + G];
|
|
||||||
b = frames[i + B];
|
|
||||||
r2 = frames[i + R2];
|
|
||||||
g2 = frames[i + G2];
|
|
||||||
b2 = frames[i + B2];
|
|
||||||
default:
|
|
||||||
r = getBezierValue(time, i, R, curveType - CurveTimeline.BEZIER);
|
|
||||||
g = getBezierValue(time, i, G, curveType + CurveTimeline.BEZIER_SIZE - CurveTimeline.BEZIER);
|
|
||||||
b = getBezierValue(time, i, B, curveType + CurveTimeline.BEZIER_SIZE * 2 - CurveTimeline.BEZIER);
|
|
||||||
r2 = getBezierValue(time, i, R2, curveType + CurveTimeline.BEZIER_SIZE * 3 - CurveTimeline.BEZIER);
|
|
||||||
g2 = getBezierValue(time, i, G2, curveType + CurveTimeline.BEZIER_SIZE * 4 - CurveTimeline.BEZIER);
|
|
||||||
b2 = getBezierValue(time, i, B2, curveType + CurveTimeline.BEZIER_SIZE * 5 - CurveTimeline.BEZIER);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alpha == 1) {
|
|
||||||
light.r = r;
|
|
||||||
light.g = g;
|
|
||||||
light.b = b;
|
|
||||||
dark.r = r2;
|
|
||||||
dark.g = g2;
|
|
||||||
dark.b = b2;
|
|
||||||
} else {
|
} else {
|
||||||
if (blend == MixBlend.setup) {
|
var i:Int = Timeline.search(frames, time, ENTRIES);
|
||||||
var setup = slot.data.setup;
|
var curveType:Int = Std.int(curves[Std.int(i / ENTRIES)]);
|
||||||
var setupLight = setup.color, setupDark = setup.darkColor;
|
switch (curveType) {
|
||||||
light.r = setupLight.r;
|
case CurveTimeline.LINEAR:
|
||||||
light.g = setupLight.g;
|
var before:Float = frames[i];
|
||||||
light.b = setupLight.b;
|
r = frames[i + R];
|
||||||
dark.r = setupDark.r;
|
g = frames[i + G];
|
||||||
dark.g = setupDark.g;
|
b = frames[i + B];
|
||||||
dark.b = setupDark.b;
|
r2 = frames[i + R2];
|
||||||
|
g2 = frames[i + G2];
|
||||||
|
b2 = frames[i + B2];
|
||||||
|
var t:Float = (time - before) / (frames[i + ENTRIES] - before);
|
||||||
|
r += (frames[i + ENTRIES + R] - r) * t;
|
||||||
|
g += (frames[i + ENTRIES + G] - g) * t;
|
||||||
|
b += (frames[i + ENTRIES + B] - b) * t;
|
||||||
|
r2 += (frames[i + ENTRIES + R2] - r2) * t;
|
||||||
|
g2 += (frames[i + ENTRIES + G2] - g2) * t;
|
||||||
|
b2 += (frames[i + ENTRIES + B2] - b2) * t;
|
||||||
|
case CurveTimeline.STEPPED:
|
||||||
|
r = frames[i + R];
|
||||||
|
g = frames[i + G];
|
||||||
|
b = frames[i + B];
|
||||||
|
r2 = frames[i + R2];
|
||||||
|
g2 = frames[i + G2];
|
||||||
|
b2 = frames[i + B2];
|
||||||
|
default:
|
||||||
|
r = getBezierValue(time, i, R, curveType - CurveTimeline.BEZIER);
|
||||||
|
g = getBezierValue(time, i, G, curveType + CurveTimeline.BEZIER_SIZE - CurveTimeline.BEZIER);
|
||||||
|
b = getBezierValue(time, i, B, curveType + CurveTimeline.BEZIER_SIZE * 2 - CurveTimeline.BEZIER);
|
||||||
|
r2 = getBezierValue(time, i, R2, curveType + CurveTimeline.BEZIER_SIZE * 3 - CurveTimeline.BEZIER);
|
||||||
|
g2 = getBezierValue(time, i, G2, curveType + CurveTimeline.BEZIER_SIZE * 4 - CurveTimeline.BEZIER);
|
||||||
|
b2 = getBezierValue(time, i, B2, curveType + CurveTimeline.BEZIER_SIZE * 5 - CurveTimeline.BEZIER);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alpha != 1) {
|
||||||
|
if (blend == MixBlend.setup) {
|
||||||
|
var setupPose = slot.data.setup;
|
||||||
|
var setup = setupPose.color;
|
||||||
|
r = setup.r + (r - setup.r) * alpha;
|
||||||
|
g = setup.g + (g - setup.g) * alpha;
|
||||||
|
b = setup.b + (b - setup.b) * alpha;
|
||||||
|
setup = setupPose.darkColor;
|
||||||
|
r2 = setup.r + (r2 - setup.r) * alpha;
|
||||||
|
g2 = setup.g + (g2 - setup.g) * alpha;
|
||||||
|
b2 = setup.b + (b2 - setup.b) * alpha;
|
||||||
|
} else {
|
||||||
|
r = light.r + (r - light.r) * alpha;
|
||||||
|
g = light.g + (g - light.g) * alpha;
|
||||||
|
b = light.b + (b - light.b) * alpha;
|
||||||
|
r2 = dark.r + (r2 - dark.r) * alpha;
|
||||||
|
g2 = dark.g + (g2 - dark.g) * alpha;
|
||||||
|
b2 = dark.b + (b2 - dark.b) * alpha;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
light.r += (r - light.r) * alpha;
|
|
||||||
light.g += (g - light.g) * alpha;
|
|
||||||
light.b += (b - light.b) * alpha;
|
|
||||||
dark.r += (r2 - dark.r) * alpha;
|
|
||||||
dark.g += (g2 - dark.g) * alpha;
|
|
||||||
dark.b += (b2 - dark.b) * alpha;
|
|
||||||
}
|
}
|
||||||
|
light.r = r < 0 ? 0 : (r > 1 ? 1 : r);
|
||||||
|
light.g = g < 0 ? 0 : (g > 1 ? 1 : g);
|
||||||
|
light.b = b < 0 ? 0 : (b > 1 ? 1 : b);
|
||||||
|
dark.r = r2 < 0 ? 0 : (r2 > 1 ? 1 : r2);
|
||||||
|
dark.g = g2 < 0 ? 0 : (g2 > 1 ? 1 : g2);
|
||||||
|
dark.b = b2 < 0 ? 0 : (b2 > 1 ? 1 : b2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -71,6 +71,7 @@ class RGBA2Timeline extends SlotCurveTimeline {
|
|||||||
|
|
||||||
public function apply1(slot:Slot, pose:SlotPose, time:Float, alpha:Float, blend:MixBlend) {
|
public function apply1(slot:Slot, pose:SlotPose, time:Float, alpha:Float, blend:MixBlend) {
|
||||||
var light = pose.color, dark = pose.darkColor;
|
var light = pose.color, dark = pose.darkColor;
|
||||||
|
var r2:Float = 0, g2:Float = 0, b2:Float = 0;
|
||||||
if (time < frames[0]) {
|
if (time < frames[0]) {
|
||||||
var setup = slot.data.setup;
|
var setup = slot.data.setup;
|
||||||
var setupLight = setup.color, setupDark = setup.darkColor;
|
var setupLight = setup.color, setupDark = setup.darkColor;
|
||||||
@ -80,70 +81,76 @@ class RGBA2Timeline extends SlotCurveTimeline {
|
|||||||
dark.r = setupDark.r;
|
dark.r = setupDark.r;
|
||||||
dark.g = setupDark.g;
|
dark.g = setupDark.g;
|
||||||
dark.b = setupDark.b;
|
dark.b = setupDark.b;
|
||||||
|
return;
|
||||||
case MixBlend.first:
|
case MixBlend.first:
|
||||||
light.add((setupLight.r - light.r) * alpha, (setupLight.g - light.g) * alpha, (setupLight.b - light.b) * alpha,
|
light.add((setupLight.r - light.r) * alpha, (setupLight.g - light.g) * alpha, (setupLight.b - light.b) * alpha,
|
||||||
(setupLight.a - light.a) * alpha);
|
(setupLight.a - light.a) * alpha);
|
||||||
dark.r += (setupDark.r - dark.r) * alpha;
|
r2 = dark.r + (setupDark.r - dark.r) * alpha;
|
||||||
dark.g += (setupDark.g - dark.g) * alpha;
|
g2 = dark.g + (setupDark.g - dark.g) * alpha;
|
||||||
dark.b += (setupDark.b - dark.b) * alpha;
|
b2 = dark.b + (setupDark.b - dark.b) * alpha;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var r:Float = 0, g:Float = 0, b:Float = 0, a:Float = 0, r2:Float = 0, g2:Float = 0, b2:Float = 0;
|
|
||||||
var i:Int = Timeline.search(frames, time, ENTRIES);
|
|
||||||
var curveType:Int = Std.int(curves[i >> 3]);
|
|
||||||
switch (curveType) {
|
|
||||||
case CurveTimeline.LINEAR:
|
|
||||||
var before:Float = frames[i];
|
|
||||||
r = frames[i + R];
|
|
||||||
g = frames[i + G];
|
|
||||||
b = frames[i + B];
|
|
||||||
a = frames[i + A];
|
|
||||||
r2 = frames[i + R2];
|
|
||||||
g2 = frames[i + G2];
|
|
||||||
b2 = frames[i + B2];
|
|
||||||
var t:Float = (time - before) / (frames[i + ENTRIES] - before);
|
|
||||||
r += (frames[i + ENTRIES + R] - r) * t;
|
|
||||||
g += (frames[i + ENTRIES + G] - g) * t;
|
|
||||||
b += (frames[i + ENTRIES + B] - b) * t;
|
|
||||||
a += (frames[i + ENTRIES + A] - a) * t;
|
|
||||||
r2 += (frames[i + ENTRIES + R2] - r2) * t;
|
|
||||||
g2 += (frames[i + ENTRIES + G2] - g2) * t;
|
|
||||||
b2 += (frames[i + ENTRIES + B2] - b2) * t;
|
|
||||||
case CurveTimeline.STEPPED:
|
|
||||||
r = frames[i + R];
|
|
||||||
g = frames[i + G];
|
|
||||||
b = frames[i + B];
|
|
||||||
a = frames[i + A];
|
|
||||||
r2 = frames[i + R2];
|
|
||||||
g2 = frames[i + G2];
|
|
||||||
b2 = frames[i + B2];
|
|
||||||
default:
|
|
||||||
r = getBezierValue(time, i, R, curveType - CurveTimeline.BEZIER);
|
|
||||||
g = getBezierValue(time, i, G, curveType + CurveTimeline.BEZIER_SIZE - CurveTimeline.BEZIER);
|
|
||||||
b = getBezierValue(time, i, B, curveType + CurveTimeline.BEZIER_SIZE * 2 - CurveTimeline.BEZIER);
|
|
||||||
a = getBezierValue(time, i, A, curveType + CurveTimeline.BEZIER_SIZE * 3 - CurveTimeline.BEZIER);
|
|
||||||
r2 = getBezierValue(time, i, R2, curveType + CurveTimeline.BEZIER_SIZE * 4 - CurveTimeline.BEZIER);
|
|
||||||
g2 = getBezierValue(time, i, G2, curveType + CurveTimeline.BEZIER_SIZE * 5 - CurveTimeline.BEZIER);
|
|
||||||
b2 = getBezierValue(time, i, B2, curveType + CurveTimeline.BEZIER_SIZE * 6 - CurveTimeline.BEZIER);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (alpha == 1) {
|
|
||||||
light.set(r, g, b, a);
|
|
||||||
dark.r = r2;
|
|
||||||
dark.g = g2;
|
|
||||||
dark.b = b2;
|
|
||||||
} else {
|
} else {
|
||||||
if (blend == MixBlend.setup) {
|
var r:Float = 0, g:Float = 0, b:Float = 0, a:Float = 0;
|
||||||
var setup = slot.data.setup;
|
var i:Int = Timeline.search(frames, time, ENTRIES);
|
||||||
light.setFromColor(setup.color);
|
var curveType:Int = Std.int(curves[i >> 3]);
|
||||||
dark.setFromColor(setup.darkColor);
|
switch (curveType) {
|
||||||
|
case CurveTimeline.LINEAR:
|
||||||
|
var before:Float = frames[i];
|
||||||
|
r = frames[i + R];
|
||||||
|
g = frames[i + G];
|
||||||
|
b = frames[i + B];
|
||||||
|
a = frames[i + A];
|
||||||
|
r2 = frames[i + R2];
|
||||||
|
g2 = frames[i + G2];
|
||||||
|
b2 = frames[i + B2];
|
||||||
|
var t:Float = (time - before) / (frames[i + ENTRIES] - before);
|
||||||
|
r += (frames[i + ENTRIES + R] - r) * t;
|
||||||
|
g += (frames[i + ENTRIES + G] - g) * t;
|
||||||
|
b += (frames[i + ENTRIES + B] - b) * t;
|
||||||
|
a += (frames[i + ENTRIES + A] - a) * t;
|
||||||
|
r2 += (frames[i + ENTRIES + R2] - r2) * t;
|
||||||
|
g2 += (frames[i + ENTRIES + G2] - g2) * t;
|
||||||
|
b2 += (frames[i + ENTRIES + B2] - b2) * t;
|
||||||
|
case CurveTimeline.STEPPED:
|
||||||
|
r = frames[i + R];
|
||||||
|
g = frames[i + G];
|
||||||
|
b = frames[i + B];
|
||||||
|
a = frames[i + A];
|
||||||
|
r2 = frames[i + R2];
|
||||||
|
g2 = frames[i + G2];
|
||||||
|
b2 = frames[i + B2];
|
||||||
|
default:
|
||||||
|
r = getBezierValue(time, i, R, curveType - CurveTimeline.BEZIER);
|
||||||
|
g = getBezierValue(time, i, G, curveType + CurveTimeline.BEZIER_SIZE - CurveTimeline.BEZIER);
|
||||||
|
b = getBezierValue(time, i, B, curveType + CurveTimeline.BEZIER_SIZE * 2 - CurveTimeline.BEZIER);
|
||||||
|
a = getBezierValue(time, i, A, curveType + CurveTimeline.BEZIER_SIZE * 3 - CurveTimeline.BEZIER);
|
||||||
|
r2 = getBezierValue(time, i, R2, curveType + CurveTimeline.BEZIER_SIZE * 4 - CurveTimeline.BEZIER);
|
||||||
|
g2 = getBezierValue(time, i, G2, curveType + CurveTimeline.BEZIER_SIZE * 5 - CurveTimeline.BEZIER);
|
||||||
|
b2 = getBezierValue(time, i, B2, curveType + CurveTimeline.BEZIER_SIZE * 6 - CurveTimeline.BEZIER);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alpha == 1)
|
||||||
|
light.set(r, g, b, a);
|
||||||
|
else if (blend == MixBlend.setup) {
|
||||||
|
var setupPose = slot.data.setup;
|
||||||
|
var setup = setupPose.color;
|
||||||
|
light.set(setup.r + (r - setup.r) * alpha, setup.g + (g - setup.g) * alpha, setup.b + (b - setup.b) * alpha,
|
||||||
|
setup.a + (a - setup.a) * alpha);
|
||||||
|
setup = setupPose.darkColor;
|
||||||
|
r2 = setup.r + (r2 - setup.r) * alpha;
|
||||||
|
g2 = setup.g + (g2 - setup.g) * alpha;
|
||||||
|
b2 = setup.b + (b2 - setup.b) * alpha;
|
||||||
|
} else {
|
||||||
|
light.add((r - light.r) * alpha, (g - light.g) * alpha, (b - light.b) * alpha, (a - light.a) * alpha);
|
||||||
|
r2 = dark.r + (r2 - dark.r) * alpha;
|
||||||
|
g2 = dark.g + (g2 - dark.g) * alpha;
|
||||||
|
b2 = dark.b + (b2 - dark.b) * alpha;
|
||||||
}
|
}
|
||||||
light.add((r - light.r) * alpha, (g - light.g) * alpha, (b - light.b) * alpha, (a - light.a) * alpha);
|
|
||||||
dark.r += (r2 - dark.r) * alpha;
|
|
||||||
dark.g += (g2 - dark.g) * alpha;
|
|
||||||
dark.b += (b2 - dark.b) * alpha;
|
|
||||||
}
|
}
|
||||||
|
dark.r = r2 < 0 ? 0 : (r2 > 1 ? 1 : r2);
|
||||||
|
dark.g = g2 < 0 ? 0 : (g2 > 1 ? 1 : g2);
|
||||||
|
dark.b = b2 < 0 ? 0 : (b2 > 1 ? 1 : b2);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -97,12 +97,15 @@ class RGBATimeline extends SlotCurveTimeline {
|
|||||||
a = getBezierValue(time, i, A, curveType + CurveTimeline.BEZIER_SIZE * 3 - CurveTimeline.BEZIER);
|
a = getBezierValue(time, i, A, curveType + CurveTimeline.BEZIER_SIZE * 3 - CurveTimeline.BEZIER);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (alpha == 1) {
|
if (alpha == 1)
|
||||||
color.set(r, g, b, a);
|
color.set(r, g, b, a);
|
||||||
} else {
|
else {
|
||||||
if (blend == MixBlend.setup)
|
if (blend == MixBlend.setup) {
|
||||||
color.setFromColor(slot.data.setup.color);
|
var setup = slot.data.setup.color;
|
||||||
color.add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha);
|
color.set(setup.r + (r - setup.r) * alpha, setup.g + (g - setup.g) * alpha, setup.b + (b - setup.b) * alpha,
|
||||||
|
setup.a + (a - setup.a) * alpha);
|
||||||
|
} else
|
||||||
|
color.add((r - color.r) * alpha, (g - color.g) * alpha, (b - color.b) * alpha, (a - color.a) * alpha);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -57,6 +57,7 @@ class RGBTimeline extends SlotCurveTimeline {
|
|||||||
|
|
||||||
public function apply1(slot:Slot, pose:SlotPose, time:Float, alpha:Float, blend:MixBlend) {
|
public function apply1(slot:Slot, pose:SlotPose, time:Float, alpha:Float, blend:MixBlend) {
|
||||||
var color = pose.color;
|
var color = pose.color;
|
||||||
|
var r:Float = 0, g:Float = 0, b:Float = 0;
|
||||||
if (time < frames[0]) {
|
if (time < frames[0]) {
|
||||||
var setup = slot.data.setup.color;
|
var setup = slot.data.setup.color;
|
||||||
switch (blend) {
|
switch (blend) {
|
||||||
@ -64,50 +65,51 @@ class RGBTimeline extends SlotCurveTimeline {
|
|||||||
color.r = setup.r;
|
color.r = setup.r;
|
||||||
color.g = setup.g;
|
color.g = setup.g;
|
||||||
color.b = setup.b;
|
color.b = setup.b;
|
||||||
|
return;
|
||||||
case MixBlend.first:
|
case MixBlend.first:
|
||||||
color.r += (setup.r - color.r) * alpha;
|
r = color.r + (setup.r - color.r) * alpha;
|
||||||
color.g += (setup.g - color.g) * alpha;
|
g = color.g + (setup.g - color.g) * alpha;
|
||||||
color.b += (setup.b - color.b) * alpha;
|
b = color.b + (setup.b - color.b) * alpha;
|
||||||
|
default:
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
var r:Float = 0, g:Float = 0, b:Float = 0;
|
|
||||||
var i:Int = Timeline.search(frames, time, ENTRIES);
|
|
||||||
var curveType:Int = Std.int(curves[Std.int(i / ENTRIES)]);
|
|
||||||
switch (curveType) {
|
|
||||||
case CurveTimeline.LINEAR:
|
|
||||||
var before:Float = frames[i];
|
|
||||||
r = frames[i + R];
|
|
||||||
g = frames[i + G];
|
|
||||||
b = frames[i + B];
|
|
||||||
var t:Float = (time - before) / (frames[i + ENTRIES] - before);
|
|
||||||
r += (frames[i + ENTRIES + R] - r) * t;
|
|
||||||
g += (frames[i + ENTRIES + G] - g) * t;
|
|
||||||
b += (frames[i + ENTRIES + B] - b) * t;
|
|
||||||
case CurveTimeline.STEPPED:
|
|
||||||
r = frames[i + R];
|
|
||||||
g = frames[i + G];
|
|
||||||
b = frames[i + B];
|
|
||||||
default:
|
|
||||||
r = getBezierValue(time, i, R, curveType - CurveTimeline.BEZIER);
|
|
||||||
g = getBezierValue(time, i, G, curveType + CurveTimeline.BEZIER_SIZE - CurveTimeline.BEZIER);
|
|
||||||
b = getBezierValue(time, i, B, curveType + CurveTimeline.BEZIER_SIZE * 2 - CurveTimeline.BEZIER);
|
|
||||||
}
|
|
||||||
if (alpha == 1) {
|
|
||||||
color.r = r;
|
|
||||||
color.g = g;
|
|
||||||
color.b = b;
|
|
||||||
} else {
|
} else {
|
||||||
if (blend == MixBlend.setup) {
|
var i:Int = Timeline.search(frames, time, ENTRIES);
|
||||||
var setup = slot.data.setup.color;
|
var curveType:Int = Std.int(curves[Std.int(i / ENTRIES)]);
|
||||||
color.r = setup.r;
|
switch (curveType) {
|
||||||
color.g = setup.g;
|
case CurveTimeline.LINEAR:
|
||||||
color.b = setup.b;
|
var before:Float = frames[i];
|
||||||
|
r = frames[i + R];
|
||||||
|
g = frames[i + G];
|
||||||
|
b = frames[i + B];
|
||||||
|
var t:Float = (time - before) / (frames[i + ENTRIES] - before);
|
||||||
|
r += (frames[i + ENTRIES + R] - r) * t;
|
||||||
|
g += (frames[i + ENTRIES + G] - g) * t;
|
||||||
|
b += (frames[i + ENTRIES + B] - b) * t;
|
||||||
|
case CurveTimeline.STEPPED:
|
||||||
|
r = frames[i + R];
|
||||||
|
g = frames[i + G];
|
||||||
|
b = frames[i + B];
|
||||||
|
default:
|
||||||
|
r = getBezierValue(time, i, R, curveType - CurveTimeline.BEZIER);
|
||||||
|
g = getBezierValue(time, i, G, curveType + CurveTimeline.BEZIER_SIZE - CurveTimeline.BEZIER);
|
||||||
|
b = getBezierValue(time, i, B, curveType + CurveTimeline.BEZIER_SIZE * 2 - CurveTimeline.BEZIER);
|
||||||
|
}
|
||||||
|
if (alpha != 1) {
|
||||||
|
if (blend == MixBlend.setup) {
|
||||||
|
var setup = slot.data.setup.color;
|
||||||
|
r = setup.r + (r - setup.r) * alpha;
|
||||||
|
g = setup.g + (g - setup.g) * alpha;
|
||||||
|
b = setup.b + (b - setup.b) * alpha;
|
||||||
|
} else {
|
||||||
|
r = color.r + (r - color.r) * alpha;
|
||||||
|
g = color.g + (g - color.g) * alpha;
|
||||||
|
b = color.b + (b - color.b) * alpha;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
color.r += (r - color.r) * alpha;
|
|
||||||
color.g += (g - color.g) * alpha;
|
|
||||||
color.b += (b - color.b) * alpha;
|
|
||||||
}
|
}
|
||||||
|
color.r = r < 0 ? 0 : (r > 1 ? 1 : r);
|
||||||
|
color.g = g < 0 ? 0 : (g > 1 ? 1 : g);
|
||||||
|
color.b = b < 0 ? 0 : (b > 1 ? 1 : b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -29,7 +29,6 @@
|
|||||||
|
|
||||||
package spine.animation;
|
package spine.animation;
|
||||||
|
|
||||||
import spine.attachments.VertexAttachment;
|
|
||||||
import spine.attachments.Attachment;
|
import spine.attachments.Attachment;
|
||||||
|
|
||||||
/** Changes a slot's Slot#getSequenceIndex() for an attachment's Sequence. */
|
/** Changes a slot's Slot#getSequenceIndex() for an attachment's Sequence. */
|
||||||
@ -39,9 +38,9 @@ class SequenceTimeline extends Timeline implements SlotTimeline {
|
|||||||
static var DELAY = 2;
|
static var DELAY = 2;
|
||||||
|
|
||||||
var slotIndex:Int;
|
var slotIndex:Int;
|
||||||
var attachment:HasTextureRegion;
|
var attachment:HasSequence;
|
||||||
|
|
||||||
public function new(frameCount:Int, slotIndex:Int, attachment:HasTextureRegion) {
|
public function new(frameCount:Int, slotIndex:Int, attachment:HasSequence) {
|
||||||
super(frameCount, Std.string(Property.sequence) + "|" + Std.string(slotIndex) + "|" + Std.string(attachment.sequence.id));
|
super(frameCount, Std.string(Property.sequence) + "|" + Std.string(slotIndex) + "|" + Std.string(attachment.sequence.id));
|
||||||
this.slotIndex = slotIndex;
|
this.slotIndex = slotIndex;
|
||||||
this.attachment = attachment;
|
this.attachment = attachment;
|
||||||
@ -55,6 +54,8 @@ class SequenceTimeline extends Timeline implements SlotTimeline {
|
|||||||
return this.slotIndex;
|
return this.slotIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** The attachment for which the sequenceIndex will be set.
|
||||||
|
* See VertexAttachment.timelineAttachment. */
|
||||||
public function getAttachment():Attachment {
|
public function getAttachment():Attachment {
|
||||||
return cast(attachment, Attachment);
|
return cast(attachment, Attachment);
|
||||||
}
|
}
|
||||||
@ -76,12 +77,11 @@ class SequenceTimeline extends Timeline implements SlotTimeline {
|
|||||||
return;
|
return;
|
||||||
var pose = appliedPose ? slot.applied : slot.pose;
|
var pose = appliedPose ? slot.applied : slot.pose;
|
||||||
|
|
||||||
var slotAttachment = pose.attachment;
|
var slotAttachment:Attachment = cast(pose.attachment, Attachment);
|
||||||
var attachment = cast(this.attachment, Attachment);
|
var attachmentRef:Attachment = cast(this.attachment, Attachment);
|
||||||
if (slotAttachment != attachment) {
|
|
||||||
if (!Std.isOfType(slotAttachment, VertexAttachment) || cast(slotAttachment, VertexAttachment).timelineAttachment != attachment)
|
if (!Std.isOfType(slotAttachment, HasSequence) || slotAttachment.timelineAttachment != attachmentRef)
|
||||||
return;
|
return;
|
||||||
}
|
|
||||||
|
|
||||||
if (direction == MixDirection.mixOut) {
|
if (direction == MixDirection.mixOut) {
|
||||||
if (blend == MixBlend.setup)
|
if (blend == MixBlend.setup)
|
||||||
@ -100,10 +100,8 @@ class SequenceTimeline extends Timeline implements SlotTimeline {
|
|||||||
var modeAndIndex = Std.int(frames[i + SequenceTimeline.MODE]);
|
var modeAndIndex = Std.int(frames[i + SequenceTimeline.MODE]);
|
||||||
var delay = frames[i + SequenceTimeline.DELAY];
|
var delay = frames[i + SequenceTimeline.DELAY];
|
||||||
|
|
||||||
if (this.attachment.sequence == null)
|
var hasSeq:HasSequence = cast(slotAttachment, HasSequence);
|
||||||
return;
|
var index = modeAndIndex >> 4, count = hasSeq.sequence.regions.length;
|
||||||
var index = modeAndIndex >> 4,
|
|
||||||
count = this.attachment.sequence.regions.length;
|
|
||||||
var mode = SequenceMode.values[modeAndIndex & 0xf];
|
var mode = SequenceMode.values[modeAndIndex & 0xf];
|
||||||
if (mode != SequenceMode.hold) {
|
if (mode != SequenceMode.hold) {
|
||||||
index += Std.int(((time - before) / delay + 0.00001));
|
index += Std.int(((time - before) / delay + 0.00001));
|
||||||
|
|||||||
@ -30,13 +30,10 @@
|
|||||||
package spine.attachments;
|
package spine.attachments;
|
||||||
|
|
||||||
import spine.atlas.TextureAtlas;
|
import spine.atlas.TextureAtlas;
|
||||||
|
import spine.atlas.TextureAtlasRegion;
|
||||||
import spine.Skin;
|
import spine.Skin;
|
||||||
|
import spine.Sequence;
|
||||||
|
|
||||||
/**
|
|
||||||
* The interface which can be implemented to customize creating and populating attachments.
|
|
||||||
*
|
|
||||||
* @see https://esotericsoftware.com/spine-loading-skeleton-data#AttachmentLoader Loading skeleton data in the Spine Runtimes Guide
|
|
||||||
*/
|
|
||||||
class AtlasAttachmentLoader implements AttachmentLoader {
|
class AtlasAttachmentLoader implements AttachmentLoader {
|
||||||
private var atlas:TextureAtlas;
|
private var atlas:TextureAtlas;
|
||||||
|
|
||||||
@ -50,72 +47,41 @@ class AtlasAttachmentLoader implements AttachmentLoader {
|
|||||||
this.allowMissingRegions = allowMissingRegions;
|
this.allowMissingRegions = allowMissingRegions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private function loadSequence(name:String, basePath:String, sequence:Sequence) {
|
private function findRegions(name:String, basePath:String, sequence:Sequence):Void {
|
||||||
var regions = sequence.regions;
|
var regions = sequence.regions;
|
||||||
for (i in 0...regions.length) {
|
for (i in 0...regions.length)
|
||||||
var path = sequence.getPath(basePath, i);
|
regions[i] = findRegion(name, sequence.getPath(basePath, i));
|
||||||
regions[i] = this.atlas.findRegion(path);
|
}
|
||||||
if (regions[i] == null)
|
|
||||||
throw new SpineException("Region not found in atlas: " + path + " (sequence: " + name + ")");
|
private function findRegion(name:String, path:String):TextureAtlasRegion {
|
||||||
}
|
var region = atlas.findRegion(path);
|
||||||
|
if (region == null && !allowMissingRegions)
|
||||||
|
throw new SpineException("Region not found in atlas: " + path + " (attachment: " + name + ")");
|
||||||
|
return region;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return May be null to not load the attachment.
|
|
||||||
*/
|
|
||||||
public function newRegionAttachment(skin:Skin, name:String, path:String, sequence:Sequence):RegionAttachment {
|
public function newRegionAttachment(skin:Skin, name:String, path:String, sequence:Sequence):RegionAttachment {
|
||||||
var attachment = new RegionAttachment(name, path);
|
findRegions(name, path, sequence);
|
||||||
if (sequence != null) {
|
return new RegionAttachment(name, sequence);
|
||||||
this.loadSequence(name, path, sequence);
|
|
||||||
} else {
|
|
||||||
var region = this.atlas.findRegion(path);
|
|
||||||
if (region == null && !this.allowMissingRegions)
|
|
||||||
throw new SpineException("Region not found in atlas: " + path + " (region attachment: " + name + ")");
|
|
||||||
attachment.region = region;
|
|
||||||
}
|
|
||||||
return attachment;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return May be null to not load the attachment. In that case null should also be returned for child meshes.
|
|
||||||
*/
|
|
||||||
public function newMeshAttachment(skin:Skin, name:String, path:String, sequence:Sequence):MeshAttachment {
|
public function newMeshAttachment(skin:Skin, name:String, path:String, sequence:Sequence):MeshAttachment {
|
||||||
var attachment = new MeshAttachment(name, path);
|
findRegions(name, path, sequence);
|
||||||
if (sequence != null) {
|
return new MeshAttachment(name, sequence);
|
||||||
this.loadSequence(name, path, sequence);
|
|
||||||
} else {
|
|
||||||
var region = atlas.findRegion(path);
|
|
||||||
if (region == null && !this.allowMissingRegions)
|
|
||||||
throw new SpineException("Region not found in atlas: " + path + " (mesh attachment: " + name + ")");
|
|
||||||
attachment.region = region;
|
|
||||||
}
|
|
||||||
return attachment;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return May be null to not load the attachment.
|
|
||||||
*/
|
|
||||||
public function newBoundingBoxAttachment(skin:Skin, name:String):BoundingBoxAttachment {
|
public function newBoundingBoxAttachment(skin:Skin, name:String):BoundingBoxAttachment {
|
||||||
return new BoundingBoxAttachment(name);
|
return new BoundingBoxAttachment(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return May be null to not load the attachment.
|
|
||||||
*/
|
|
||||||
public function newPathAttachment(skin:Skin, name:String):PathAttachment {
|
public function newPathAttachment(skin:Skin, name:String):PathAttachment {
|
||||||
return new PathAttachment(name);
|
return new PathAttachment(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return May be null to not load the attachment.
|
|
||||||
*/
|
|
||||||
public function newPointAttachment(skin:Skin, name:String):PointAttachment {
|
public function newPointAttachment(skin:Skin, name:String):PointAttachment {
|
||||||
return new PointAttachment(name);
|
return new PointAttachment(name);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* @return May be null to not load the attachment.
|
|
||||||
*/
|
|
||||||
public function newClippingAttachment(skin:Skin, name:String):ClippingAttachment {
|
public function newClippingAttachment(skin:Skin, name:String):ClippingAttachment {
|
||||||
return new ClippingAttachment(name);
|
return new ClippingAttachment(name);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -33,11 +33,16 @@ package spine.attachments;
|
|||||||
class Attachment {
|
class Attachment {
|
||||||
private var _name:String;
|
private var _name:String;
|
||||||
|
|
||||||
|
/** Timelines for the timeline attachment are also applied to this attachment.
|
||||||
|
* May be null if no attachment-specific timelines should be applied. */
|
||||||
|
public var timelineAttachment:Attachment;
|
||||||
|
|
||||||
public function new(name:String) {
|
public function new(name:String) {
|
||||||
if (name == null) {
|
if (name == null) {
|
||||||
throw new SpineException("name cannot be null.");
|
throw new SpineException("name cannot be null.");
|
||||||
}
|
}
|
||||||
_name = name;
|
_name = name;
|
||||||
|
timelineAttachment = this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** The attachment's name. */
|
/** The attachment's name. */
|
||||||
|
|||||||
@ -30,6 +30,9 @@
|
|||||||
package spine.attachments;
|
package spine.attachments;
|
||||||
|
|
||||||
import spine.Color;
|
import spine.Color;
|
||||||
|
import spine.Sequence;
|
||||||
|
import spine.TextureRegion;
|
||||||
|
import spine.HasSequence;
|
||||||
import spine.atlas.TextureAtlasRegion;
|
import spine.atlas.TextureAtlasRegion;
|
||||||
import spine.atlas.TextureAtlasPage;
|
import spine.atlas.TextureAtlasPage;
|
||||||
|
|
||||||
@ -37,60 +40,114 @@ import spine.atlas.TextureAtlasPage;
|
|||||||
* supported. Each vertex has UVs (texture coordinates) and triangles are used to map an image on to the mesh.
|
* supported. Each vertex has UVs (texture coordinates) and triangles are used to map an image on to the mesh.
|
||||||
*
|
*
|
||||||
* @see https://esotericsoftware.com/spine-meshes Mesh attachments in the Spine User Guide */
|
* @see https://esotericsoftware.com/spine-meshes Mesh attachments in the Spine User Guide */
|
||||||
class MeshAttachment extends VertexAttachment implements HasTextureRegion {
|
class MeshAttachment extends VertexAttachment implements HasSequence {
|
||||||
public var region:TextureRegion;
|
public var sequence:Sequence;
|
||||||
public var path:String;
|
|
||||||
|
|
||||||
/** The UV pair for each vertex, normalized within the texture region. */
|
/** The UV pair for each vertex, normalized within the texture region. */
|
||||||
public var regionUVs = new Array<Float>();
|
public var regionUVs = new Array<Float>();
|
||||||
|
|
||||||
/** The UV pair for each vertex, normalized within the entire texture.
|
|
||||||
* See #updateRegion(). */
|
|
||||||
public var uvs = new Array<Float>();
|
|
||||||
|
|
||||||
/** Triplets of vertex indices which describe the mesh's triangulation. */
|
/** Triplets of vertex indices which describe the mesh's triangulation. */
|
||||||
public var triangles = new Array<Int>();
|
public var triangles = new Array<Int>();
|
||||||
|
|
||||||
|
/** The number of entries at the beginning of #vertices that make up the mesh hull. */
|
||||||
|
public var hullLength:Int = 0;
|
||||||
|
|
||||||
|
/** The name of the texture region for this attachment. */
|
||||||
|
public var path:String;
|
||||||
|
|
||||||
|
/** The color to tint the mesh. */
|
||||||
public var color:Color = new Color(1, 1, 1, 1);
|
public var color:Color = new Color(1, 1, 1, 1);
|
||||||
|
|
||||||
|
/** The parent mesh if this is a linked mesh, else null. A linked mesh shares the #bones, #vertices,
|
||||||
|
* #regionUVs, #triangles, #hullLength, #edges, #width, and #height with the
|
||||||
|
* parent mesh, but may have a different #name or #path (and therefore a different texture). */
|
||||||
|
private var _parentMesh:MeshAttachment;
|
||||||
|
|
||||||
|
/** Vertex index pairs describing edges for controlling triangulation, or null if nonessential data was not exported. Mesh
|
||||||
|
* triangles never cross edges. Triangulation is not performed at runtime. */
|
||||||
|
public var edges = new Array<Int>();
|
||||||
|
|
||||||
/** The width of the mesh's image, or zero if nonessential data was not exported. */
|
/** The width of the mesh's image, or zero if nonessential data was not exported. */
|
||||||
public var width:Float = 0;
|
public var width:Float = 0;
|
||||||
|
|
||||||
/** The height of the mesh's image, or zero if nonessential data was not exported. */
|
/** The height of the mesh's image, or zero if nonessential data was not exported. */
|
||||||
public var height:Float = 0;
|
public var height:Float = 0;
|
||||||
|
|
||||||
/** The number of entries at the beginning of #vertices that make up the mesh hull. */
|
|
||||||
public var hullLength:Int = 0;
|
|
||||||
|
|
||||||
/** Vertex index pairs describing edges for controlling triangulation, or null if nonessential data was not exported. Mesh
|
|
||||||
* triangles will never cross edges. Triangulation is not performed at runtime. */
|
|
||||||
public var edges = new Array<Int>();
|
|
||||||
|
|
||||||
public var rendererObject:Dynamic;
|
public var rendererObject:Dynamic;
|
||||||
public var sequence:Sequence;
|
|
||||||
|
|
||||||
/** The parent mesh if this is a linked mesh, else null. A linked mesh shares the #bones, #vertices,
|
public function new(name:String, sequence:Sequence) {
|
||||||
* #regionUVs, #triangles, #hullLength, #edges, #width, and #height with the
|
|
||||||
* parent mesh, but may have a different #name or #path (and therefore a different texture). */
|
|
||||||
private var _parentMesh:MeshAttachment;
|
|
||||||
|
|
||||||
/** Copy constructor. Use newLinkedMesh() if the other mesh is a linked mesh. */
|
|
||||||
public function new(name:String, path:String) {
|
|
||||||
super(name);
|
super(name);
|
||||||
this.path = path;
|
this.sequence = sequence;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Calculates uvs using the regionUVs and region. Must be called if the region, the region's properties, or
|
override public function copy():Attachment {
|
||||||
* the regionUVs are changed. */
|
if (_parentMesh != null)
|
||||||
public function updateRegion():Void {
|
return newLinkedMesh();
|
||||||
if (region == null) {
|
|
||||||
throw new SpineException("Region not set.");
|
var copy = new MeshAttachment(name, sequence.copy());
|
||||||
return;
|
copy.path = path;
|
||||||
|
copy.color.setFromColor(color);
|
||||||
|
copy.rendererObject = rendererObject;
|
||||||
|
|
||||||
|
this.copyTo(copy);
|
||||||
|
copy.regionUVs = regionUVs.copy();
|
||||||
|
copy.triangles = triangles.copy();
|
||||||
|
copy.hullLength = hullLength;
|
||||||
|
|
||||||
|
if (edges != null) {
|
||||||
|
copy.edges = edges.copy();
|
||||||
}
|
}
|
||||||
var regionUVs = this.regionUVs;
|
copy.width = width;
|
||||||
if (uvs.length != regionUVs.length) {
|
copy.height = height;
|
||||||
uvs = new Array<Float>();
|
|
||||||
uvs.resize(regionUVs.length);
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Calls Sequence.update() on this attachment's sequence. */
|
||||||
|
public function updateSequence():Void {
|
||||||
|
sequence.update(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public var parentMesh(get, set):MeshAttachment;
|
||||||
|
|
||||||
|
private function get_parentMesh():MeshAttachment {
|
||||||
|
return _parentMesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function set_parentMesh(parentMesh:MeshAttachment):MeshAttachment {
|
||||||
|
_parentMesh = parentMesh;
|
||||||
|
if (parentMesh != null) {
|
||||||
|
bones = parentMesh.bones;
|
||||||
|
vertices = parentMesh.vertices;
|
||||||
|
worldVerticesLength = parentMesh.worldVerticesLength;
|
||||||
|
regionUVs = parentMesh.regionUVs;
|
||||||
|
triangles = parentMesh.triangles;
|
||||||
|
hullLength = parentMesh.hullLength;
|
||||||
|
edges = parentMesh.edges;
|
||||||
|
width = parentMesh.width;
|
||||||
|
height = parentMesh.height;
|
||||||
|
}
|
||||||
|
return _parentMesh;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns a new mesh with the parentMesh set to this mesh's parent mesh, if any, else to this mesh. */
|
||||||
|
public function newLinkedMesh():MeshAttachment {
|
||||||
|
var copy = new MeshAttachment(name, sequence.copy());
|
||||||
|
copy.rendererObject = rendererObject;
|
||||||
|
copy.timelineAttachment = timelineAttachment;
|
||||||
|
copy.path = path;
|
||||||
|
copy.color.setFromColor(color);
|
||||||
|
copy.parentMesh = _parentMesh != null ? _parentMesh : this;
|
||||||
|
copy.updateSequence();
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Computes UVs for a mesh attachment.
|
||||||
|
* @param uvs Output array for the computed UVs, same length as regionUVs. */
|
||||||
|
public static function computeUVs(region:TextureRegion, regionUVs:Array<Float>, uvs:Array<Float>):Void {
|
||||||
|
if (region == null) {
|
||||||
|
throw "Region not set.";
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
var n = uvs.length;
|
var n = uvs.length;
|
||||||
var u = region.u, v = region.v, width:Float = 0, height:Float = 0;
|
var u = region.u, v = region.v, width:Float = 0, height:Float = 0;
|
||||||
@ -145,8 +202,8 @@ class MeshAttachment extends VertexAttachment implements HasTextureRegion {
|
|||||||
u = v = 0;
|
u = v = 0;
|
||||||
width = height = 1;
|
width = height = 1;
|
||||||
} else {
|
} else {
|
||||||
width = this.region.u2 - u;
|
width = region.u2 - u;
|
||||||
height = this.region.v2 - v;
|
height = region.v2 - v;
|
||||||
}
|
}
|
||||||
var i = 0;
|
var i = 0;
|
||||||
while (i < n) {
|
while (i < n) {
|
||||||
@ -155,72 +212,4 @@ class MeshAttachment extends VertexAttachment implements HasTextureRegion {
|
|||||||
i += 2;
|
i += 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public var parentMesh(get, set):MeshAttachment;
|
|
||||||
|
|
||||||
private function get_parentMesh():MeshAttachment {
|
|
||||||
return _parentMesh;
|
|
||||||
}
|
|
||||||
|
|
||||||
private function set_parentMesh(parentMesh:MeshAttachment):MeshAttachment {
|
|
||||||
_parentMesh = parentMesh;
|
|
||||||
if (parentMesh != null) {
|
|
||||||
bones = parentMesh.bones;
|
|
||||||
vertices = parentMesh.vertices;
|
|
||||||
worldVerticesLength = parentMesh.worldVerticesLength;
|
|
||||||
regionUVs = parentMesh.regionUVs;
|
|
||||||
triangles = parentMesh.triangles;
|
|
||||||
hullLength = parentMesh.hullLength;
|
|
||||||
edges = parentMesh.edges;
|
|
||||||
width = parentMesh.width;
|
|
||||||
height = parentMesh.height;
|
|
||||||
}
|
|
||||||
return _parentMesh;
|
|
||||||
}
|
|
||||||
|
|
||||||
override public function copy():Attachment {
|
|
||||||
if (parentMesh != null)
|
|
||||||
return newLinkedMesh();
|
|
||||||
|
|
||||||
var copy:MeshAttachment = new MeshAttachment(name, this.path);
|
|
||||||
copy.region = region;
|
|
||||||
copy.color.setFromColor(color);
|
|
||||||
copy.rendererObject = rendererObject;
|
|
||||||
|
|
||||||
this.copyTo(copy);
|
|
||||||
copy.regionUVs = regionUVs.copy();
|
|
||||||
copy.uvs = uvs.copy();
|
|
||||||
copy.triangles = triangles.copy();
|
|
||||||
copy.hullLength = hullLength;
|
|
||||||
|
|
||||||
copy.sequence = sequence != null ? sequence.copy() : null;
|
|
||||||
|
|
||||||
if (edges != null) {
|
|
||||||
copy.edges = edges.copy();
|
|
||||||
}
|
|
||||||
copy.width = width;
|
|
||||||
copy.height = height;
|
|
||||||
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
|
|
||||||
/** If the attachment has a sequence, the region may be changed. */
|
|
||||||
public override function computeWorldVertices(skeleton:Skeleton, slot:Slot, start:Int, count:Int, worldVertices:Array<Float>, offset:Int, stride:Int):Void {
|
|
||||||
if (sequence != null)
|
|
||||||
sequence.apply(slot.applied, this);
|
|
||||||
super.computeWorldVertices(skeleton, slot, start, count, worldVertices, offset, stride);
|
|
||||||
}
|
|
||||||
|
|
||||||
/** Returns a new mesh with the parentMesh set to this mesh's parent mesh, if any, else to this mesh. */
|
|
||||||
public function newLinkedMesh():MeshAttachment {
|
|
||||||
var copy:MeshAttachment = new MeshAttachment(name, path);
|
|
||||||
copy.rendererObject = rendererObject;
|
|
||||||
copy.region = region;
|
|
||||||
copy.color.setFromColor(color);
|
|
||||||
copy.timelineAttachment = timelineAttachment;
|
|
||||||
copy.parentMesh = this.parentMesh != null ? this.parentMesh : this;
|
|
||||||
if (copy.region != null)
|
|
||||||
copy.updateRegion();
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -30,12 +30,18 @@
|
|||||||
package spine.attachments;
|
package spine.attachments;
|
||||||
|
|
||||||
import spine.Color;
|
import spine.Color;
|
||||||
|
import spine.Sequence;
|
||||||
|
import spine.SlotPose;
|
||||||
|
import spine.Slot;
|
||||||
|
import spine.TextureRegion;
|
||||||
|
import spine.MathUtils;
|
||||||
|
import spine.HasSequence;
|
||||||
|
|
||||||
/** An attachment that displays a textured quadrilateral.
|
/** An attachment that displays a textured quadrilateral.
|
||||||
*
|
*
|
||||||
* @see https://esotericsoftware.com/spine-regions Region attachments in the Spine User Guide
|
* @see https://esotericsoftware.com/spine-regions Region attachments in the Spine User Guide
|
||||||
*/
|
*/
|
||||||
class RegionAttachment extends Attachment implements HasTextureRegion {
|
class RegionAttachment extends Attachment implements HasSequence {
|
||||||
public static inline var BLX:Int = 0;
|
public static inline var BLX:Int = 0;
|
||||||
public static inline var BLY:Int = 1;
|
public static inline var BLY:Int = 1;
|
||||||
public static inline var ULX:Int = 2;
|
public static inline var ULX:Int = 2;
|
||||||
@ -45,6 +51,8 @@ class RegionAttachment extends Attachment implements HasTextureRegion {
|
|||||||
public static inline var BRX:Int = 6;
|
public static inline var BRX:Int = 6;
|
||||||
public static inline var BRY:Int = 7;
|
public static inline var BRY:Int = 7;
|
||||||
|
|
||||||
|
public var sequence:Sequence;
|
||||||
|
|
||||||
/** The local x translation. */
|
/** The local x translation. */
|
||||||
public var x:Float = 0;
|
public var x:Float = 0;
|
||||||
|
|
||||||
@ -66,31 +74,86 @@ class RegionAttachment extends Attachment implements HasTextureRegion {
|
|||||||
/** The height of the region attachment in Spine. */
|
/** The height of the region attachment in Spine. */
|
||||||
public var height:Float = 0;
|
public var height:Float = 0;
|
||||||
|
|
||||||
public var color:Color = new Color(1, 1, 1, 1);
|
/** The name of the texture region for this attachment. */
|
||||||
public var path:String;
|
public var path:String;
|
||||||
|
|
||||||
|
/** The color to tint the region attachment. */
|
||||||
|
public var color:Color = new Color(1, 1, 1, 1);
|
||||||
|
|
||||||
public var rendererObject:Dynamic;
|
public var rendererObject:Dynamic;
|
||||||
public var region:TextureRegion;
|
|
||||||
public var sequence:Sequence;
|
|
||||||
|
|
||||||
/** For each of the 4 vertices, a pair of x,y values that is the local position of the vertex.
|
public function new(name:String, sequence:Sequence) {
|
||||||
*
|
|
||||||
* See RegionAttachment.updateRegion(). */
|
|
||||||
private var offset:Array<Float> = new Array<Float>();
|
|
||||||
|
|
||||||
public var uvs:Array<Float> = new Array<Float>();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param name The attachment name.
|
|
||||||
* @param path The path used to find the region for the attachment.
|
|
||||||
*/
|
|
||||||
public function new(name:String, path:String) {
|
|
||||||
super(name);
|
super(name);
|
||||||
this.path = path;
|
this.sequence = sequence;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Calculates the RegionAttachment.offsets and RegionAttachment.uvs using the region and the attachment's transform. Must be called if the
|
override public function copy():Attachment {
|
||||||
* region, the region's properties, or the transform are changed. */
|
var copy = new RegionAttachment(name, sequence.copy());
|
||||||
public function updateRegion():Void {
|
copy.path = path;
|
||||||
|
copy.x = x;
|
||||||
|
copy.y = y;
|
||||||
|
copy.scaleX = scaleX;
|
||||||
|
copy.scaleY = scaleY;
|
||||||
|
copy.rotation = rotation;
|
||||||
|
copy.width = width;
|
||||||
|
copy.height = height;
|
||||||
|
copy.color.setFromColor(color);
|
||||||
|
return copy;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Transforms the attachment's four vertices to world coordinates.
|
||||||
|
*
|
||||||
|
* @see https://esotericsoftware.com/spine-runtime-skeletons#World-transforms World transforms in the Spine Runtimes Guide
|
||||||
|
* @param worldVertices The output world vertices. Must have a length >= offset + 8.
|
||||||
|
* @param vertexOffsets The vertex offsets from the sequence.
|
||||||
|
* @param offset The worldVertices index to begin writing values.
|
||||||
|
* @param stride The number of worldVertices entries between the value pairs written. */
|
||||||
|
public function computeWorldVertices(slot:Slot, vertexOffsets:Array<Float>, worldVertices:Array<Float>, offset:Int, stride:Int):Void {
|
||||||
|
var bone = slot.bone.applied;
|
||||||
|
var x = bone.worldX, y = bone.worldY;
|
||||||
|
var a = bone.a, b = bone.b, c = bone.c, d = bone.d;
|
||||||
|
|
||||||
|
var offsetX = vertexOffsets[0];
|
||||||
|
var offsetY = vertexOffsets[1];
|
||||||
|
worldVertices[offset] = offsetX * a + offsetY * b + x; // br
|
||||||
|
worldVertices[offset + 1] = offsetX * c + offsetY * d + y;
|
||||||
|
offset += stride;
|
||||||
|
|
||||||
|
offsetX = vertexOffsets[2];
|
||||||
|
offsetY = vertexOffsets[3];
|
||||||
|
worldVertices[offset] = offsetX * a + offsetY * b + x; // bl
|
||||||
|
worldVertices[offset + 1] = offsetX * c + offsetY * d + y;
|
||||||
|
offset += stride;
|
||||||
|
|
||||||
|
offsetX = vertexOffsets[4];
|
||||||
|
offsetY = vertexOffsets[5];
|
||||||
|
worldVertices[offset] = offsetX * a + offsetY * b + x; // ul
|
||||||
|
worldVertices[offset + 1] = offsetX * c + offsetY * d + y;
|
||||||
|
offset += stride;
|
||||||
|
|
||||||
|
offsetX = vertexOffsets[6];
|
||||||
|
offsetY = vertexOffsets[7];
|
||||||
|
worldVertices[offset] = offsetX * a + offsetY * b + x; // ur
|
||||||
|
worldVertices[offset + 1] = offsetX * c + offsetY * d + y;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Returns the vertex offsets for the given slot pose. */
|
||||||
|
public function getOffsets(pose:SlotPose):Array<Float> {
|
||||||
|
return sequence.offsets[sequence.resolveIndex(pose)];
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Calls Sequence.update() on this attachment's sequence. */
|
||||||
|
public function updateSequence():Void {
|
||||||
|
sequence.update(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Computes UVs and offsets for a region attachment.
|
||||||
|
* @param uvs Output array for the computed UVs, length of 8.
|
||||||
|
* @param offset Output array for the computed vertex offsets, length of 8. */
|
||||||
|
public static function computeUVs(region:TextureRegion, x:Float, y:Float, scaleX:Float, scaleY:Float, rotation:Float,
|
||||||
|
width:Float, height:Float, offset:Array<Float>, uvs:Array<Float>):Void {
|
||||||
|
|
||||||
|
if (region == null) throw "Region not set.";
|
||||||
var regionScaleX = width / region.originalWidth * scaleX;
|
var regionScaleX = width / region.originalWidth * scaleX;
|
||||||
var regionScaleY = height / region.originalHeight * scaleY;
|
var regionScaleY = height / region.originalHeight * scaleY;
|
||||||
var localX = -width / 2 * scaleX + region.offsetX * regionScaleX;
|
var localX = -width / 2 * scaleX + region.offsetX * regionScaleX;
|
||||||
@ -100,7 +163,6 @@ class RegionAttachment extends Attachment implements HasTextureRegion {
|
|||||||
var radians = rotation * MathUtils.degRad;
|
var radians = rotation * MathUtils.degRad;
|
||||||
var cos = Math.cos(radians);
|
var cos = Math.cos(radians);
|
||||||
var sin = Math.sin(radians);
|
var sin = Math.sin(radians);
|
||||||
var x = this.x, y = this.y;
|
|
||||||
var localXCos = localX * cos + x;
|
var localXCos = localX * cos + x;
|
||||||
var localXSin = localX * sin;
|
var localXSin = localX * sin;
|
||||||
var localYCos = localY * cos + y;
|
var localYCos = localY * cos + y;
|
||||||
@ -109,7 +171,6 @@ class RegionAttachment extends Attachment implements HasTextureRegion {
|
|||||||
var localX2Sin = localX2 * sin;
|
var localX2Sin = localX2 * sin;
|
||||||
var localY2Cos = localY2 * cos + y;
|
var localY2Cos = localY2 * cos + y;
|
||||||
var localY2Sin = localY2 * sin;
|
var localY2Sin = localY2 * sin;
|
||||||
|
|
||||||
offset[0] = localXCos - localYSin;
|
offset[0] = localXCos - localYSin;
|
||||||
offset[1] = localYCos + localXSin;
|
offset[1] = localYCos + localXSin;
|
||||||
offset[2] = localXCos - localY2Sin;
|
offset[2] = localXCos - localY2Sin;
|
||||||
@ -128,83 +189,22 @@ class RegionAttachment extends Attachment implements HasTextureRegion {
|
|||||||
uvs[5] = 1;
|
uvs[5] = 1;
|
||||||
uvs[6] = 1;
|
uvs[6] = 1;
|
||||||
uvs[7] = 0;
|
uvs[7] = 0;
|
||||||
} else if (region.degrees == 90) {
|
|
||||||
uvs[0] = region.u2;
|
|
||||||
uvs[1] = region.v2;
|
|
||||||
uvs[2] = region.u;
|
|
||||||
uvs[3] = region.v2;
|
|
||||||
uvs[4] = region.u;
|
|
||||||
uvs[5] = region.v;
|
|
||||||
uvs[6] = region.u2;
|
|
||||||
uvs[7] = region.v;
|
|
||||||
} else {
|
} else {
|
||||||
uvs[0] = region.u;
|
|
||||||
uvs[1] = region.v2;
|
uvs[1] = region.v2;
|
||||||
uvs[2] = region.u;
|
uvs[2] = region.u;
|
||||||
uvs[3] = region.v;
|
|
||||||
uvs[4] = region.u2;
|
|
||||||
uvs[5] = region.v;
|
uvs[5] = region.v;
|
||||||
uvs[6] = region.u2;
|
uvs[6] = region.u2;
|
||||||
uvs[7] = region.v2;
|
if (region.degrees == 90) {
|
||||||
|
uvs[0] = region.u2;
|
||||||
|
uvs[3] = region.v2;
|
||||||
|
uvs[4] = region.u;
|
||||||
|
uvs[7] = region.v;
|
||||||
|
} else {
|
||||||
|
uvs[0] = region.u;
|
||||||
|
uvs[3] = region.v;
|
||||||
|
uvs[4] = region.u2;
|
||||||
|
uvs[7] = region.v2;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Transforms the attachment's four vertices to world coordinates. If the attachment has a RegionAttachment.sequence, the region may
|
|
||||||
* be changed.
|
|
||||||
*
|
|
||||||
* @see https://esotericsoftware.com/spine-runtime-skeletons#World-transforms World transforms in the Spine Runtimes Guide
|
|
||||||
* @param worldVertices The output world vertices. Must have a length >= offset + 8.
|
|
||||||
* @param offset The worldVertices index to begin writing values.
|
|
||||||
* @param stride The number of worldVertices entries between the value pairs written. */
|
|
||||||
public function computeWorldVertices(slot:Slot, worldVertices:Array<Float>, offset:Int, stride:Int):Void {
|
|
||||||
if (sequence != null)
|
|
||||||
sequence.apply(slot.applied, this);
|
|
||||||
|
|
||||||
var vertexOffset = this.offset;
|
|
||||||
var bone = slot.bone.applied;
|
|
||||||
var x = bone.worldX, y = bone.worldY;
|
|
||||||
var a = bone.a, b = bone.b, c = bone.c, d = bone.d;
|
|
||||||
var offsetX:Float = 0, offsetY:Float = 0;
|
|
||||||
|
|
||||||
offsetX = vertexOffset[0];
|
|
||||||
offsetY = vertexOffset[1];
|
|
||||||
worldVertices[offset] = offsetX * a + offsetY * b + x; // br
|
|
||||||
worldVertices[offset + 1] = offsetX * c + offsetY * d + y;
|
|
||||||
offset += stride;
|
|
||||||
|
|
||||||
offsetX = vertexOffset[2];
|
|
||||||
offsetY = vertexOffset[3];
|
|
||||||
worldVertices[offset] = offsetX * a + offsetY * b + x; // bl
|
|
||||||
worldVertices[offset + 1] = offsetX * c + offsetY * d + y;
|
|
||||||
offset += stride;
|
|
||||||
|
|
||||||
offsetX = vertexOffset[4];
|
|
||||||
offsetY = vertexOffset[5];
|
|
||||||
worldVertices[offset] = offsetX * a + offsetY * b + x; // ul
|
|
||||||
worldVertices[offset + 1] = offsetX * c + offsetY * d + y;
|
|
||||||
offset += stride;
|
|
||||||
|
|
||||||
offsetX = vertexOffset[6];
|
|
||||||
offsetY = vertexOffset[7];
|
|
||||||
worldVertices[offset] = offsetX * a + offsetY * b + x; // ur
|
|
||||||
worldVertices[offset + 1] = offsetX * c + offsetY * d + y;
|
|
||||||
}
|
|
||||||
|
|
||||||
override public function copy():Attachment {
|
|
||||||
var copy:RegionAttachment = new RegionAttachment(name, path);
|
|
||||||
copy.region = region;
|
|
||||||
copy.rendererObject = rendererObject;
|
|
||||||
copy.x = x;
|
|
||||||
copy.y = y;
|
|
||||||
copy.scaleX = scaleX;
|
|
||||||
copy.scaleY = scaleY;
|
|
||||||
copy.rotation = rotation;
|
|
||||||
copy.width = width;
|
|
||||||
copy.height = height;
|
|
||||||
copy.uvs = uvs.copy();
|
|
||||||
copy.offset = offset.copy();
|
|
||||||
copy.color.setFromColor(color);
|
|
||||||
copy.sequence = sequence != null ? sequence.copy() : null;
|
|
||||||
return copy;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -55,13 +55,8 @@ class VertexAttachment extends Attachment {
|
|||||||
/** Returns a unique ID for this attachment. */
|
/** Returns a unique ID for this attachment. */
|
||||||
public var id:Int = nextID++;
|
public var id:Int = nextID++;
|
||||||
|
|
||||||
/** Timelines for the timeline attachment are also applied to this attachment.
|
|
||||||
* May be null if no attachment-specific timelines should be applied. */
|
|
||||||
public var timelineAttachment:VertexAttachment;
|
|
||||||
|
|
||||||
public function new(name:String) {
|
public function new(name:String) {
|
||||||
super(name);
|
super(name);
|
||||||
timelineAttachment = this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Transforms the attachment's local vertices to world coordinates. If the slot's spine.SlotPose.deform is
|
/** Transforms the attachment's local vertices to world coordinates. If the slot's spine.SlotPose.deform is
|
||||||
|
|||||||
@ -174,12 +174,14 @@ class SkeletonSprite extends FlxTypedGroup<FlxObject> {
|
|||||||
numFloats = clippedVertexSize << 2;
|
numFloats = clippedVertexSize << 2;
|
||||||
if (numFloats > worldVertices.length)
|
if (numFloats > worldVertices.length)
|
||||||
worldVertices.resize(numFloats);
|
worldVertices.resize(numFloats);
|
||||||
region.computeWorldVertices(slot, worldVertices, 0, clippedVertexSize);
|
var sequence = region.sequence;
|
||||||
|
var sequenceIndex = sequence.resolveIndex(pose);
|
||||||
|
region.computeWorldVertices(slot, sequence.offsets[sequenceIndex], worldVertices, 0, clippedVertexSize);
|
||||||
|
|
||||||
mesh = getFlixelMeshFromRendererAttachment(region);
|
mesh = getFlixelMeshFromRendererAttachment(region);
|
||||||
mesh.graphic = region.region.texture;
|
mesh.graphic = sequence.regions[sequenceIndex].texture;
|
||||||
triangles = QUAD_INDICES;
|
triangles = QUAD_INDICES;
|
||||||
uvs = region.uvs;
|
uvs = sequence.getUVs(sequenceIndex);
|
||||||
attachmentColor = region.color;
|
attachmentColor = region.color;
|
||||||
} else if (Std.isOfType(attachment, MeshAttachment)) {
|
} else if (Std.isOfType(attachment, MeshAttachment)) {
|
||||||
var meshAttachment:MeshAttachment = cast(attachment, MeshAttachment);
|
var meshAttachment:MeshAttachment = cast(attachment, MeshAttachment);
|
||||||
@ -190,10 +192,12 @@ class SkeletonSprite extends FlxTypedGroup<FlxObject> {
|
|||||||
}
|
}
|
||||||
meshAttachment.computeWorldVertices(skeleton, slot, 0, meshAttachment.worldVerticesLength, worldVertices, 0, clippedVertexSize);
|
meshAttachment.computeWorldVertices(skeleton, slot, 0, meshAttachment.worldVerticesLength, worldVertices, 0, clippedVertexSize);
|
||||||
|
|
||||||
|
var sequence = meshAttachment.sequence;
|
||||||
|
var sequenceIndex = sequence.resolveIndex(pose);
|
||||||
mesh = getFlixelMeshFromRendererAttachment(meshAttachment);
|
mesh = getFlixelMeshFromRendererAttachment(meshAttachment);
|
||||||
mesh.graphic = meshAttachment.region.texture;
|
mesh.graphic = sequence.regions[sequenceIndex].texture;
|
||||||
triangles = meshAttachment.triangles;
|
triangles = meshAttachment.triangles;
|
||||||
uvs = meshAttachment.uvs;
|
uvs = sequence.getUVs(sequenceIndex);
|
||||||
attachmentColor = meshAttachment.color;
|
attachmentColor = meshAttachment.color;
|
||||||
} else if (Std.isOfType(attachment, ClippingAttachment)) {
|
} else if (Std.isOfType(attachment, ClippingAttachment)) {
|
||||||
var clip:ClippingAttachment = cast(attachment, ClippingAttachment);
|
var clip:ClippingAttachment = cast(attachment, ClippingAttachment);
|
||||||
@ -553,5 +557,4 @@ class SkeletonSprite extends FlxTypedGroup<FlxObject> {
|
|||||||
|
|
||||||
typedef RenderedAttachment = {
|
typedef RenderedAttachment = {
|
||||||
var rendererObject:Dynamic;
|
var rendererObject:Dynamic;
|
||||||
var region:TextureRegion;
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -127,15 +127,18 @@ class SkeletonSprite extends DisplayObject implements IAnimatable {
|
|||||||
verticesCount = verticesLength >> 1;
|
verticesCount = verticesLength >> 1;
|
||||||
if (worldVertices.length < verticesLength)
|
if (worldVertices.length < verticesLength)
|
||||||
worldVertices.resize(verticesLength);
|
worldVertices.resize(verticesLength);
|
||||||
region.computeWorldVertices(slot, worldVertices, 0, 2);
|
var sequence = region.sequence;
|
||||||
|
var sequenceIndex = sequence.resolveIndex(pose);
|
||||||
|
region.computeWorldVertices(slot, sequence.offsets[sequenceIndex], worldVertices, 0, 2);
|
||||||
|
|
||||||
mesh = null;
|
mesh = null;
|
||||||
|
var regionTexture = sequence.regions[sequenceIndex].texture;
|
||||||
if (Std.isOfType(region.rendererObject, SkeletonMesh)) {
|
if (Std.isOfType(region.rendererObject, SkeletonMesh)) {
|
||||||
mesh = cast(region.rendererObject, SkeletonMesh);
|
mesh = cast(region.rendererObject, SkeletonMesh);
|
||||||
mesh.texture = region.region.texture;
|
mesh.texture = regionTexture;
|
||||||
indices = QUAD_INDICES;
|
indices = QUAD_INDICES;
|
||||||
} else {
|
} else {
|
||||||
mesh = region.rendererObject = new SkeletonMesh(cast(region.region.texture, Texture));
|
mesh = region.rendererObject = new SkeletonMesh(cast(regionTexture, Texture));
|
||||||
|
|
||||||
indexData = mesh.getIndexData();
|
indexData = mesh.getIndexData();
|
||||||
indices = QUAD_INDICES;
|
indices = QUAD_INDICES;
|
||||||
@ -148,7 +151,7 @@ class SkeletonSprite extends DisplayObject implements IAnimatable {
|
|||||||
|
|
||||||
indexData = mesh.getIndexData();
|
indexData = mesh.getIndexData();
|
||||||
attachmentColor = region.color;
|
attachmentColor = region.color;
|
||||||
uvs = region.uvs;
|
uvs = sequence.getUVs(sequenceIndex);
|
||||||
} else if (Std.isOfType(attachment, MeshAttachment)) {
|
} else if (Std.isOfType(attachment, MeshAttachment)) {
|
||||||
var meshAttachment:MeshAttachment = cast(attachment, MeshAttachment);
|
var meshAttachment:MeshAttachment = cast(attachment, MeshAttachment);
|
||||||
verticesLength = meshAttachment.worldVerticesLength;
|
verticesLength = meshAttachment.worldVerticesLength;
|
||||||
@ -157,13 +160,16 @@ class SkeletonSprite extends DisplayObject implements IAnimatable {
|
|||||||
worldVertices.resize(verticesLength);
|
worldVertices.resize(verticesLength);
|
||||||
meshAttachment.computeWorldVertices(skeleton, slot, 0, meshAttachment.worldVerticesLength, worldVertices, 0, 2);
|
meshAttachment.computeWorldVertices(skeleton, slot, 0, meshAttachment.worldVerticesLength, worldVertices, 0, 2);
|
||||||
|
|
||||||
|
var sequence = meshAttachment.sequence;
|
||||||
|
var sequenceIndex = sequence.resolveIndex(pose);
|
||||||
mesh = null;
|
mesh = null;
|
||||||
|
var regionTexture = sequence.regions[sequenceIndex].texture;
|
||||||
if (Std.isOfType(meshAttachment.rendererObject, SkeletonMesh)) {
|
if (Std.isOfType(meshAttachment.rendererObject, SkeletonMesh)) {
|
||||||
mesh = cast(meshAttachment.rendererObject, SkeletonMesh);
|
mesh = cast(meshAttachment.rendererObject, SkeletonMesh);
|
||||||
mesh.texture = meshAttachment.region.texture;
|
mesh.texture = regionTexture;
|
||||||
indices = meshAttachment.triangles;
|
indices = meshAttachment.triangles;
|
||||||
} else {
|
} else {
|
||||||
mesh = meshAttachment.rendererObject = new SkeletonMesh(cast(meshAttachment.region.texture, Texture));
|
mesh = meshAttachment.rendererObject = new SkeletonMesh(cast(regionTexture, Texture));
|
||||||
|
|
||||||
indexData = mesh.getIndexData();
|
indexData = mesh.getIndexData();
|
||||||
indices = meshAttachment.triangles;
|
indices = meshAttachment.triangles;
|
||||||
@ -177,7 +183,7 @@ class SkeletonSprite extends DisplayObject implements IAnimatable {
|
|||||||
|
|
||||||
indexData = mesh.getIndexData();
|
indexData = mesh.getIndexData();
|
||||||
attachmentColor = meshAttachment.color;
|
attachmentColor = meshAttachment.color;
|
||||||
uvs = meshAttachment.uvs;
|
uvs = sequence.getUVs(sequenceIndex);
|
||||||
} else if (Std.isOfType(attachment, ClippingAttachment)) {
|
} else if (Std.isOfType(attachment, ClippingAttachment)) {
|
||||||
var clip:ClippingAttachment = cast(attachment, ClippingAttachment);
|
var clip:ClippingAttachment = cast(attachment, ClippingAttachment);
|
||||||
clipper.clipEnd(slot);
|
clipper.clipEnd(slot);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user