mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2025-12-22 10:16:01 +08:00
[haxe] Initial port complete. WIP.
This commit is contained in:
parent
9d8c32b496
commit
fafb585882
@ -1,20 +1,24 @@
|
||||
package spine;
|
||||
|
||||
class SequenceMode {
|
||||
public static var hold(default, never):RotateMode = new SequenceMode("hold");
|
||||
public static var once(default, never):RotateMode = new SequenceMode("once");
|
||||
public static var loop(default, never):RotateMode = new SequenceMode("loop");
|
||||
public static var pingpong(default, never):RotateMode = new SequenceMode("pingpong");
|
||||
public static var onceReverse(default, never):RotateMode = new SequenceMode("onceReverse");
|
||||
public static var loopReverse(default, never):RotateMode = new SequenceMode("loopReverse");
|
||||
public static var pingpongReverse(default, never):RotateMode = new SequenceMode("pingpongReverse");
|
||||
import openfl.Vector;
|
||||
|
||||
public static var values(default, never):Vector<SequenceMode> = Vector.ofArray([tangent, chain, chainScale]);
|
||||
class SequenceMode {
|
||||
public static var hold(default, never):SequenceMode = new SequenceMode("hold", 0);
|
||||
public static var once(default, never):SequenceMode = new SequenceMode("once", 1);
|
||||
public static var loop(default, never):SequenceMode = new SequenceMode("loop", 2);
|
||||
public static var pingpong(default, never):SequenceMode = new SequenceMode("pingpong", 3);
|
||||
public static var onceReverse(default, never):SequenceMode = new SequenceMode("onceReverse", 4);
|
||||
public static var loopReverse(default, never):SequenceMode = new SequenceMode("loopReverse", 5);
|
||||
public static var pingpongReverse(default, never):SequenceMode = new SequenceMode("pingpongReverse", 6);
|
||||
|
||||
public static var values(default, never):Vector<SequenceMode> = Vector.ofArray([hold, once, loop, pingpong, onceReverse, loopReverse, pingpongReverse]);
|
||||
|
||||
public var name(default, null):String;
|
||||
public var value:Int;
|
||||
|
||||
public function new(name:String) {
|
||||
public function new(name:String, value:Int) {
|
||||
this.name = name;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public static function fromName(name:String):SequenceMode {
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package spine;
|
||||
|
||||
import spine.animation.SequenceTimeline;
|
||||
import openfl.errors.ArgumentError;
|
||||
import openfl.errors.Error;
|
||||
import openfl.utils.ByteArray;
|
||||
@ -69,6 +70,9 @@ class SkeletonBinary {
|
||||
private static inline var SLOT_RGB2:Int = 4;
|
||||
private static inline var SLOT_ALPHA:Int = 5;
|
||||
|
||||
private static inline var ATTACHMENT_DEFORM = 0;
|
||||
private static inline var ATTACHMENT_SEQUENCE = 1;
|
||||
|
||||
private static inline var PATH_POSITION:Int = 0;
|
||||
private static inline var PATH_SPACING:Int = 1;
|
||||
private static inline var PATH_MIX:Int = 2;
|
||||
@ -253,13 +257,14 @@ class SkeletonBinary {
|
||||
for (linkedMesh in linkedMeshes) {
|
||||
var skin:Skin = linkedMesh.skin == null ? skeletonData.defaultSkin : skeletonData.findSkin(linkedMesh.skin);
|
||||
if (skin == null)
|
||||
throw new Error("Skin not found: " + linkedMesh.skin);
|
||||
throw new SpineException("Skin not found: " + linkedMesh.skin);
|
||||
var parent:Attachment = skin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent);
|
||||
if (parent == null)
|
||||
throw new Error("Parent mesh not found: " + linkedMesh.parent);
|
||||
linkedMesh.mesh.deformAttachment = linkedMesh.inheritDeform ? cast(parent, VertexAttachment) : linkedMesh.mesh;
|
||||
throw new SpineException("Parent mesh not found: " + linkedMesh.parent);
|
||||
linkedMesh.mesh.timelineAttachment = linkedMesh.inheritTimeline ? cast(parent, VertexAttachment) : linkedMesh.mesh;
|
||||
linkedMesh.mesh.parentMesh = cast(parent, MeshAttachment);
|
||||
linkedMesh.mesh.updateUVs();
|
||||
if (linkedMesh.mesh.region != null)
|
||||
linkedMesh.mesh.updateRegion();
|
||||
}
|
||||
linkedMeshes.length = 0;
|
||||
|
||||
@ -327,6 +332,16 @@ class SkeletonBinary {
|
||||
return skin;
|
||||
}
|
||||
|
||||
private function readSequence(input:BinaryInput):Sequence {
|
||||
if (!input.readBoolean())
|
||||
return null;
|
||||
var sequence = new Sequence(input.readInt(true));
|
||||
sequence.start = input.readInt(true);
|
||||
sequence.digits = input.readInt(true);
|
||||
sequence.setupIndex = input.readInt(true);
|
||||
return sequence;
|
||||
}
|
||||
|
||||
private function readAttachment(input:BinaryInput, skeletonData:SkeletonData, skin:Skin, slotIndex:Int, attachmentName:String,
|
||||
nonessential:Bool):Attachment {
|
||||
var vertexCount:Int;
|
||||
@ -357,10 +372,11 @@ class SkeletonBinary {
|
||||
width = input.readFloat();
|
||||
height = input.readFloat();
|
||||
color = input.readInt32();
|
||||
var sequence = readSequence(input);
|
||||
|
||||
if (path == null)
|
||||
path = name;
|
||||
var region:RegionAttachment = attachmentLoader.newRegionAttachment(skin, name, path);
|
||||
var region:RegionAttachment = attachmentLoader.newRegionAttachment(skin, name, path, sequence);
|
||||
if (region == null)
|
||||
return null;
|
||||
region.path = path;
|
||||
@ -372,7 +388,9 @@ class SkeletonBinary {
|
||||
region.width = width * scale;
|
||||
region.height = height * scale;
|
||||
region.color.setFromRgba8888(color);
|
||||
region.updateOffset();
|
||||
region.sequence = sequence;
|
||||
if (sequence == null)
|
||||
region.updateRegion();
|
||||
return region;
|
||||
case AttachmentType.boundingbox:
|
||||
vertexCount = input.readInt(true);
|
||||
@ -397,6 +415,7 @@ class SkeletonBinary {
|
||||
var triangles:Vector<Int> = readShortArray(input);
|
||||
vertices = readVertices(input, vertexCount);
|
||||
var hullLength:Int = input.readInt(true);
|
||||
var sequence = readSequence(input);
|
||||
var edges:Vector<Int> = null;
|
||||
if (nonessential) {
|
||||
edges = readShortArray(input);
|
||||
@ -406,7 +425,7 @@ class SkeletonBinary {
|
||||
|
||||
if (path == null)
|
||||
path = name;
|
||||
mesh = attachmentLoader.newMeshAttachment(skin, name, path);
|
||||
mesh = attachmentLoader.newMeshAttachment(skin, name, path, sequence);
|
||||
if (mesh == null)
|
||||
return null;
|
||||
mesh.path = path;
|
||||
@ -417,8 +436,10 @@ class SkeletonBinary {
|
||||
mesh.worldVerticesLength = vertexCount << 1;
|
||||
mesh.triangles = triangles;
|
||||
mesh.regionUVs = uvs;
|
||||
mesh.updateUVs();
|
||||
if (sequence == null)
|
||||
mesh.updateRegion();
|
||||
mesh.hullLength = hullLength << 1;
|
||||
mesh.sequence = sequence;
|
||||
if (nonessential) {
|
||||
mesh.edges = edges;
|
||||
mesh.width = width * scale;
|
||||
@ -430,7 +451,8 @@ class SkeletonBinary {
|
||||
color = input.readInt32();
|
||||
var skinName:String = input.readStringRef();
|
||||
var parent:String = input.readStringRef();
|
||||
var inheritDeform:Bool = input.readBoolean();
|
||||
var inheritTimelines:Bool = input.readBoolean();
|
||||
var sequence = readSequence(input);
|
||||
if (nonessential) {
|
||||
width = input.readFloat();
|
||||
height = input.readFloat();
|
||||
@ -438,16 +460,17 @@ class SkeletonBinary {
|
||||
|
||||
if (path == null)
|
||||
path = name;
|
||||
mesh = attachmentLoader.newMeshAttachment(skin, name, path);
|
||||
mesh = attachmentLoader.newMeshAttachment(skin, name, path, sequence);
|
||||
if (mesh == null)
|
||||
return null;
|
||||
mesh.path = path;
|
||||
mesh.color.setFromRgba8888(color);
|
||||
mesh.sequence = sequence;
|
||||
if (nonessential) {
|
||||
mesh.width = width * scale;
|
||||
mesh.height = height * scale;
|
||||
}
|
||||
this.linkedMeshes.push(new LinkedMeshBinary(mesh, skinName, slotIndex, parent, inheritDeform));
|
||||
this.linkedMeshes.push(new LinkedMeshBinary(mesh, skinName, slotIndex, parent, inheritTimelines));
|
||||
return mesh;
|
||||
case AttachmentType.path:
|
||||
var closed:Bool = input.readBoolean();
|
||||
@ -985,64 +1008,78 @@ class SkeletonBinary {
|
||||
var attachmentName:String = input.readStringRef();
|
||||
var attachment:VertexAttachment = cast(skin.getAttachment(slotIndex, attachmentName), VertexAttachment);
|
||||
if (attachment == null)
|
||||
throw new Error("Vertex attachment not found: " + attachmentName);
|
||||
var weighted:Bool = attachment.bones != null;
|
||||
var vertices:Vector<Float> = attachment.vertices;
|
||||
var deformLength:Int = weighted ? Std.int(vertices.length / 3 * 2) : vertices.length;
|
||||
|
||||
throw new SpineException("Vertex attachment not found: " + attachmentName);
|
||||
var timelineType = input.readByte();
|
||||
frameCount = input.readInt(true);
|
||||
frameLast = frameCount - 1;
|
||||
bezierCount = input.readInt(true);
|
||||
var deformTimeline:DeformTimeline = new DeformTimeline(frameCount, bezierCount, slotIndex, attachment);
|
||||
|
||||
time = input.readFloat();
|
||||
frame = 0;
|
||||
bezier = 0;
|
||||
while (true) {
|
||||
var deform:Vector<Float>;
|
||||
var end:Int = input.readInt(true);
|
||||
if (end == 0) {
|
||||
if (weighted) {
|
||||
deform = new Vector<Float>(deformLength, true);
|
||||
} else {
|
||||
deform = vertices;
|
||||
}
|
||||
} else {
|
||||
var v:Int, vn:Int;
|
||||
deform = new Vector<Float>(deformLength, true);
|
||||
var start:Int = input.readInt(true);
|
||||
end += start;
|
||||
if (scale == 1) {
|
||||
for (v in start...end) {
|
||||
deform[v] = input.readFloat();
|
||||
}
|
||||
} else {
|
||||
for (v in start...end) {
|
||||
deform[v] = input.readFloat() * scale;
|
||||
}
|
||||
}
|
||||
if (!weighted) {
|
||||
for (v in 0...deform.length) {
|
||||
deform[v] += vertices[v];
|
||||
}
|
||||
}
|
||||
}
|
||||
switch (timelineType) {
|
||||
case ATTACHMENT_DEFORM:
|
||||
var weighted:Bool = attachment.bones != null;
|
||||
var vertices:Vector<Float> = attachment.vertices;
|
||||
var deformLength:Int = weighted ? Std.int(vertices.length / 3 * 2) : vertices.length;
|
||||
|
||||
deformTimeline.setFrame(frame, time, deform);
|
||||
if (frame == frameLast)
|
||||
bezierCount = input.readInt(true);
|
||||
var deformTimeline:DeformTimeline = new DeformTimeline(frameCount, bezierCount, slotIndex, attachment);
|
||||
|
||||
time = input.readFloat();
|
||||
frame = 0;
|
||||
bezier = 0;
|
||||
while (true) {
|
||||
var deform:Vector<Float>;
|
||||
var end:Int = input.readInt(true);
|
||||
if (end == 0) {
|
||||
if (weighted) {
|
||||
deform = new Vector<Float>(deformLength, true);
|
||||
} else {
|
||||
deform = vertices;
|
||||
}
|
||||
} else {
|
||||
var v:Int, vn:Int;
|
||||
deform = new Vector<Float>(deformLength, true);
|
||||
var start:Int = input.readInt(true);
|
||||
end += start;
|
||||
if (scale == 1) {
|
||||
for (v in start...end) {
|
||||
deform[v] = input.readFloat();
|
||||
}
|
||||
} else {
|
||||
for (v in start...end) {
|
||||
deform[v] = input.readFloat() * scale;
|
||||
}
|
||||
}
|
||||
if (!weighted) {
|
||||
for (v in 0...deform.length) {
|
||||
deform[v] += vertices[v];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
deformTimeline.setFrame(frame, time, deform);
|
||||
if (frame == frameLast)
|
||||
break;
|
||||
time2 = input.readFloat();
|
||||
switch (input.readByte()) {
|
||||
case CURVE_STEPPED:
|
||||
deformTimeline.setStepped(frame);
|
||||
case CURVE_BEZIER:
|
||||
SkeletonBinary.setBezier(input, deformTimeline, bezier++, frame, 0, time, time2, 0, 1, 1);
|
||||
}
|
||||
time = time2;
|
||||
|
||||
frame++;
|
||||
}
|
||||
timelines.push(deformTimeline);
|
||||
case ATTACHMENT_SEQUENCE:
|
||||
var timeline = new SequenceTimeline(frameCount, slotIndex, cast(attachment, HasTextureRegion));
|
||||
for (frame in 0...frameCount) {
|
||||
var time = input.readFloat();
|
||||
var modeAndIndex = input.readInt32();
|
||||
timeline.setFrame(frame, time, SequenceMode.values[modeAndIndex & 0xf], modeAndIndex >> 4, input.readFloat());
|
||||
}
|
||||
timelines.push(timeline);
|
||||
break;
|
||||
time2 = input.readFloat();
|
||||
switch (input.readByte()) {
|
||||
case CURVE_STEPPED:
|
||||
deformTimeline.setStepped(frame);
|
||||
case CURVE_BEZIER:
|
||||
SkeletonBinary.setBezier(input, deformTimeline, bezier++, frame, 0, time, time2, 0, 1, 1);
|
||||
}
|
||||
time = time2;
|
||||
|
||||
frame++;
|
||||
}
|
||||
timelines.push(deformTimeline);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1193,13 +1230,13 @@ class LinkedMeshBinary {
|
||||
public var skin(default, null):String;
|
||||
public var slotIndex(default, null):Int;
|
||||
public var mesh(default, null):MeshAttachment;
|
||||
public var inheritDeform(default, null):Bool;
|
||||
public var inheritTimeline(default, null):Bool;
|
||||
|
||||
public function new(mesh:MeshAttachment, skin:String, slotIndex:Int, parent:String, inheritDeform:Bool) {
|
||||
public function new(mesh:MeshAttachment, skin:String, slotIndex:Int, parent:String, inheritTimeline:Bool) {
|
||||
this.mesh = mesh;
|
||||
this.skin = skin;
|
||||
this.slotIndex = slotIndex;
|
||||
this.parent = parent;
|
||||
this.inheritDeform = inheritDeform;
|
||||
this.inheritTimeline = inheritTimeline;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
package spine;
|
||||
|
||||
import spine.animation.SequenceTimeline;
|
||||
import haxe.Json;
|
||||
import openfl.errors.ArgumentError;
|
||||
import openfl.errors.Error;
|
||||
@ -97,7 +98,7 @@ class SkeletonJson {
|
||||
if (parentName != null) {
|
||||
parent = skeletonData.findBone(parentName);
|
||||
if (parent == null)
|
||||
throw new Error("Parent bone not found: " + parentName);
|
||||
throw new SpineException("Parent bone not found: " + parentName);
|
||||
}
|
||||
boneData = new BoneData(skeletonData.bones.length, Reflect.getProperty(boneMap, "name"), parent);
|
||||
boneData.length = getFloat(Reflect.getProperty(boneMap, "length")) * scale;
|
||||
@ -126,7 +127,7 @@ class SkeletonJson {
|
||||
var boneName:String = Reflect.getProperty(slotMap, "bone");
|
||||
boneData = skeletonData.findBone(boneName);
|
||||
if (boneData == null)
|
||||
throw new Error("Slot bone not found: " + boneName);
|
||||
throw new SpineException("Slot bone not found: " + boneName);
|
||||
var slotData:SlotData = new SlotData(skeletonData.slots.length, slotName, boneData);
|
||||
|
||||
var color:String = Reflect.getProperty(slotMap, "color");
|
||||
@ -155,22 +156,22 @@ class SkeletonJson {
|
||||
for (boneName in cast(Reflect.getProperty(constraintMap, "bones"), Array<Dynamic>)) {
|
||||
var bone:BoneData = skeletonData.findBone(boneName);
|
||||
if (bone == null)
|
||||
throw new Error("IK constraint bone not found: " + boneName);
|
||||
throw new SpineException("IK constraint bone not found: " + boneName);
|
||||
ikData.bones.push(bone);
|
||||
}
|
||||
|
||||
ikData.target = skeletonData.findBone(Reflect.getProperty(constraintMap, "target"));
|
||||
if (ikData.target == null)
|
||||
throw new Error("Target bone not found: " + Reflect.getProperty(constraintMap, "target"));
|
||||
throw new SpineException("Target bone not found: " + Reflect.getProperty(constraintMap, "target"));
|
||||
|
||||
ikData.mix = getFloat(Reflect.getProperty(constraintMap, "mix"), 1);
|
||||
ikData.softness = getFloat(Reflect.getProperty(constraintMap, "softness"), 0) * scale;
|
||||
ikData.bendDirection = (!Reflect.hasField(constraintMap, "bendPositive")
|
||||
|| cast(Reflect.getProperty(constraintMap, "bendPositive"), Bool)) ? 1 : -1;
|
||||
ikData.compress = (Reflect.hasField(constraintMap, "compress")
|
||||
&& cast(Reflect.getProperty(constraintMap, "compress"), Bool));
|
||||
ikData.stretch = (Reflect.hasField(constraintMap, "stretch") && cast(Reflect.getProperty(constraintMap, "stretch"), Bool));
|
||||
ikData.uniform = (Reflect.hasField(constraintMap, "uniform") && cast(Reflect.getProperty(constraintMap, "uniform"), Bool));
|
||||
ikData.softness = getFloat(Reflect.getProperty(constraintMap, "softness")) * scale;
|
||||
ikData.mix = getFloat(Reflect.getProperty(constraintMap, "mix"), 1);
|
||||
|
||||
skeletonData.ikConstraints.push(ikData);
|
||||
}
|
||||
@ -186,13 +187,13 @@ class SkeletonJson {
|
||||
for (boneName in cast(Reflect.getProperty(constraintMap, "bones"), Array<Dynamic>)) {
|
||||
var bone = skeletonData.findBone(boneName);
|
||||
if (bone == null)
|
||||
throw new Error("Transform constraint bone not found: " + boneName);
|
||||
throw new SpineException("Transform constraint bone not found: " + boneName);
|
||||
transformData.bones.push(bone);
|
||||
}
|
||||
|
||||
transformData.target = skeletonData.findBone(Reflect.getProperty(constraintMap, "target"));
|
||||
if (transformData.target == null)
|
||||
throw new Error("Target bone not found: " + Reflect.getProperty(constraintMap, "target"));
|
||||
throw new SpineException("Target bone not found: " + Reflect.getProperty(constraintMap, "target"));
|
||||
|
||||
transformData.local = Reflect.hasField(constraintMap, "local") ? cast(Reflect.getProperty(constraintMap, "local"), Bool) : false;
|
||||
transformData.relative = Reflect.hasField(constraintMap, "relative") ? cast(Reflect.getProperty(constraintMap, "relative"), Bool) : false;
|
||||
@ -225,13 +226,13 @@ class SkeletonJson {
|
||||
for (boneName in cast(Reflect.getProperty(constraintMap, "bones"), Array<Dynamic>)) {
|
||||
var bone = skeletonData.findBone(boneName);
|
||||
if (bone == null)
|
||||
throw new Error("Path constraint bone not found: " + boneName);
|
||||
throw new SpineException("Path constraint bone not found: " + boneName);
|
||||
pathData.bones.push(bone);
|
||||
}
|
||||
|
||||
pathData.target = skeletonData.findSlot(Reflect.getProperty(constraintMap, "target"));
|
||||
if (pathData.target == null)
|
||||
throw new Error("Path target slot not found: " + Reflect.getProperty(constraintMap, "target"));
|
||||
throw new SpineException("Path target slot not found: " + Reflect.getProperty(constraintMap, "target"));
|
||||
|
||||
pathData.positionMode = Reflect.hasField(constraintMap,
|
||||
"positionMode") ? PositionMode.fromName(Reflect.getProperty(constraintMap, "positionMode")) : PositionMode.percent;
|
||||
@ -264,7 +265,7 @@ class SkeletonJson {
|
||||
for (ii in 0...bones.length) {
|
||||
var boneData:BoneData = skeletonData.findBone(bones[ii]);
|
||||
if (boneData == null)
|
||||
throw new Error("Skin bone not found: " + bones[ii]);
|
||||
throw new SpineException("Skin bone not found: " + bones[ii]);
|
||||
skin.bones.push(boneData);
|
||||
}
|
||||
}
|
||||
@ -274,7 +275,7 @@ class SkeletonJson {
|
||||
for (ii in 0...ik.length) {
|
||||
var constraint:ConstraintData = skeletonData.findIkConstraint(ik[ii]);
|
||||
if (constraint == null)
|
||||
throw new Error("Skin IK constraint not found: " + ik[ii]);
|
||||
throw new SpineException("Skin IK constraint not found: " + ik[ii]);
|
||||
skin.constraints.push(constraint);
|
||||
}
|
||||
}
|
||||
@ -284,7 +285,7 @@ class SkeletonJson {
|
||||
for (ii in 0...transform.length) {
|
||||
var constraint:ConstraintData = skeletonData.findTransformConstraint(transform[ii]);
|
||||
if (constraint == null)
|
||||
throw new Error("Skin transform constraint not found: " + transform[ii]);
|
||||
throw new SpineException("Skin transform constraint not found: " + transform[ii]);
|
||||
skin.constraints.push(constraint);
|
||||
}
|
||||
}
|
||||
@ -294,7 +295,7 @@ class SkeletonJson {
|
||||
for (ii in 0...path.length) {
|
||||
var constraint:ConstraintData = skeletonData.findPathConstraint(path[ii]);
|
||||
if (constraint == null)
|
||||
throw new Error("Skin path constraint not found: " + path[ii]);
|
||||
throw new SpineException("Skin path constraint not found: " + path[ii]);
|
||||
skin.constraints.push(constraint);
|
||||
}
|
||||
}
|
||||
@ -325,13 +326,14 @@ class SkeletonJson {
|
||||
for (linkedMesh in linkedMeshes) {
|
||||
var parentSkin:Skin = linkedMesh.skin == null ? skeletonData.defaultSkin : skeletonData.findSkin(linkedMesh.skin);
|
||||
if (parentSkin == null)
|
||||
throw new Error("Skin not found: " + linkedMesh.skin);
|
||||
throw new SpineException("Skin not found: " + linkedMesh.skin);
|
||||
var parentMesh:Attachment = parentSkin.getAttachment(linkedMesh.slotIndex, linkedMesh.parent);
|
||||
if (parentMesh == null)
|
||||
throw new Error("Parent mesh not found: " + linkedMesh.parent);
|
||||
linkedMesh.mesh.deformAttachment = linkedMesh.inheritDeform ? cast(parentMesh, VertexAttachment) : linkedMesh.mesh;
|
||||
throw new SpineException("Parent mesh not found: " + linkedMesh.parent);
|
||||
linkedMesh.mesh.timelineAttachment = linkedMesh.inheritTimeline ? cast(parentMesh, VertexAttachment) : linkedMesh.mesh;
|
||||
linkedMesh.mesh.parentMesh = cast(parentMesh, MeshAttachment);
|
||||
linkedMesh.mesh.updateUVs();
|
||||
if (linkedMesh.mesh.region != null)
|
||||
linkedMesh.mesh.updateRegion();
|
||||
}
|
||||
linkedMeshes.length = 0;
|
||||
|
||||
@ -359,6 +361,16 @@ class SkeletonJson {
|
||||
return skeletonData;
|
||||
}
|
||||
|
||||
private function readSequence(map:Object) {
|
||||
if (map == null)
|
||||
return null;
|
||||
var sequence = new Sequence(getInt(map["count"], 0));
|
||||
sequence.start = getInt(map["start"], 1);
|
||||
sequence.digits = getInt(map["digits"], 0);
|
||||
sequence.setupIndex = getInt(map["setup"], 0);
|
||||
return sequence;
|
||||
}
|
||||
|
||||
private function readAttachment(map:Object, skin:Skin, slotIndex:Int, name:String, skeletonData:SkeletonData):Attachment {
|
||||
if (map["name"] != null)
|
||||
name = map["name"];
|
||||
@ -366,10 +378,12 @@ class SkeletonJson {
|
||||
var color:String;
|
||||
switch (AttachmentType.fromName(Reflect.hasField(map, "type") ? Reflect.getProperty(map, "type") : "region")) {
|
||||
case AttachmentType.region:
|
||||
var region:RegionAttachment = attachmentLoader.newRegionAttachment(skin, name, map["path"] != null ? map["path"] : name);
|
||||
var path = getString(map, "path", name);
|
||||
var sequence = readSequence(map["sequence"]);
|
||||
var region:RegionAttachment = attachmentLoader.newRegionAttachment(skin, name, path, sequence);
|
||||
if (region == null)
|
||||
return null;
|
||||
region.path = map["path"] != null ? map["path"] : name;
|
||||
region.path = path;
|
||||
region.x = getFloat(map["x"]) * scale;
|
||||
region.y = getFloat(map["y"]) * scale;
|
||||
region.scaleX = getFloat(map["scaleX"], 1);
|
||||
@ -377,36 +391,48 @@ class SkeletonJson {
|
||||
region.rotation = getFloat(map["rotation"]);
|
||||
region.width = getFloat(map["width"]) * scale;
|
||||
region.height = getFloat(map["height"]) * scale;
|
||||
region.sequence = sequence;
|
||||
|
||||
color = Reflect.getProperty(map, "color");
|
||||
if (color != null) {
|
||||
region.color.setFromString(color);
|
||||
}
|
||||
region.updateOffset();
|
||||
if (region.region != null)
|
||||
region.updateRegion();
|
||||
return region;
|
||||
case AttachmentType.mesh, AttachmentType.linkedmesh:
|
||||
var mesh:MeshAttachment = attachmentLoader.newMeshAttachment(skin, name, map["path"] != null ? map["path"] : name);
|
||||
var path = getString(map, "path", name);
|
||||
var sequence = readSequence(map["sequence"]);
|
||||
var mesh:MeshAttachment = attachmentLoader.newMeshAttachment(skin, name, path, sequence);
|
||||
if (mesh == null)
|
||||
return null;
|
||||
mesh.path = map["path"] != null ? map["path"] : name;
|
||||
mesh.path = path;
|
||||
|
||||
color = Reflect.getProperty(map, "color");
|
||||
if (color != null) {
|
||||
mesh.color.setFromString(color);
|
||||
}
|
||||
|
||||
mesh.width = getFloat(map["width"]) * scale;
|
||||
mesh.height = getFloat(map["height"]) * scale;
|
||||
mesh.sequence = sequence;
|
||||
|
||||
if (map["parent"] != null) {
|
||||
var inheritDeform:Bool = map.hasOwnProperty("deform") ? cast(map["deform"], Bool) : true;
|
||||
linkedMeshes.push(new LinkedMesh(mesh, map["skin"], slotIndex, map["parent"], inheritDeform));
|
||||
var inheritTimelines:Bool = map.hasOwnProperty("timelines") ? cast(map["timelines"], Bool) : true;
|
||||
linkedMeshes.push(new LinkedMesh(mesh, map["skin"], slotIndex, map["parent"], inheritTimelines));
|
||||
return mesh;
|
||||
}
|
||||
|
||||
var uvs:Vector<Float> = getFloatArray(map, "uvs");
|
||||
readVertices(map, mesh, uvs.length);
|
||||
mesh.triangles = getIntArray(map, "triangles");
|
||||
mesh.regionUVs = uvs;
|
||||
mesh.updateUVs();
|
||||
mesh.hullLength = (getInt(map["hull"])) * 2;
|
||||
if (mesh.region != null)
|
||||
mesh.updateRegion();
|
||||
|
||||
if (map["edges"] != null)
|
||||
mesh.edges = getIntArray(map, "edges");
|
||||
mesh.hullLength = (getInt(map["hull"])) * 2;
|
||||
return mesh;
|
||||
case AttachmentType.boundingbox:
|
||||
var box:BoundingBoxAttachment = attachmentLoader.newBoundingBoxAttachment(skin, name);
|
||||
@ -448,7 +474,7 @@ class SkeletonJson {
|
||||
if (end != null) {
|
||||
var slot:SlotData = skeletonData.findSlot(end);
|
||||
if (slot == null)
|
||||
throw new Error("Clipping end slot not found: " + end);
|
||||
throw new SpineException("Clipping end slot not found: " + end);
|
||||
clip.endSlot = slot;
|
||||
}
|
||||
var vertexCount:Int = Std.parseInt(map["vertexCount"]);
|
||||
@ -524,7 +550,7 @@ class SkeletonJson {
|
||||
var attachmentTimeline:AttachmentTimeline = new AttachmentTimeline(timelineMap.length, slotIndex);
|
||||
for (frame in 0...timelineMap.length) {
|
||||
keyMap = timelineMap[frame];
|
||||
attachmentTimeline.setFrame(frame, getFloat(Reflect.getProperty(keyMap, "time")), keyMap.name);
|
||||
attachmentTimeline.setFrame(frame, getFloat(Reflect.getProperty(keyMap, "time")), getString(keyMap, "name", null));
|
||||
}
|
||||
timelines.push(attachmentTimeline);
|
||||
} else if (timelineName == "rgba") {
|
||||
@ -672,7 +698,7 @@ class SkeletonJson {
|
||||
|
||||
timelines.push(rgb2Timeline);
|
||||
} else {
|
||||
throw new Error("Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")");
|
||||
throw new SpineException("Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -682,7 +708,7 @@ class SkeletonJson {
|
||||
for (boneName in bones) {
|
||||
var boneIndex:Int = skeletonData.findBoneIndex(boneName);
|
||||
if (boneIndex == -1)
|
||||
throw new Error("Bone not found: " + boneName);
|
||||
throw new SpineException("Bone not found: " + boneName);
|
||||
var boneMap:Object = bones[boneName];
|
||||
for (timelineName in boneMap) {
|
||||
timelineMap = boneMap[timelineName];
|
||||
@ -719,7 +745,7 @@ class SkeletonJson {
|
||||
var shearYTimeline:ShearYTimeline = new ShearYTimeline(timelineMap.length, timelineMap.length, boneIndex);
|
||||
timelines.push(readTimeline(timelineMap, shearYTimeline, 0, 1));
|
||||
} else {
|
||||
throw new Error("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")");
|
||||
throw new SpineException("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -839,7 +865,7 @@ class SkeletonJson {
|
||||
for (pathName in paths) {
|
||||
var index:Int = skeletonData.findPathConstraintIndex(pathName);
|
||||
if (index == -1)
|
||||
throw new Error("Path constraint not found: " + pathName);
|
||||
throw new SpineException("Path constraint not found: " + pathName);
|
||||
var pathData:PathConstraintData = skeletonData.pathConstraints[index];
|
||||
|
||||
var pathMap:Object = paths[pathName];
|
||||
@ -896,78 +922,99 @@ class SkeletonJson {
|
||||
}
|
||||
}
|
||||
|
||||
// Deform timelines.
|
||||
var deforms:Object = Reflect.getProperty(map, "deform");
|
||||
for (deformName in deforms) {
|
||||
var deformMap:Object = deforms[deformName];
|
||||
var skin:Skin = skeletonData.findSkin(deformName);
|
||||
// Attachment timelines.
|
||||
var attachments:Object = Reflect.getProperty(map, "attachments");
|
||||
for (attachmentsName in attachments) {
|
||||
var attachmentsMap:Object = attachments[attachmentsName];
|
||||
var skin:Skin = skeletonData.findSkin(attachmentsName);
|
||||
if (skin == null)
|
||||
throw new Error("Skin not found: " + deformName);
|
||||
throw new SpineException("Skin not found: " + attachmentsName);
|
||||
|
||||
for (slotName in deformMap) {
|
||||
slotMap = deformMap[slotName];
|
||||
for (slotMapName in attachmentsMap) {
|
||||
slotMap = attachmentsMap[slotMapName];
|
||||
slotIndex = skeletonData.findSlot(slotName).index;
|
||||
if (slotIndex == -1)
|
||||
throw new Error("Slot not found: " + slotName);
|
||||
for (timelineName in slotMap) {
|
||||
timelineMap = slotMap[timelineName];
|
||||
keyMap = timelineMap[0];
|
||||
if (keyMap == null)
|
||||
continue;
|
||||
|
||||
var attachment:VertexAttachment = cast(skin.getAttachment(slotIndex, timelineName), VertexAttachment);
|
||||
throw new SpineException("Slot not found: " + slotName);
|
||||
for (attachmentMapName in slotMap) {
|
||||
var attachmentMap = slotMap[attachmentMapName];
|
||||
var attachment:VertexAttachment = cast(skin.getAttachment(slotIndex, attachmentMapName), VertexAttachment);
|
||||
if (attachment == null)
|
||||
throw new Error("Deform attachment not found: " + timelineName);
|
||||
var weighted:Bool = attachment.bones != null;
|
||||
var vertices:Vector<Float> = attachment.vertices;
|
||||
var deformLength:Int = weighted ? Std.int(vertices.length / 3 * 2) : vertices.length;
|
||||
throw new SpineException("Timeline attachment not found: " + timelineName);
|
||||
|
||||
var deformTimeline:DeformTimeline = new DeformTimeline(timelineMap.length, timelineMap.length, slotIndex, attachment);
|
||||
time = getFloat(Reflect.getProperty(keyMap, "time"));
|
||||
frame = 0;
|
||||
bezier = 0;
|
||||
while (true) {
|
||||
var deform:Vector<Float>;
|
||||
var verticesValue:Vector<Float> = Reflect.getProperty(keyMap, "vertices");
|
||||
if (verticesValue == null) {
|
||||
deform = weighted ? new Vector<Float>(deformLength, true) : vertices;
|
||||
} else {
|
||||
deform = new Vector<Float>(deformLength, true);
|
||||
var start:Int = getInt(Reflect.getProperty(keyMap, "offset"));
|
||||
var temp:Vector<Float> = getFloatArray(keyMap, "vertices");
|
||||
for (i in 0...temp.length) {
|
||||
deform[start + i] = temp[i];
|
||||
}
|
||||
if (scale != 1) {
|
||||
for (i in start...start + temp.length) {
|
||||
deform[i] *= scale;
|
||||
for (timelineMapName in attachmentMap) {
|
||||
var timelineMap = attachmentMap[timelineMapName];
|
||||
var keyMap = timelineMap[0];
|
||||
if (keyMap == null)
|
||||
continue;
|
||||
|
||||
if (timelineMapName == "deform") {
|
||||
var weighted:Bool = attachment.bones != null;
|
||||
var vertices:Vector<Float> = attachment.vertices;
|
||||
var deformLength:Int = weighted ? Std.int(vertices.length / 3 * 2) : vertices.length;
|
||||
|
||||
var deformTimeline:DeformTimeline = new DeformTimeline(timelineMap.length, timelineMap.length, slotIndex, attachment);
|
||||
time = getFloat(Reflect.getProperty(keyMap, "time"));
|
||||
frame = 0;
|
||||
bezier = 0;
|
||||
while (true) {
|
||||
var deform:Vector<Float>;
|
||||
var verticesValue:Vector<Float> = Reflect.getProperty(keyMap, "vertices");
|
||||
if (verticesValue == null) {
|
||||
deform = weighted ? new Vector<Float>(deformLength, true) : vertices;
|
||||
} else {
|
||||
deform = new Vector<Float>(deformLength, true);
|
||||
var start:Int = getInt(Reflect.getProperty(keyMap, "offset"));
|
||||
var temp:Vector<Float> = getFloatArray(keyMap, "vertices");
|
||||
for (i in 0...temp.length) {
|
||||
deform[start + i] = temp[i];
|
||||
}
|
||||
if (scale != 1) {
|
||||
for (i in start...start + temp.length) {
|
||||
deform[i] *= scale;
|
||||
}
|
||||
}
|
||||
if (!weighted) {
|
||||
for (i in 0...deformLength) {
|
||||
deform[i] += vertices[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!weighted) {
|
||||
for (i in 0...deformLength) {
|
||||
deform[i] += vertices[i];
|
||||
|
||||
deformTimeline.setFrame(frame, time, deform);
|
||||
nextMap = timelineMap[frame + 1];
|
||||
if (nextMap == null) {
|
||||
deformTimeline.shrink(bezier);
|
||||
break;
|
||||
}
|
||||
time2 = getFloat(Reflect.getProperty(nextMap, "time"));
|
||||
curve = keyMap.curve;
|
||||
if (curve != null) {
|
||||
bezier = readCurve(curve, deformTimeline, bezier, frame, 0, time, time2, 0, 1, 1);
|
||||
}
|
||||
time = time2;
|
||||
keyMap = nextMap;
|
||||
|
||||
frame++;
|
||||
}
|
||||
}
|
||||
|
||||
deformTimeline.setFrame(frame, time, deform);
|
||||
nextMap = timelineMap[frame + 1];
|
||||
if (nextMap == null) {
|
||||
deformTimeline.shrink(bezier);
|
||||
break;
|
||||
timelines.push(deformTimeline);
|
||||
} else if (timelineMapName == "sequence") {
|
||||
var timeline = new SequenceTimeline(timelineMap.length, slotIndex, cast(attachment, HasTextureRegion));
|
||||
var lastDelay:Float = 0;
|
||||
var frame:Int = 0;
|
||||
while (frame < timelineMap.length) {
|
||||
var delay = getFloat(keyMap["delay"], lastDelay);
|
||||
var time = getFloat(keyMap["time"], 0);
|
||||
var mode = SequenceMode.fromName(getString(keyMap, "mode", "hold"));
|
||||
var index = getInt(keyMap["index"], 0);
|
||||
timeline.setFrame(frame, time, mode, index, delay);
|
||||
lastDelay = delay;
|
||||
keyMap = timelineMap[frame + 1];
|
||||
frame++;
|
||||
}
|
||||
timelines.push(timeline);
|
||||
}
|
||||
time2 = getFloat(Reflect.getProperty(nextMap, "time"));
|
||||
curve = keyMap.curve;
|
||||
if (curve != null) {
|
||||
bezier = readCurve(curve, deformTimeline, bezier, frame, 0, time, time2, 0, 1, 1);
|
||||
}
|
||||
time = time2;
|
||||
keyMap = nextMap;
|
||||
|
||||
frame++;
|
||||
}
|
||||
|
||||
timelines.push(deformTimeline);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -993,7 +1040,7 @@ class SkeletonJson {
|
||||
for (offsetMap in offsets) {
|
||||
slotIndex = skeletonData.findSlot(Reflect.getProperty(offsetMap, "slot")).index;
|
||||
if (slotIndex == -1)
|
||||
throw new Error("Slot not found: " + Reflect.getProperty(offsetMap, "slot"));
|
||||
throw new SpineException("Slot not found: " + Reflect.getProperty(offsetMap, "slot"));
|
||||
// Collect unchanged items.
|
||||
while (originalIndex != slotIndex) {
|
||||
unchanged[unchangedIndex++] = originalIndex++;
|
||||
@ -1028,7 +1075,7 @@ class SkeletonJson {
|
||||
for (eventMap in eventsMap) {
|
||||
var eventData:EventData = skeletonData.findEvent(Reflect.getProperty(eventMap, "name"));
|
||||
if (eventData == null)
|
||||
throw new Error("Event not found: " + Reflect.getProperty(eventMap, "name"));
|
||||
throw new SpineException("Event not found: " + Reflect.getProperty(eventMap, "name"));
|
||||
var event:Event = new Event(getFloat(Reflect.getProperty(eventMap, "time")), eventData);
|
||||
event.intValue = Reflect.hasField(eventMap, "int") ? getInt(Reflect.getProperty(eventMap, "int")) : eventData.intValue;
|
||||
event.floatValue = Reflect.hasField(eventMap, "float") ? getFloat(Reflect.getProperty(eventMap, "float")) : eventData.floatValue;
|
||||
@ -1128,6 +1175,18 @@ class SkeletonJson {
|
||||
return bezier + 1;
|
||||
}
|
||||
|
||||
static private function getValue(map:Object, name:String, defaultValue:Dynamic):Dynamic {
|
||||
if (map.hasOwnProperty(name))
|
||||
return map[name];
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
static private function getString(value:Object, name:String, defaultValue:String):String {
|
||||
if (Std.isOfType(value[name], String))
|
||||
return cast(value[name], String);
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
static private function getFloat(value:Object, defaultValue:Float = 0):Float {
|
||||
if (Std.isOfType(value, Float))
|
||||
return cast(value, Float);
|
||||
@ -1146,12 +1205,12 @@ class SkeletonJson {
|
||||
return values;
|
||||
}
|
||||
|
||||
static private function getInt(value:Object):Int {
|
||||
static private function getInt(value:Object, defaultValue:Int = 0):Int {
|
||||
if (Std.isOfType(value, Int))
|
||||
return cast(value, Int);
|
||||
var intValue:Null<Int> = Std.parseInt(value);
|
||||
if (intValue == null)
|
||||
intValue = 0;
|
||||
intValue = defaultValue;
|
||||
return intValue;
|
||||
}
|
||||
|
||||
@ -1170,13 +1229,13 @@ class LinkedMesh {
|
||||
public var skin(default, null):String;
|
||||
public var slotIndex(default, null):Int;
|
||||
public var mesh(default, null):MeshAttachment;
|
||||
public var inheritDeform(default, null):Bool;
|
||||
public var inheritTimeline(default, null):Bool;
|
||||
|
||||
public function new(mesh:MeshAttachment, skin:String, slotIndex:Int, parent:String, inheritDeform:Bool) {
|
||||
public function new(mesh:MeshAttachment, skin:String, slotIndex:Int, parent:String, inheritTimeline:Bool) {
|
||||
this.mesh = mesh;
|
||||
this.skin = skin;
|
||||
this.slotIndex = slotIndex;
|
||||
this.parent = parent;
|
||||
this.inheritDeform = inheritDeform;
|
||||
this.inheritTimeline = inheritTimeline;
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,7 +100,8 @@ class Skin {
|
||||
if (attachment.attachment == null)
|
||||
continue;
|
||||
if (Std.isOfType(attachment.attachment, MeshAttachment)) {
|
||||
attachment.attachment = new MeshAttachment(attachment.attachment.name).newLinkedMesh();
|
||||
var mesh = cast(attachment.attachment, MeshAttachment);
|
||||
attachment.attachment = new MeshAttachment(mesh.name, mesh.path).newLinkedMesh();
|
||||
setAttachment(attachment.slotIndex, attachment.name, attachment.attachment);
|
||||
} else {
|
||||
attachment.attachment = attachment.attachment.copy();
|
||||
|
||||
7
spine-haxe/spine-haxe/spine/SpineException.hx
Normal file
7
spine-haxe/spine-haxe/spine/SpineException.hx
Normal file
@ -0,0 +1,7 @@
|
||||
package spine;
|
||||
|
||||
class SpineException extends haxe.Exception {
|
||||
public function new(message:String) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@ -15,18 +15,23 @@ class Animation {
|
||||
|
||||
public function new(name:String, timelines:Vector<Timeline>, duration:Float) {
|
||||
if (name == null)
|
||||
throw new ArgumentError("name cannot be null.");
|
||||
if (timelines == null)
|
||||
throw new ArgumentError("timelines cannot be null.");
|
||||
throw new SpineException("name cannot be null.");
|
||||
_name = name;
|
||||
setTimelines(timelines);
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
public function setTimelines(timelines:Vector<Timeline>) {
|
||||
if (timelines == null)
|
||||
throw new SpineException("timelines cannot be null.");
|
||||
_timelines = timelines;
|
||||
_timelineIds = new Dictionary<String, Bool>();
|
||||
for (timeline in timelines) {
|
||||
var ids:Vector<String> = timeline.propertyIds;
|
||||
for (id in ids) {
|
||||
_timelineIds[id] = true;
|
||||
}
|
||||
}
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
public function hasTimeline(ids:Vector<String>):Bool {
|
||||
|
||||
@ -181,14 +181,22 @@ class AnimationState {
|
||||
} else {
|
||||
var timelineMode:Vector<Int> = current.timelineMode;
|
||||
|
||||
var firstFrame:Bool = current.timelinesRotation.length == 0;
|
||||
var shortestRotation = current.shortestRotation;
|
||||
var firstFrame:Bool = !shortestRotation && current.timelinesRotation.length != timelineCount << 1;
|
||||
if (firstFrame)
|
||||
current.timelinesRotation.length = timelineCount << 1;
|
||||
|
||||
for (ii in 0...timelineCount) {
|
||||
var timeline:Timeline = timelines[ii];
|
||||
var timelineBlend:MixBlend = timelineMode[ii] == SUBSEQUENT ? blend : MixBlend.setup;
|
||||
timeline.apply(skeleton, animationLast, applyTime, applyEvents, mix, timelineBlend, MixDirection.mixIn);
|
||||
if (!shortestRotation && Std.isOfType(timeline, RotateTimeline)) {
|
||||
this.applyRotateTimeline(cast(timeline, RotateTimeline), skeleton, applyTime, mix, timelineBlend, current.timelinesRotation, ii << 1,
|
||||
firstFrame);
|
||||
} else if (Std.isOfType(timeline, AttachmentTimeline)) {
|
||||
this.applyAttachmentTimeline(cast(timeline, AttachmentTimeline), skeleton, applyTime, blend, true);
|
||||
} else {
|
||||
timeline.apply(skeleton, animationLast, applyTime, applyEvents, mix, timelineBlend, MixDirection.mixIn);
|
||||
}
|
||||
}
|
||||
}
|
||||
queueEvents(current, animationTime);
|
||||
@ -255,8 +263,9 @@ class AnimationState {
|
||||
} else {
|
||||
var timelineMode:Vector<Int> = from.timelineMode;
|
||||
var timelineHoldMix:Vector<TrackEntry> = from.timelineHoldMix;
|
||||
var shortestRotation = from.shortestRotation;
|
||||
|
||||
var firstFrame:Bool = from.timelinesRotation.length != timelineCount << 1;
|
||||
var firstFrame:Bool = !shortestRotation && from.timelinesRotation.length != timelineCount << 1;
|
||||
if (firstFrame)
|
||||
from.timelinesRotation.length = timelineCount << 1;
|
||||
var timelinesRotation:Vector<Float> = from.timelinesRotation;
|
||||
@ -290,9 +299,15 @@ class AnimationState {
|
||||
|
||||
from.totalAlpha += alpha;
|
||||
|
||||
if (drawOrder && Std.isOfType(timeline, DrawOrderTimeline) && timelineBlend == MixBlend.setup)
|
||||
direction = MixDirection.mixIn;
|
||||
timeline.apply(skeleton, animationLast, applyTime, applyEvents, alpha, timelineBlend, direction);
|
||||
if (!shortestRotation && Std.isOfType(timeline, RotateTimeline)) {
|
||||
applyRotateTimeline(cast(timeline, RotateTimeline), skeleton, applyTime, alpha, timelineBlend, from.timelinesRotation, i << 1, firstFrame);
|
||||
} else if (Std.isOfType(timeline, AttachmentTimeline)) {
|
||||
applyAttachmentTimeline(cast(timeline, AttachmentTimeline), skeleton, applyTime, timelineBlend, attachments);
|
||||
} else {
|
||||
if (drawOrder && Std.isOfType(timeline, DrawOrderTimeline) && timelineBlend == MixBlend.setup)
|
||||
direction = MixDirection.mixIn;
|
||||
timeline.apply(skeleton, animationLast, applyTime, events, alpha, timelineBlend, direction);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -305,6 +320,83 @@ class AnimationState {
|
||||
return mix;
|
||||
}
|
||||
|
||||
public function applyAttachmentTimeline(timeline:AttachmentTimeline, skeleton:Skeleton, time:Float, blend:MixBlend, attachments:Bool) {
|
||||
var slot = skeleton.slots[timeline.slotIndex];
|
||||
if (!slot.bone.active)
|
||||
return;
|
||||
|
||||
if (time < timeline.frames[0]) { // Time is before first frame.
|
||||
if (blend == MixBlend.setup || blend == MixBlend.first)
|
||||
this.setAttachment(skeleton, slot, slot.data.attachmentName, attachments);
|
||||
} else
|
||||
this.setAttachment(skeleton, slot, timeline.attachmentNames[Timeline.search1(timeline.frames, time)], attachments);
|
||||
|
||||
// If an attachment wasn't set (ie before the first frame or attachments is false), set the setup attachment later.
|
||||
if (slot.attachmentState <= this.unkeyedState)
|
||||
slot.attachmentState = this.unkeyedState + SETUP;
|
||||
}
|
||||
|
||||
public function applyRotateTimeline(timeline:RotateTimeline, skeleton:Skeleton, time:Float, alpha:Float, blend:MixBlend, timelinesRotation:Vector<Float>,
|
||||
i:Int, firstFrame:Bool) {
|
||||
if (firstFrame)
|
||||
timelinesRotation[i] = 0;
|
||||
|
||||
if (alpha == 1) {
|
||||
timeline.apply(skeleton, 0, time, null, 1, blend, MixDirection.mixIn);
|
||||
return;
|
||||
}
|
||||
|
||||
var bone = skeleton.bones[timeline.boneIndex];
|
||||
if (!bone.active)
|
||||
return;
|
||||
var frames = timeline.frames;
|
||||
var r1:Float = 0, r2:Float = 0;
|
||||
if (time < frames[0]) {
|
||||
switch (blend) {
|
||||
case MixBlend.setup:
|
||||
bone.rotation = bone.data.rotation;
|
||||
default:
|
||||
return;
|
||||
case MixBlend.first:
|
||||
r1 = bone.rotation;
|
||||
r2 = bone.data.rotation;
|
||||
}
|
||||
} else {
|
||||
r1 = blend == MixBlend.setup ? bone.data.rotation : bone.rotation;
|
||||
r2 = bone.data.rotation + timeline.getCurveValue(time);
|
||||
}
|
||||
|
||||
// Mix between rotations using the direction of the shortest route on the first frame while detecting crosses.
|
||||
var total:Float = 0, diff:Float = r2 - r1;
|
||||
diff -= (16384.0 - Std.int((16384.499999999996 - diff / 360.0))) * 360.0;
|
||||
if (diff == 0) {
|
||||
total = timelinesRotation[i];
|
||||
} else {
|
||||
var lastTotal:Float = 0, lastDiff:Float = 0;
|
||||
if (firstFrame) {
|
||||
lastTotal = 0;
|
||||
lastDiff = diff;
|
||||
} else {
|
||||
lastTotal = timelinesRotation[i]; // Angle and direction of mix, including loops.
|
||||
lastDiff = timelinesRotation[i + 1]; // Difference between bones.
|
||||
}
|
||||
var current = diff > 0, dir = lastTotal >= 0;
|
||||
// Detect cross at 0 (not 180).
|
||||
if (MathUtils.signum(lastDiff) != MathUtils.signum(diff) && Math.abs(lastDiff) <= 90) {
|
||||
// A cross after a 360 rotation is a loop.
|
||||
if (Math.abs(lastTotal) > 180)
|
||||
lastTotal += 360 * MathUtils.signum(lastTotal);
|
||||
dir = current;
|
||||
}
|
||||
total = diff + lastTotal - lastTotal % 360; // Store loops as part of lastTotal.
|
||||
if (dir != current)
|
||||
total += 360 * MathUtils.signum(lastTotal);
|
||||
timelinesRotation[i] = total;
|
||||
}
|
||||
timelinesRotation[i + 1] = diff;
|
||||
bone.rotation = r1 + total * alpha;
|
||||
}
|
||||
|
||||
private function setAttachment(skeleton:Skeleton, slot:Slot, attachmentName:String, attachments:Bool):Void {
|
||||
slot.attachment = attachmentName == null ? null : skeleton.getAttachmentForSlotIndex(slot.data.index, attachmentName);
|
||||
if (attachments)
|
||||
@ -519,6 +611,9 @@ class AnimationState {
|
||||
entry.loop = loop;
|
||||
entry.holdPrevious = false;
|
||||
|
||||
entry.reverse = false;
|
||||
entry.shortestRotation = false;
|
||||
|
||||
entry.eventThreshold = 0;
|
||||
entry.attachmentThreshold = 0;
|
||||
entry.drawOrderThreshold = 0;
|
||||
@ -536,9 +631,10 @@ class AnimationState {
|
||||
entry.timeScale = 1;
|
||||
|
||||
entry.alpha = 1;
|
||||
entry.interruptAlpha = 1;
|
||||
entry.mixTime = 0;
|
||||
entry.mixDuration = last == null ? 0 : data.getMix(last.animation, animation);
|
||||
entry.interruptAlpha = 1;
|
||||
entry.totalAlpha = 0;
|
||||
entry.mixBlend = MixBlend.replace;
|
||||
return entry;
|
||||
}
|
||||
|
||||
@ -106,10 +106,10 @@ class DeformTimeline extends CurveTimeline implements SlotTimeline {
|
||||
if (!slot.bone.active)
|
||||
return;
|
||||
var slotAttachment:Attachment = slot.attachment;
|
||||
|
||||
if (!Std.isOfType(slotAttachment, VertexAttachment) || cast(slotAttachment, VertexAttachment).deformAttachment != attachment)
|
||||
if (slotAttachment == null)
|
||||
return;
|
||||
if (!Std.isOfType(slotAttachment, VertexAttachment) || cast(slotAttachment, VertexAttachment).timelineAttachment != attachment)
|
||||
return;
|
||||
var vertexAttachment:VertexAttachment = cast(slotAttachment, VertexAttachment);
|
||||
|
||||
var deform:Vector<Float> = slot.deform;
|
||||
if (deform.length == 0)
|
||||
@ -128,6 +128,7 @@ class DeformTimeline extends CurveTimeline implements SlotTimeline {
|
||||
return;
|
||||
}
|
||||
deform.length = vertexCount;
|
||||
var vertexAttachment:VertexAttachment = cast(slotAttachment, VertexAttachment);
|
||||
if (vertexAttachment.bones == null) {
|
||||
// Unweighted vertex positions.
|
||||
setupVertices = vertexAttachment.vertices;
|
||||
@ -152,6 +153,7 @@ class DeformTimeline extends CurveTimeline implements SlotTimeline {
|
||||
var lastVertices:Vector<Float> = vertices[frames.length - 1];
|
||||
if (alpha == 1) {
|
||||
if (blend == MixBlend.add) {
|
||||
var vertexAttachment:VertexAttachment = cast(slotAttachment, VertexAttachment);
|
||||
if (vertexAttachment.bones == null) {
|
||||
// Unweighted vertex positions, with alpha.
|
||||
setupVertices = vertexAttachment.vertices;
|
||||
@ -172,6 +174,7 @@ class DeformTimeline extends CurveTimeline implements SlotTimeline {
|
||||
} else {
|
||||
switch (blend) {
|
||||
case MixBlend.setup:
|
||||
var vertexAttachment:VertexAttachment = cast(slotAttachment, VertexAttachment);
|
||||
if (vertexAttachment.bones == null) {
|
||||
// Unweighted vertex positions, with alpha.
|
||||
setupVertices = vertexAttachment.vertices;
|
||||
@ -190,6 +193,7 @@ class DeformTimeline extends CurveTimeline implements SlotTimeline {
|
||||
deform[i] += (lastVertices[i] - deform[i]) * alpha;
|
||||
}
|
||||
case MixBlend.add:
|
||||
var vertexAttachment:VertexAttachment = cast(slotAttachment, VertexAttachment);
|
||||
if (vertexAttachment.bones == null) {
|
||||
// Unweighted vertex positions, with alpha.
|
||||
setupVertices = vertexAttachment.vertices;
|
||||
@ -215,6 +219,7 @@ class DeformTimeline extends CurveTimeline implements SlotTimeline {
|
||||
|
||||
if (alpha == 1) {
|
||||
if (blend == MixBlend.add) {
|
||||
var vertexAttachment:VertexAttachment = cast(slotAttachment, VertexAttachment);
|
||||
if (vertexAttachment.bones == null) {
|
||||
// Unweighted vertex positions, with alpha.
|
||||
setupVertices = vertexAttachment.vertices;
|
||||
@ -238,6 +243,7 @@ class DeformTimeline extends CurveTimeline implements SlotTimeline {
|
||||
} else {
|
||||
switch (blend) {
|
||||
case MixBlend.setup:
|
||||
var vertexAttachment:VertexAttachment = cast(slotAttachment, VertexAttachment);
|
||||
if (vertexAttachment.bones == null) {
|
||||
// Unweighted vertex positions, with alpha.
|
||||
setupVertices = vertexAttachment.vertices;
|
||||
@ -259,6 +265,7 @@ class DeformTimeline extends CurveTimeline implements SlotTimeline {
|
||||
deform[i] += (prev + (nextVertices[i] - prev) * percent - deform[i]) * alpha;
|
||||
}
|
||||
case MixBlend.add:
|
||||
var vertexAttachment:VertexAttachment = cast(slotAttachment, VertexAttachment);
|
||||
if (vertexAttachment.bones == null) {
|
||||
// Unweighted vertex positions, with alpha.
|
||||
setupVertices = vertexAttachment.vertices;
|
||||
|
||||
@ -26,5 +26,7 @@ class Property {
|
||||
public static inline var pathConstraintSpacing:Int = 17;
|
||||
public static inline var pathConstraintMix:Int = 18;
|
||||
|
||||
public static inline var sequence:Int = 19;
|
||||
|
||||
public function new() {}
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@ import spine.Event;
|
||||
import spine.Skeleton;
|
||||
|
||||
class RotateTimeline extends CurveTimeline1 implements BoneTimeline {
|
||||
private var boneIndex:Int = 0;
|
||||
public var boneIndex:Int = 0;
|
||||
|
||||
public function new(frameCount:Int, bezierCount:Int, boneIndex:Int) {
|
||||
super(frameCount, bezierCount, Vector.ofArray([Property.rotate + "|" + boneIndex]));
|
||||
|
||||
98
spine-haxe/spine-haxe/spine/animation/SequenceTimeline.hx
Normal file
98
spine-haxe/spine-haxe/spine/animation/SequenceTimeline.hx
Normal file
@ -0,0 +1,98 @@
|
||||
package spine.animation;
|
||||
|
||||
import openfl.Vector;
|
||||
import spine.attachments.VertexAttachment;
|
||||
import spine.attachments.Attachment;
|
||||
|
||||
class SequenceTimeline extends Timeline implements SlotTimeline {
|
||||
static var ENTRIES = 3;
|
||||
static var MODE = 1;
|
||||
static var DELAY = 2;
|
||||
|
||||
var slotIndex:Int;
|
||||
var attachment:HasTextureRegion;
|
||||
|
||||
public function new(frameCount:Int, slotIndex:Int, attachment:HasTextureRegion) {
|
||||
super(frameCount, Vector.ofArray([
|
||||
Std.string(Property.sequence) + "|" + Std.string(slotIndex) + "|" + Std.string(attachment.sequence.id)
|
||||
]));
|
||||
this.slotIndex = slotIndex;
|
||||
this.attachment = attachment;
|
||||
}
|
||||
|
||||
public override function getFrameEntries():Int {
|
||||
return SequenceTimeline.ENTRIES;
|
||||
}
|
||||
|
||||
public function getSlotIndex():Int {
|
||||
return this.slotIndex;
|
||||
}
|
||||
|
||||
public function getAttachment():Attachment {
|
||||
return cast(attachment, Attachment);
|
||||
}
|
||||
|
||||
/** Sets the time, mode, index, and frame time for the specified frame.
|
||||
* @param frame Between 0 and <code>frameCount</code>, inclusive.
|
||||
* @param time Seconds between frames. */
|
||||
public function setFrame(frame:Int, time:Float, mode:SequenceMode, index:Int, delay:Float) {
|
||||
frame *= SequenceTimeline.ENTRIES;
|
||||
frames[frame] = time;
|
||||
frames[frame + SequenceTimeline.MODE] = mode.value | (index << 4);
|
||||
frames[frame + SequenceTimeline.DELAY] = delay;
|
||||
}
|
||||
|
||||
public override function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Vector<Event>, alpha:Float, blend:MixBlend,
|
||||
direction:MixDirection):Void {
|
||||
var slot = skeleton.slots[this.slotIndex];
|
||||
if (!slot.bone.active)
|
||||
return;
|
||||
var slotAttachment = slot.attachment;
|
||||
var attachment = cast(this.attachment, Attachment);
|
||||
if (slotAttachment != attachment) {
|
||||
if (!Std.isOfType(slotAttachment, VertexAttachment) || cast(slotAttachment, VertexAttachment).timelineAttachment != attachment)
|
||||
return;
|
||||
}
|
||||
|
||||
if (time < frames[0]) { // Time is before first frame.
|
||||
if (blend == MixBlend.setup || blend == MixBlend.first)
|
||||
slot.sequenceIndex = -1;
|
||||
return;
|
||||
}
|
||||
|
||||
var i = Timeline.search(frames, time, SequenceTimeline.ENTRIES);
|
||||
var before = frames[i];
|
||||
var modeAndIndex = Std.int(frames[i + SequenceTimeline.MODE]);
|
||||
var delay = frames[i + SequenceTimeline.DELAY];
|
||||
|
||||
if (this.attachment.sequence == null)
|
||||
return;
|
||||
var index = modeAndIndex >> 4,
|
||||
count = this.attachment.sequence.regions.length;
|
||||
var mode = SequenceMode.values[modeAndIndex & 0xf];
|
||||
if (mode != SequenceMode.hold) {
|
||||
index += Std.int(((time - before) / delay + 0.00001));
|
||||
switch (mode) {
|
||||
case SequenceMode.once:
|
||||
index = Std.int(Math.min(count - 1, index));
|
||||
case SequenceMode.loop:
|
||||
index %= count;
|
||||
case SequenceMode.pingpong:
|
||||
var n = (count << 1) - 2;
|
||||
index = n == 0 ? 0 : index % n;
|
||||
if (index >= count)
|
||||
index = n - index;
|
||||
case SequenceMode.onceReverse:
|
||||
index = Std.int(Math.max(count - 1 - index, 0));
|
||||
case SequenceMode.loopReverse:
|
||||
index = count - 1 - (index % count);
|
||||
case SequenceMode.pingpongReverse:
|
||||
var n = (count << 1) - 2;
|
||||
index = n == 0 ? 0 : (index + count - 1) % n;
|
||||
if (index >= count)
|
||||
index = n - index;
|
||||
}
|
||||
}
|
||||
slot.sequenceIndex = index;
|
||||
}
|
||||
}
|
||||
@ -26,7 +26,7 @@ class Timeline {
|
||||
}
|
||||
|
||||
public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Vector<Event>, alpha:Float, blend:MixBlend, direction:MixDirection):Void {
|
||||
trace("Timeline implementations must override apply()");
|
||||
throw new SpineException("Timeline implementations must override apply()");
|
||||
}
|
||||
|
||||
public static function search1(frames:Vector<Float>, time:Float):Int {
|
||||
|
||||
@ -42,6 +42,7 @@ class TrackEntry implements Poolable {
|
||||
public var timelineMode:Vector<Int> = new Vector<Int>();
|
||||
public var timelineHoldMix:Vector<TrackEntry> = new Vector<TrackEntry>();
|
||||
public var timelinesRotation:Vector<Float> = new Vector<Float>();
|
||||
public var shortestRotation = false;
|
||||
|
||||
public function new() {}
|
||||
|
||||
|
||||
@ -20,49 +20,34 @@ class AtlasAttachmentLoader implements AttachmentLoader {
|
||||
var path = sequence.getPath(basePath, i);
|
||||
var region = this.atlas.findRegion(path);
|
||||
if (region == null)
|
||||
trace("Region not found in atlas: " + path + " (sequence: " + name + ")");
|
||||
throw new SpineException("Region not found in atlas: " + path + " (sequence: " + name + ")");
|
||||
regions[i] = region;
|
||||
}
|
||||
}
|
||||
|
||||
public function newRegionAttachment(skin:Skin, name:String, path:String):RegionAttachment {
|
||||
var region = atlas.findRegion(path);
|
||||
if (region == null) {
|
||||
trace("Region not found in atlas: " + path + " (region attachment: " + name + ")");
|
||||
return null;
|
||||
public function newRegionAttachment(skin:Skin, name:String, path:String, sequence:Sequence):RegionAttachment {
|
||||
var attachment = new RegionAttachment(name, path);
|
||||
if (sequence != null) {
|
||||
this.loadSequence(name, path, sequence);
|
||||
} else {
|
||||
var region = this.atlas.findRegion(path);
|
||||
if (region == null)
|
||||
throw new SpineException("Region not found in atlas: " + path + " (region attachment: " + name + ")");
|
||||
attachment.region = region;
|
||||
}
|
||||
var attachment:RegionAttachment = new RegionAttachment(name);
|
||||
attachment.rendererObject = region;
|
||||
attachment.setUVs(region.u, region.v, region.u2, region.v2, region.degrees);
|
||||
attachment.regionOffsetX = region.offsetX;
|
||||
attachment.regionOffsetY = region.offsetY;
|
||||
attachment.regionWidth = region.width;
|
||||
attachment.regionHeight = region.height;
|
||||
attachment.regionOriginalWidth = region.originalWidth;
|
||||
attachment.regionOriginalHeight = region.originalHeight;
|
||||
return attachment;
|
||||
}
|
||||
|
||||
public function newMeshAttachment(skin:Skin, name:String, path:String):MeshAttachment {
|
||||
var region = atlas.findRegion(path);
|
||||
if (region == null) {
|
||||
trace("Region not found in atlas: " + path + " (mesh attachment: " + name + ")");
|
||||
return null;
|
||||
public function newMeshAttachment(skin:Skin, name:String, path:String, sequence:Sequence):MeshAttachment {
|
||||
var attachment = new MeshAttachment(name, path);
|
||||
if (sequence != null) {
|
||||
this.loadSequence(name, path, sequence);
|
||||
} else {
|
||||
var region = atlas.findRegion(path);
|
||||
if (region == null)
|
||||
throw new SpineException("Region not found in atlas: " + path + " (mesh attachment: " + name + ")");
|
||||
attachment.region = region;
|
||||
}
|
||||
|
||||
var attachment:MeshAttachment = new MeshAttachment(name);
|
||||
attachment.rendererObject = region;
|
||||
attachment.regionU = region.u;
|
||||
attachment.regionV = region.v;
|
||||
attachment.regionU2 = region.u2;
|
||||
attachment.regionV2 = region.v2;
|
||||
attachment.regionDegrees = region.degrees;
|
||||
attachment.regionOffsetX = region.offsetX;
|
||||
attachment.regionOffsetY = region.offsetY;
|
||||
attachment.regionWidth = region.width;
|
||||
attachment.regionHeight = region.height;
|
||||
attachment.regionOriginalWidth = region.originalWidth;
|
||||
attachment.regionOriginalHeight = region.originalHeight;
|
||||
return attachment;
|
||||
}
|
||||
|
||||
@ -81,14 +66,4 @@ class AtlasAttachmentLoader implements AttachmentLoader {
|
||||
public function newClippingAttachment(skin:Skin, name:String):ClippingAttachment {
|
||||
return new ClippingAttachment(name);
|
||||
}
|
||||
|
||||
static public function nextPOT(value:Int):Int {
|
||||
value--;
|
||||
value |= value >> 1;
|
||||
value |= value >> 2;
|
||||
value |= value >> 4;
|
||||
value |= value >> 8;
|
||||
value |= value >> 16;
|
||||
return value + 1;
|
||||
}
|
||||
}
|
||||
|
||||
@ -27,7 +27,7 @@ class MeshAttachment extends VertexAttachment implements HasTextureRegion {
|
||||
|
||||
public function updateRegion():Void {
|
||||
if (region == null) {
|
||||
trace("Region not set.");
|
||||
throw new SpineException("Region not set.");
|
||||
return;
|
||||
}
|
||||
var regionUVs = this.regionUVs;
|
||||
|
||||
@ -38,7 +38,7 @@ class RegionAttachment extends Attachment implements HasTextureRegion {
|
||||
|
||||
public function updateRegion():Void {
|
||||
if (region == null) {
|
||||
trace("Region not set.");
|
||||
throw new SpineException("Region not set.");
|
||||
uvs[0] = 0;
|
||||
uvs[1] = 0;
|
||||
uvs[2] = 0;
|
||||
|
||||
@ -18,7 +18,6 @@ class SkeletonAnimation extends SkeletonSprite implements IAnimatable {
|
||||
|
||||
public function advanceTime(time:Float):Void {
|
||||
var stage = Starling.current.stage;
|
||||
skeleton.update(time);
|
||||
state.update(time);
|
||||
state.apply(skeleton);
|
||||
skeleton.updateWorldTransform();
|
||||
|
||||
@ -80,7 +80,7 @@ class SkeletonSprite extends DisplayObject {
|
||||
verticesCount = verticesLength >> 1;
|
||||
if (worldVertices.length < verticesLength)
|
||||
worldVertices.length = verticesLength;
|
||||
region.computeWorldVertices(slot.bone, worldVertices, 0, 2);
|
||||
region.computeWorldVertices(slot, worldVertices, 0, 2);
|
||||
|
||||
mesh = null;
|
||||
if (Std.isOfType(region.rendererObject, SkeletonMesh)) {
|
||||
@ -220,7 +220,7 @@ class SkeletonSprite extends DisplayObject {
|
||||
if (Std.isOfType(attachment, RegionAttachment)) {
|
||||
var region:RegionAttachment = cast(slot.attachment, RegionAttachment);
|
||||
verticesLength = 8;
|
||||
region.computeWorldVertices(slot.bone, worldVertices, 0, 2);
|
||||
region.computeWorldVertices(slot, worldVertices, 0, 2);
|
||||
} else if (Std.isOfType(attachment, MeshAttachment)) {
|
||||
var mesh:MeshAttachment = cast(attachment, MeshAttachment);
|
||||
verticesLength = mesh.worldVerticesLength;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user