[as3] Added SkeletonBinary to load binary .skel files. See #1095.

This commit is contained in:
badlogic 2019-06-18 11:12:06 +02:00
parent 15b4c54888
commit e8866cc730
20 changed files with 1032 additions and 8 deletions

View File

@ -313,6 +313,7 @@ cp -f ../owl/export/owl.atlas "$ROOT/spine-starling/spine-starling-example/src/"
cp -f ../owl/export/owl.png "$ROOT/spine-starling/spine-starling-example/src/"
cp -f ../mix-and-match/export/mix-and-match-pro.json "$ROOT/spine-starling/spine-starling-example/src/"
cp -f ../mix-and-match/export/mix-and-match-pro.skel "$ROOT/spine-starling/spine-starling-example/src/"
cp -f ../mix-and-match/export/mix-and-match.atlas "$ROOT/spine-starling/spine-starling-example/src/"
cp -f ../mix-and-match/export/mix-and-match.png "$ROOT/spine-starling/spine-starling-example/src/"

View File

@ -45,10 +45,6 @@ encoding//src/spine/animation/TrackEntry.as=UTF-8
encoding//src/spine/animation/TransformConstraintTimeline.as=UTF-8
encoding//src/spine/animation/TranslateTimeline.as=UTF-8
encoding//src/spine/animation/TwoColorTimeline.as=UTF-8
encoding//src/spine/attachments/AtlasAttachmentLoader.as=UTF-8
encoding//src/spine/attachments/ClippingAttachment.as=UTF-8
encoding//src/spine/attachments/MeshAttachment.as=UTF-8
encoding//src/spine/attachments/PointAttachment.as=UTF-8
encoding//src/spine/interpolation/Pow.as=UTF-8
encoding//src/spine/interpolation/PowOut.as=UTF-8
encoding//src/spine/vertexeffects/JitterEffect.as=UTF-8

View File

@ -0,0 +1,117 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated May 1, 2019. Replaces all prior versions.
*
* Copyright (c) 2013-2019, 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.
*
* THIS SOFTWARE IS 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 THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
package spine {
import flash.utils.ByteArray;
class BinaryInput {
private var bytes : ByteArray;
public var strings : Vector.<String> = new Vector.<String>();
public function BinaryInput(bytes: ByteArray) {
this.bytes = bytes;
}
public function readByte() : int {
return bytes.readByte();
}
public function readShort() : int {
return bytes.readShort();
}
public function readInt32(): int {
return bytes.readInt();
}
public function readInt(optimizePositive: Boolean) : int {
var b : int = readByte();
var result : int = b & 0x7F;
if ((b & 0x80) != 0) {
b = readByte();
result |= (b & 0x7F) << 7;
if ((b & 0x80) != 0) {
b = readByte();
result |= (b & 0x7F) << 14;
if ((b & 0x80) != 0) {
b = readByte();
result |= (b & 0x7F) << 21;
if ((b & 0x80) != 0) {
b = readByte();
result |= (b & 0x7F) << 28;
}
}
}
}
return optimizePositive ? result : ((result >>> 1) ^ -(result & 1));
}
public function readStringRef (): String {
var index : int = readInt(true);
return index == 0 ? null : strings[index - 1];
}
public function readString () : String {
var byteCount : int = readInt(true);
switch (byteCount) {
case 0:
return null;
case 1:
return "";
}
byteCount--;
var chars : String = "";
for (var i : int = 0; i < byteCount;) {
var b : int = readByte();
switch (b >> 4) {
case 12:
case 13:
chars += String.fromCharCode(((b & 0x1F) << 6 | readByte() & 0x3F));
i += 2;
break;
case 14:
chars += String.fromCharCode(((b & 0x0F) << 12 | (readByte() & 0x3F) << 6 | readByte() & 0x3F));
i += 3;
break;
default:
chars += String.fromCharCode(b);
i++;
}
}
return chars;
}
public function readFloat (): Number {
return bytes.readFloat();
}
public function readBoolean (): Boolean {
return this.readByte() != 0;
}
}
}

View File

@ -38,5 +38,7 @@ package spine {
public function BlendMode(ordinal : int) {
this.ordinal = ordinal;
}
public static const values : Array = [ normal, additive, multiply, screen ];
}
}

View File

@ -42,6 +42,7 @@ package spine {
public var shearY : Number;
public var transformMode : TransformMode = TransformMode.normal;
public var skinRequired : Boolean;
public var color : Color = new Color(0, 0, 0, 0);
/** @param parent May be null. */
public function BoneData(index : int, name : String, parent : BoneData) {

View File

@ -95,5 +95,18 @@ package spine {
else if (this.a > 1) this.a = 1;
return this;
}
public function setFromRgba8888(value: int) : void {
r = ((value & 0xff000000) >>> 24) / 255;
g = ((value & 0x00ff0000) >>> 16) / 255;
b = ((value & 0x0000ff00) >>> 8) / 255;
a = ((value & 0x000000ff)) / 255;
}
public function setFromRgb888(value: int) : void {
r = ((value & 0x00ff0000) >>> 16) / 255;
g = ((value & 0x0000ff00) >>> 8) / 255;
b = ((value & 0x000000ff)) / 255;
}
}
}

View File

@ -31,5 +31,7 @@ package spine {
public class PositionMode {
public static const fixed : PositionMode = new PositionMode();
public static const percent : PositionMode = new PositionMode();
public static const values : Array = [ fixed, percent ];
}
}

View File

@ -32,5 +32,7 @@ package spine {
public static const tangent : RotateMode = new RotateMode();
public static const chain : RotateMode = new RotateMode();
public static const chainScale : RotateMode = new RotateMode();
public static const values : Array = [ tangent, chain, chainScale ];
}
}

View File

@ -0,0 +1,876 @@
/******************************************************************************
* Spine Runtimes License Agreement
* Last updated May 1, 2019. Replaces all prior versions.
*
* Copyright (c) 2013-2019, 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.
*
* THIS SOFTWARE IS 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 THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*****************************************************************************/
package spine {
import spine.attachments.ClippingAttachment;
import spine.animation.TwoColorTimeline;
import spine.attachments.PointAttachment;
import spine.animation.PathConstraintMixTimeline;
import spine.animation.PathConstraintSpacingTimeline;
import spine.animation.PathConstraintPositionTimeline;
import spine.animation.TransformConstraintTimeline;
import spine.animation.ShearTimeline;
import spine.attachments.PathAttachment;
import spine.attachments.VertexAttachment;
import flash.utils.ByteArray;
import spine.animation.Animation;
import spine.animation.AttachmentTimeline;
import spine.animation.ColorTimeline;
import spine.animation.CurveTimeline;
import spine.animation.DrawOrderTimeline;
import spine.animation.EventTimeline;
import spine.animation.DeformTimeline;
import spine.animation.IkConstraintTimeline;
import spine.animation.RotateTimeline;
import spine.animation.ScaleTimeline;
import spine.animation.Timeline;
import spine.animation.TranslateTimeline;
import spine.attachments.Attachment;
import spine.attachments.AttachmentLoader;
import spine.attachments.AttachmentType;
import spine.attachments.BoundingBoxAttachment;
import spine.attachments.MeshAttachment;
import spine.attachments.RegionAttachment;
public class SkeletonBinary {
public var attachmentLoader : AttachmentLoader;
public var scale : Number = 1;
private var linkedMeshes : Vector.<LinkedMesh> = new Vector.<LinkedMesh>();
private static const BONE_ROTATE : int = 0;
private static const BONE_TRANSLATE : int = 1;
private static const BONE_SCALE : int = 2;
private static const BONE_SHEAR : int = 3;
private static const SLOT_ATTACHMENT : int = 0;
private static const SLOT_COLOR : int = 1;
private static const SLOT_TWO_COLOR : int = 2;
private static const PATH_POSITION : int = 0;
private static const PATH_SPACING : int = 1;
private static const PATH_MIX : int = 2;
private static const CURVE_LINEAR : int = 0;
private static const CURVE_STEPPED : int = 1;
private static const CURVE_BEZIER : int = 2;
public function SkeletonBinary(attachmentLoader : AttachmentLoader = null) {
this.attachmentLoader = attachmentLoader;
}
/** @param object A String or ByteArray. */
public function readSkeletonData(object : *) : SkeletonData {
if (object == null) throw new ArgumentError("object cannot be null.");
if (!(object is ByteArray)) throw new ArgumentError("Object must be a ByteArray");
var scale : Number = this.scale;
var skeletonData : SkeletonData = new SkeletonData();
skeletonData.name = ""; // BOZO
var input : BinaryInput = new BinaryInput(object);
skeletonData.hash = input.readString();
skeletonData.version = input.readString();
skeletonData.x = input.readFloat();
skeletonData.y = input.readFloat();
skeletonData.width = input.readFloat();
skeletonData.height = input.readFloat();
var nonessential : Boolean = input.readBoolean();
if (nonessential) {
skeletonData.fps = input.readFloat();
skeletonData.imagesPath = input.readString();
skeletonData.audioPath = input.readString();
}
var n : int = 0;
var i : int = 0;
// Strings.
n = input.readInt(true);
for (i = 0; i < n; i++)
input.strings.push(input.readString());
// Bones.
n = input.readInt(true);
for (i = 0; i < n; i++) {
var boneName : String = input.readString();
var boneParent : BoneData = i == 0 ? null : skeletonData.bones[input.readInt(true)];
var boneData : BoneData = new BoneData(i, boneName, boneParent);
boneData.rotation = input.readFloat();
boneData.x = input.readFloat() * scale;
boneData.y = input.readFloat() * scale;
boneData.scaleX = input.readFloat();
boneData.scaleY = input.readFloat();
boneData.shearX = input.readFloat();
boneData.shearY = input.readFloat();
boneData.length = input.readFloat() * scale;
boneData.transformMode = TransformMode.values[input.readInt(true)];
boneData.skinRequired = input.readBoolean();
if (nonessential) boneData.color.setFromRgba8888(input.readInt32());
skeletonData.bones.push(boneData);
}
// Slots.
n = input.readInt(true);
for (i = 0; i < n; i++) {
var slotName : String = input.readString();
var slotBoneData : BoneData = skeletonData.bones[input.readInt(true)];
var slotData : SlotData = new SlotData(i, slotName, slotBoneData);
slotData.color.setFromRgba8888(input.readInt32());
var darkColor : int = input.readInt32();
if (darkColor != -1) slotData.darkColor.setFromRgb888(darkColor);
slotData.attachmentName = input.readStringRef();
slotData.blendMode = BlendMode.values[input.readInt(true)];
skeletonData.slots.push(slotData);
}
// IK constraints.
n = input.readInt(true);
var nn : int = 0;
var ii : int = 0;
for (i = 0; i < n; i++) {
var ikData : IkConstraintData = new IkConstraintData(input.readString());
ikData.order = input.readInt(true);
ikData.skinRequired = input.readBoolean();
nn = input.readInt(true);
for (ii = 0; ii < nn; ii++)
ikData.bones.push(skeletonData.bones[input.readInt(true)]);
ikData.target = skeletonData.bones[input.readInt(true)];
ikData.mix = input.readFloat();
ikData.bendDirection = input.readByte();
ikData.compress = input.readBoolean();
ikData.stretch = input.readBoolean();
ikData.uniform = input.readBoolean();
skeletonData.ikConstraints.push(ikData);
}
// Transform constraints.
n = input.readInt(true);
for (i = 0, nn; i < n; i++) {
var transData : TransformConstraintData = new TransformConstraintData(input.readString());
transData.order = input.readInt(true);
transData.skinRequired = input.readBoolean();
nn = input.readInt(true);
for (ii = 0; ii < nn; ii++)
transData.bones.push(skeletonData.bones[input.readInt(true)]);
transData.target = skeletonData.bones[input.readInt(true)];
transData.local = input.readBoolean();
transData.relative = input.readBoolean();
transData.offsetRotation = input.readFloat();
transData.offsetX = input.readFloat() * scale;
transData.offsetY = input.readFloat() * scale;
transData.offsetScaleX = input.readFloat();
transData.offsetScaleY = input.readFloat();
transData.offsetShearY = input.readFloat();
transData.rotateMix = input.readFloat();
transData.translateMix = input.readFloat();
transData.scaleMix = input.readFloat();
transData.shearMix = input.readFloat();
skeletonData.transformConstraints.push(transData);
}
// Path constraints.
n = input.readInt(true);
for (i = 0, nn; i < n; i++) {
var pathData : PathConstraintData = new PathConstraintData(input.readString());
pathData.order = input.readInt(true);
pathData.skinRequired = input.readBoolean();
nn = input.readInt(true);
for (ii = 0; ii < nn; ii++)
pathData.bones.push(skeletonData.bones[input.readInt(true)]);
pathData.target = skeletonData.slots[input.readInt(true)];
pathData.positionMode = PositionMode.values[input.readInt(true)];
pathData.spacingMode = SpacingMode.values[input.readInt(true)];
pathData.rotateMode = RotateMode.values[input.readInt(true)];
pathData.offsetRotation = input.readFloat();
pathData.position = input.readFloat();
if (pathData.positionMode == PositionMode.fixed) pathData.position *= scale;
pathData.spacing = input.readFloat();
if (pathData.spacingMode == SpacingMode.length || pathData.spacingMode == SpacingMode.fixed) pathData.spacing *= scale;
pathData.rotateMix = input.readFloat();
pathData.translateMix = input.readFloat();
skeletonData.pathConstraints.push(pathData);
}
// Default skin.
var defaultSkin : Skin = readSkin(input, skeletonData, true, nonessential);
if (defaultSkin != null) {
skeletonData.defaultSkin = defaultSkin;
skeletonData.skins.push(defaultSkin);
}
// Skins.
{
i = skeletonData.skins.length;
skeletonData.skins.length = n = i + input.readInt(true);
for (; i < n; i++)
skeletonData.skins[i] = readSkin(input, skeletonData, false, nonessential);
}
// Linked meshes.
n = this.linkedMeshes.length;
for (i = 0; i < n; i++) {
var linkedMesh : LinkedMesh = this.linkedMeshes[i];
var skin : Skin = linkedMesh.skin == null ? skeletonData.defaultSkin : skeletonData.findSkin(linkedMesh.skin);
if (skin == null) throw new Error("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 ? parent as VertexAttachment : linkedMesh.mesh;
linkedMesh.mesh.parentMesh = parent as MeshAttachment;
linkedMesh.mesh.updateUVs();
}
this.linkedMeshes.length = 0;
// Events.
n = input.readInt(true);
for (i = 0; i < n; i++) {
var data : EventData = new EventData(input.readStringRef());
data.intValue = input.readInt(false);
data.floatValue = input.readFloat();
data.stringValue = input.readString();
data.audioPath = input.readString();
if (data.audioPath != null) {
data.volume = input.readFloat();
data.balance = input.readFloat();
}
skeletonData.events.push(data);
}
// Animations.
n = input.readInt(true);
for (i = 0; i < n; i++)
skeletonData.animations.push(readAnimation(input, input.readString(), skeletonData));
return skeletonData;
}
private function readSkin (input: BinaryInput, skeletonData: SkeletonData, defaultSkin: Boolean, nonessential: Boolean): Skin {
var skin : Skin = new Skin(defaultSkin ? "default" : input.readStringRef());
var i : int = 0;
var n : int = 0;
var ii : int;
var nn: int;
if (!defaultSkin) {
skin.bones.length = input.readInt(true);
for (i = 0, n = skin.bones.length; i < n; i++)
skin.bones[i] = skeletonData.bones[input.readInt(true)];
for (i = 0, n = input.readInt(true); i < n; i++)
skin.constraints.push(skeletonData.ikConstraints[input.readInt(true)]);
for (i = 0, n = input.readInt(true); i < n; i++)
skin.constraints.push(skeletonData.transformConstraints[input.readInt(true)]);
for (i = 0, n = input.readInt(true); i < n; i++)
skin.constraints.push(skeletonData.pathConstraints[input.readInt(true)]);
}
for (i = 0, n = input.readInt(true); i < n; i++) {
var slotIndex : int = input.readInt(true);
for (ii = 0, nn = input.readInt(true); ii < nn; ii++) {
var name : String = input.readStringRef();
var attachment : Attachment = readAttachment(input, skeletonData, skin, slotIndex, name, nonessential);
if (attachment != null) skin.setAttachment(slotIndex, name, attachment);
}
}
return skin;
}
private function readAttachment(input: BinaryInput, skeletonData: SkeletonData, skin: Skin, slotIndex: Number, attachmentName: String, nonessential: Boolean): Attachment {
var scale : Number = this.scale;
var i : int = 0;
var n : int = 0;
var vertexCount : int;
var vertices : Vertices;
var path: String;
var rotation : Number;
var x : Number;
var y: Number;
var scaleX : Number;
var scaleY : Number;
var width : Number;
var height : Number;
var color : int;
var mesh : MeshAttachment;
var name : String = input.readStringRef();
if (name == null) name = attachmentName;
var typeIndex : int = input.readByte();
var type : AttachmentType = AttachmentType.values[typeIndex];
switch (type) {
case AttachmentType.region: {
path = input.readStringRef();
rotation = input.readFloat();
x = input.readFloat();
y = input.readFloat();
scaleX = input.readFloat();
scaleY = input.readFloat();
width = input.readFloat();
height = input.readFloat();
color = input.readInt32();
if (path == null) path = name;
var region : RegionAttachment = this.attachmentLoader.newRegionAttachment(skin, name, path);
if (region == null) return null;
region.path = path;
region.x = x * scale;
region.y = y * scale;
region.scaleX = scaleX;
region.scaleY = scaleY;
region.rotation = rotation;
region.width = width * scale;
region.height = height * scale;
region.color.setFromRgba8888(color);
region.updateOffset();
return region;
}
case AttachmentType.boundingbox: {
vertexCount = input.readInt(true);
vertices = readVertices(input, vertexCount);
color = nonessential ? input.readInt32() : 0;
var box : BoundingBoxAttachment = this.attachmentLoader.newBoundingBoxAttachment(skin, name);
if (box == null) return null;
box.worldVerticesLength = vertexCount << 1;
box.vertices = vertices.vertices;
box.bones = vertices.bones;
if (nonessential) box.color.setFromRgba8888(color);
return box;
}
case AttachmentType.mesh: {
path = input.readStringRef();
color = input.readInt32();
vertexCount = input.readInt(true);
var uvs : Vector.<Number> = readFloatArray(input, vertexCount << 1, 1);
var triangles : Vector.<uint> = readUnsignedShortArray(input);
vertices = readVertices(input, vertexCount);
var hullLength : int = input.readInt(true);
var edges : Vector.<int> = null;
if (nonessential) {
edges = readShortArray(input);
width = input.readFloat();
height = input.readFloat();
}
if (path == null) path = name;
mesh = this.attachmentLoader.newMeshAttachment(skin, name, path);
if (mesh == null) return null;
mesh.path = path;
mesh.color.setFromRgba8888(color);
mesh.bones = vertices.bones;
mesh.vertices = vertices.vertices;
mesh.worldVerticesLength = vertexCount << 1;
mesh.triangles = triangles;
mesh.regionUVs = uvs;
mesh.updateUVs();
mesh.hullLength = hullLength << 1;
if (nonessential) {
mesh.edges = edges;
mesh.width = width * scale;
mesh.height = height * scale;
}
return mesh;
}
case AttachmentType.linkedmesh: {
path = input.readStringRef();
color = input.readInt32();
var skinName : String = input.readStringRef();
var parent : String = input.readStringRef();
var inheritDeform : Boolean = input.readBoolean();
if (nonessential) {
width = input.readFloat();
height = input.readFloat();
}
if (path == null) path = name;
mesh = this.attachmentLoader.newMeshAttachment(skin, name, path);
if (mesh == null) return null;
mesh.path = path;
mesh.color.setFromRgba8888(color);
if (nonessential) {
mesh.width = width * scale;
mesh.height = height * scale;
}
this.linkedMeshes.push(new LinkedMesh(mesh, skinName, slotIndex, parent, inheritDeform));
return mesh;
}
case AttachmentType.path: {
var closed : Boolean = input.readBoolean();
var constantSpeed : Boolean = input.readBoolean();
vertexCount = input.readInt(true);
vertices = this.readVertices(input, vertexCount);
var lengths : Vector.<Number> = new Vector.<Number>();
lengths.length = vertexCount / 3;
for (i = 0, n = lengths.length; i < n; i++)
lengths[i] = input.readFloat() * scale;
color = nonessential ? input.readInt32() : 0;
var pathAttachment : PathAttachment = this.attachmentLoader.newPathAttachment(skin, name);
if (pathAttachment == null) return null;
pathAttachment.closed = closed;
pathAttachment.constantSpeed = constantSpeed;
pathAttachment.worldVerticesLength = vertexCount << 1;
pathAttachment.vertices = vertices.vertices;
pathAttachment.bones = vertices.bones;
pathAttachment.lengths = lengths;
if (nonessential) pathAttachment.color.setFromRgba8888(color);
return pathAttachment;
}
case AttachmentType.point: {
rotation = input.readFloat();
x = input.readFloat();
y = input.readFloat();
color = nonessential ? input.readInt32() : 0;
var point : PointAttachment = this.attachmentLoader.newPointAttachment(skin, name);
if (point == null) return null;
point.x = x * scale;
point.y = y * scale;
point.rotation = rotation;
if (nonessential) point.color.setFromRgba8888(color);
return point;
}
case AttachmentType.clipping: {
var endSlotIndex : int = input.readInt(true);
vertexCount = input.readInt(true);
vertices = this.readVertices(input, vertexCount);
color = nonessential ? input.readInt32() : 0;
var clip : ClippingAttachment = this.attachmentLoader.newClippingAttachment(skin, name);
if (clip == null) return null;
clip.endSlot = skeletonData.slots[endSlotIndex];
clip.worldVerticesLength = vertexCount << 1;
clip.vertices = vertices.vertices;
clip.bones = vertices.bones;
if (nonessential) clip.color.setFromRgba8888(color);
return clip;
}
}
return null;
}
private function readVertices (input: BinaryInput, vertexCount: int): Vertices {
var verticesLength : int = vertexCount << 1;
var vertices : Vertices = new Vertices();
var scale : Number = this.scale;
if (!input.readBoolean()) {
vertices.vertices = readFloatArray(input, verticesLength, scale);
return vertices;
}
var weights : Vector.<Number> = new Vector.<Number>();
var bonesArray : Vector.<int> = new Vector.<int>();
for (var i : int = 0; i < vertexCount; i++) {
var boneCount : int = input.readInt(true);
bonesArray.push(boneCount);
for (var ii : int = 0; ii < boneCount; ii++) {
bonesArray.push(input.readInt(true));
weights.push(input.readFloat() * scale);
weights.push(input.readFloat() * scale);
weights.push(input.readFloat());
}
}
vertices.vertices = weights;
vertices.bones = bonesArray;
return vertices;
}
private function readFloatArray (input: BinaryInput, n: Number, scale: Number): Vector.<Number> {
var i : int = 0;
var array : Vector.<Number> = new Vector.<Number>();
array.length = n;
if (scale == 1) {
for (i = 0; i < n; i++)
array[i] = input.readFloat();
} else {
for (i = 0; i < n; i++)
array[i] = input.readFloat() * scale;
}
return array;
}
private function readShortArray (input: BinaryInput): Vector.<int> {
var n : int = input.readInt(true);
var array : Vector.<int> = new Vector.<int>();
array.length = n;
for (var i : int = 0; i < n; i++)
array[i] = input.readShort();
return array;
}
private function readUnsignedShortArray (input: BinaryInput): Vector.<uint> {
var n : int = input.readInt(true);
var array : Vector.<uint> = new Vector.<uint>();
array.length = n;
for (var i : int = 0; i < n; i++)
array[i] = input.readShort();
return array;
}
private function readAnimation (input: BinaryInput, name: String, skeletonData: SkeletonData): Animation {
var timelines : Vector.<Timeline> = new Vector.<Timeline>();
var scale : Number = this.scale;
var duration : Number = 0;
var tempColor1 : Color = new Color(0, 0, 0, 0);
var tempColor2 : Color = new Color(0, 0, 0, 0);
var i : int = 0, n : int = 0, ii : int = 0, nn : int = 0;
var slotIndex : int;
var timelineType : int;
var frameCount : int;
var frameIndex : int;
var timelineScale : Number;
var index : int;
var time : Number;
// Slot timelines.
for (i = 0, n = input.readInt(true); i < n; i++) {
slotIndex = input.readInt(true);
for (ii = 0, nn = input.readInt(true); ii < nn; ii++) {
timelineType = input.readByte();
frameCount = input.readInt(true);
frameIndex = 0;
switch (timelineType) {
case SkeletonBinary.SLOT_ATTACHMENT: {
var attachmentTimeline : AttachmentTimeline = new AttachmentTimeline(frameCount);
attachmentTimeline.slotIndex = slotIndex;
for (frameIndex = 0; frameIndex < frameCount; frameIndex++)
attachmentTimeline.setFrame(frameIndex, input.readFloat(), input.readStringRef());
timelines.push(attachmentTimeline);
duration = Math.max(duration, attachmentTimeline.frames[frameCount - 1]);
break;
}
case SkeletonBinary.SLOT_COLOR: {
var colorTimeline : ColorTimeline = new ColorTimeline(frameCount);
colorTimeline.slotIndex = slotIndex;
for (frameIndex = 0; frameIndex < frameCount; frameIndex++) {
time = input.readFloat();
tempColor1.setFromRgba8888(input.readInt32());
colorTimeline.setFrame(frameIndex, time, tempColor1.r, tempColor1.g, tempColor1.b, tempColor1.a);
if (frameIndex < frameCount - 1) readCurve(input, frameIndex, colorTimeline);
}
timelines.push(colorTimeline);
duration = Math.max(duration, colorTimeline.frames[(frameCount - 1) * ColorTimeline.ENTRIES]);
break;
}
case SkeletonBinary.SLOT_TWO_COLOR: {
var twoColorTimeline : TwoColorTimeline = new TwoColorTimeline(frameCount);
twoColorTimeline.slotIndex = slotIndex;
for (frameIndex = 0; frameIndex < frameCount; frameIndex++) {
time = input.readFloat();
tempColor1.setFromRgba8888(input.readInt32());
tempColor2.setFromRgb888(input.readInt32());
twoColorTimeline.setFrame(frameIndex, time, tempColor1.r, tempColor1.g, tempColor1.b, tempColor1.a, tempColor2.r,
tempColor2.g, tempColor2.b);
if (frameIndex < frameCount - 1) this.readCurve(input, frameIndex, twoColorTimeline);
}
timelines.push(twoColorTimeline);
duration = Math.max(duration, twoColorTimeline.frames[(frameCount - 1) * TwoColorTimeline.ENTRIES]);
break;
}
}
}
}
// Bone timelines.
for (i = 0, n = input.readInt(true); i < n; i++) {
var boneIndex : int = input.readInt(true);
for (ii = 0, nn = input.readInt(true); ii < nn; ii++) {
timelineType = input.readByte();
frameCount = input.readInt(true);
frameIndex = 0;
switch (timelineType) {
case SkeletonBinary.BONE_ROTATE: {
var rotateTimeline : RotateTimeline = new RotateTimeline(frameCount);
rotateTimeline.boneIndex = boneIndex;
for (frameIndex = 0; frameIndex < frameCount; frameIndex++) {
rotateTimeline.setFrame(frameIndex, input.readFloat(), input.readFloat());
if (frameIndex < frameCount - 1) readCurve(input, frameIndex, rotateTimeline);
}
timelines.push(rotateTimeline);
duration = Math.max(duration, rotateTimeline.frames[(frameCount - 1) * RotateTimeline.ENTRIES]);
break;
}
case SkeletonBinary.BONE_TRANSLATE:
case SkeletonBinary.BONE_SCALE:
case SkeletonBinary.BONE_SHEAR: {
var translateTimeline : TranslateTimeline;
timelineScale = 1;
if (timelineType == SkeletonBinary.BONE_SCALE)
translateTimeline = new ScaleTimeline(frameCount);
else if (timelineType == SkeletonBinary.BONE_SHEAR)
translateTimeline = new ShearTimeline(frameCount);
else {
translateTimeline = new TranslateTimeline(frameCount);
timelineScale = scale;
}
translateTimeline.boneIndex = boneIndex;
for (frameIndex = 0; frameIndex < frameCount; frameIndex++) {
translateTimeline.setFrame(frameIndex, input.readFloat(), input.readFloat() * timelineScale,
input.readFloat() * timelineScale);
if (frameIndex < frameCount - 1) this.readCurve(input, frameIndex, translateTimeline);
}
timelines.push(translateTimeline);
duration = Math.max(duration, translateTimeline.frames[(frameCount - 1) * TranslateTimeline.ENTRIES]);
break;
}
}
}
}
// IK constraint timelines.
for (i = 0, n = input.readInt(true); i < n; i++) {
index = input.readInt(true);
frameCount = input.readInt(true);
var ikConstraintTimeline : IkConstraintTimeline = new IkConstraintTimeline(frameCount);
frameIndex = 0;
ikConstraintTimeline.ikConstraintIndex = index;
for (frameIndex = 0; frameIndex < frameCount; frameIndex++) {
ikConstraintTimeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readByte(), input.readBoolean(),
input.readBoolean());
if (frameIndex < frameCount - 1) this.readCurve(input, frameIndex, ikConstraintTimeline);
}
timelines.push(ikConstraintTimeline);
duration = Math.max(duration, ikConstraintTimeline.frames[(frameCount - 1) * IkConstraintTimeline.ENTRIES]);
}
// Transform constraint timelines.
for (i = 0, n = input.readInt(true); i < n; i++) {
index = input.readInt(true);
frameCount = input.readInt(true);
var transformConstraintTimeline : TransformConstraintTimeline = new TransformConstraintTimeline(frameCount);
transformConstraintTimeline.transformConstraintIndex = index;
for (frameIndex = 0; frameIndex < frameCount; frameIndex++) {
transformConstraintTimeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat(),
input.readFloat());
if (frameIndex < frameCount - 1) this.readCurve(input, frameIndex, transformConstraintTimeline);
}
timelines.push(transformConstraintTimeline);
duration = Math.max(duration, transformConstraintTimeline.frames[(frameCount - 1) * TransformConstraintTimeline.ENTRIES]);
}
// Path constraint timelines.
for (i = 0, n = input.readInt(true); i < n; i++) {
index = input.readInt(true);
var data : PathConstraintData = skeletonData.pathConstraints[index];
for (ii = 0, nn = input.readInt(true); ii < nn; ii++) {
timelineType = input.readByte();
frameCount = input.readInt(true);
switch (timelineType) {
case SkeletonBinary.PATH_POSITION:
case SkeletonBinary.PATH_SPACING: {
var pathConstraintPositionTimeline : PathConstraintPositionTimeline;
timelineScale = 1;
if (timelineType == SkeletonBinary.PATH_SPACING) {
pathConstraintPositionTimeline = new PathConstraintSpacingTimeline(frameCount);
if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) timelineScale = scale;
} else {
pathConstraintPositionTimeline = new PathConstraintPositionTimeline(frameCount);
if (data.positionMode == PositionMode.fixed) timelineScale = scale;
}
pathConstraintPositionTimeline.pathConstraintIndex = index;
for (frameIndex = 0; frameIndex < frameCount; frameIndex++) {
pathConstraintPositionTimeline.setFrame(frameIndex, input.readFloat(), input.readFloat() * timelineScale);
if (frameIndex < frameCount - 1) readCurve(input, frameIndex, pathConstraintPositionTimeline);
}
timelines.push(pathConstraintPositionTimeline);
duration = Math.max(duration, pathConstraintPositionTimeline.frames[(frameCount - 1) * PathConstraintPositionTimeline.ENTRIES]);
break;
}
case SkeletonBinary.PATH_MIX: {
var pathConstraintMixTimeline : PathConstraintMixTimeline = new PathConstraintMixTimeline(frameCount);
pathConstraintMixTimeline.pathConstraintIndex = index;
for (frameIndex = 0; frameIndex < frameCount; frameIndex++) {
pathConstraintMixTimeline.setFrame(frameIndex, input.readFloat(), input.readFloat(), input.readFloat());
if (frameIndex < frameCount - 1) this.readCurve(input, frameIndex, pathConstraintMixTimeline);
}
timelines.push(pathConstraintMixTimeline);
duration = Math.max(duration, pathConstraintMixTimeline.frames[(frameCount - 1) * PathConstraintMixTimeline.ENTRIES]);
break;
}
}
}
}
// Deform timelines.
for (i = 0, n = input.readInt(true); i < n; i++) {
var skin : Skin = skeletonData.skins[input.readInt(true)];
for (ii = 0, nn = input.readInt(true); ii < nn; ii++) {
slotIndex = input.readInt(true);
for (var iii : int = 0, nnn : int = input.readInt(true); iii < nnn; iii++) {
var attachment : VertexAttachment = skin.getAttachment(slotIndex, input.readStringRef()) as VertexAttachment;
var weighted : Boolean = attachment.bones != null;
var vertices : Vector.<Number> = attachment.vertices;
var deformLength : int = weighted ? vertices.length / 3 * 2 : vertices.length;
frameCount = input.readInt(true);
var deformTimeline : DeformTimeline= new DeformTimeline(frameCount);
deformTimeline.slotIndex = slotIndex;
deformTimeline.attachment = attachment;
for (frameIndex = 0; frameIndex < frameCount; frameIndex++) {
time = input.readFloat();
var deform : Vector.<Number>;
var end : int = input.readInt(true);
if (end == 0) {
if (weighted) {
deform = new Vector.<Number>();
deform.length = deformLength;
} else
deform = vertices;
} else {
var v : int, vn: int;
deform = new Vector.<Number>();
deform.length = deformLength;
var start : int = input.readInt(true);
end += start;
if (scale == 1) {
for (v = start; v < end; v++)
deform[v] = input.readFloat();
} else {
for (v = start; v < end; v++)
deform[v] = input.readFloat() * scale;
}
if (!weighted) {
for (v = 0, vn = deform.length; v < vn; v++)
deform[v] += vertices[v];
}
}
deformTimeline.setFrame(frameIndex, time, deform);
if (frameIndex < frameCount - 1) readCurve(input, frameIndex, deformTimeline);
}
timelines.push(deformTimeline);
duration = Math.max(duration, deformTimeline.frames[frameCount - 1]);
}
}
}
// Draw order timeline.
var drawOrderCount : int = input.readInt(true);
if (drawOrderCount > 0) {
var drawOrderTimeline : DrawOrderTimeline = new DrawOrderTimeline(drawOrderCount);
var slotCount : int = skeletonData.slots.length;
for (i = 0; i < drawOrderCount; i++) {
time = input.readFloat();
var offsetCount : int = input.readInt(true);
var drawOrder : Vector.<int> = new Vector.<int>();
drawOrder.length = slotCount;
for (ii = slotCount - 1; ii >= 0; ii--)
drawOrder[ii] = -1;
var unchanged : Vector.<int> = new Vector.<int>();
unchanged.length = slotCount - offsetCount;
var originalIndex : int = 0, unchangedIndex : int = 0;
for (ii = 0; ii < offsetCount; ii++) {
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.
for (ii = slotCount - 1; ii >= 0; ii--)
if (drawOrder[ii] == -1) drawOrder[ii] = unchanged[--unchangedIndex];
drawOrderTimeline.setFrame(i, time, drawOrder);
}
timelines.push(drawOrderTimeline);
duration = Math.max(duration, drawOrderTimeline.frames[drawOrderCount - 1]);
}
// Event timeline.
var eventCount : int = input.readInt(true);
if (eventCount > 0) {
var eventTimeline : EventTimeline = new EventTimeline(eventCount);
for (i = 0; i < eventCount; i++) {
time = input.readFloat();
var eventData : EventData = skeletonData.events[input.readInt(true)];
var event : Event = new Event(time, eventData);
event.intValue = input.readInt(false);
event.floatValue = input.readFloat();
event.stringValue = input.readBoolean() ? input.readString() : eventData.stringValue;
if (event.data.audioPath != null) {
event.volume = input.readFloat();
event.balance = input.readFloat();
}
eventTimeline.setFrame(i, event);
}
timelines.push(eventTimeline);
duration = Math.max(duration, eventTimeline.frames[eventCount - 1]);
}
return new Animation(name, timelines, duration);
}
private function readCurve (input: BinaryInput, frameIndex: Number, timeline: CurveTimeline) : void {
switch (input.readByte()) {
case SkeletonBinary.CURVE_STEPPED:
timeline.setStepped(frameIndex);
break;
case SkeletonBinary.CURVE_BEZIER:
setCurve(timeline, frameIndex, input.readFloat(), input.readFloat(), input.readFloat(), input.readFloat());
break;
}
}
public function setCurve (timeline: CurveTimeline, frameIndex: Number, cx1: Number, cy1: Number, cx2: Number, cy2: Number) : void {
timeline.setCurve(frameIndex, cx1, cy1, cx2, cy2);
}
}
}
import spine.attachments.MeshAttachment;
class Vertices {
public var vertices : Vector.<Number> = new Vector.<Number>();
public var bones : Vector.<int> = new Vector.<int>();
}
class LinkedMesh {
internal var parent : String, skin : String;
internal var slotIndex : int;
internal var mesh : MeshAttachment;
internal var inheritDeform : Boolean;
public function LinkedMesh(mesh : MeshAttachment, skin : String, slotIndex : int, parent : String, inheritDeform : Boolean) {
this.mesh = mesh;
this.skin = skin;
this.slotIndex = slotIndex;
this.parent = parent;
this.inheritDeform = inheritDeform;
}
}

View File

@ -46,6 +46,7 @@ package spine {
public var version : String, hash : String;
public var fps : Number;
public var imagesPath : String;
public var audioPath : String;
public function SkeletonData() {
}

View File

@ -32,5 +32,7 @@ package spine {
public static const length : SpacingMode = new SpacingMode();
public static const fixed : SpacingMode = new SpacingMode();
public static const percent : SpacingMode = new SpacingMode();
public static const values : Array = [ length, fixed, percent ];
}
}

View File

@ -34,5 +34,7 @@ package spine {
public static const noRotationOrReflection : TransformMode = new TransformMode();
public static const noScale : TransformMode = new TransformMode();
public static const noScaleOrReflection : TransformMode = new TransformMode();
public static const values : Array = [ normal, onlyTranslation, noRotationOrReflection, noScale, noScaleOrReflection ];
}
}

View File

@ -39,6 +39,8 @@ package spine.attachments {
public static const clipping : AttachmentType = new AttachmentType(6, "clipping");
public var ordinal : int;
public var name : String;
public static const values : Array = [ region, boundingbox, mesh, linkedmesh, path, point, clipping ];
public function AttachmentType(ordinal : int, name : String) {
this.ordinal = ordinal;

View File

@ -28,7 +28,11 @@
*****************************************************************************/
package spine.attachments {
import spine.Color;
public dynamic class BoundingBoxAttachment extends VertexAttachment {
public var color : Color = new Color(0, 0, 0, 0);
public function BoundingBoxAttachment(name : String) {
super(name);
}

View File

@ -28,9 +28,11 @@
*****************************************************************************/
package spine.attachments {
import spine.Color;
public dynamic class PathAttachment extends VertexAttachment {
public var lengths : Vector.<Number>;
public var closed : Boolean, constantSpeed : Boolean;
public var color : Color = new Color(0, 0, 0, 0);
public function PathAttachment(name : String) {
super(name);

View File

@ -28,6 +28,7 @@
*****************************************************************************/
package spine.examples {
import spine.SkeletonBinary;
import spine.Skin;
import starling.display.DisplayObjectContainer;
import starling.events.Touch;
@ -45,7 +46,7 @@ package spine.examples {
import spine.starling.SkeletonAnimation;
public class MixAndMatchExample extends Sprite {
[Embed(source = "/mix-and-match-pro.json", mimeType = "application/octet-stream")]
[Embed(source = "/mix-and-match-pro.skel", mimeType = "application/octet-stream")]
static public const MixAndMatchJson : Class;
[Embed(source = "/mix-and-match.atlas", mimeType = "application/octet-stream")]
@ -60,9 +61,9 @@ package spine.examples {
var spineAtlas : Atlas = new Atlas(new MixAndMatchAtlas(), new StarlingTextureLoader(new MixAndMatchAtlasTexture()));
attachmentLoader = new AtlasAttachmentLoader(spineAtlas);
var json : SkeletonJson = new SkeletonJson(attachmentLoader);
json.scale = 0.5;
var skeletonData : SkeletonData = json.readSkeletonData(new MixAndMatchJson());
var binary : SkeletonBinary = new SkeletonBinary(attachmentLoader);
binary.scale = 0.5;
var skeletonData : SkeletonData = binary.readSkeletonData(new MixAndMatchJson());
this.x = 400;
this.y = 500;