[haxe] Formatting

This commit is contained in:
Mario Zechner 2025-07-16 01:34:53 +02:00
parent ab64434ae7
commit 9fcc5a8b8c
173 changed files with 1591 additions and 1238 deletions

View File

@ -5,11 +5,10 @@ set -e
echo "Formatting Haxe files..." echo "Formatting Haxe files..."
if command -v haxelib &> /dev/null && haxelib list formatter &> /dev/null; then if command -v haxelib &> /dev/null && haxelib list formatter &> /dev/null; then
find .. -name "*.hx" \ # Format spine-haxe directory
-not -path "*/.*" \ if [ -d ../spine-haxe ]; then
-not -path "*/node_modules/*" \ haxelib run formatter -s ../spine-haxe
-not -path "*/build/*" \ fi
| xargs haxelib run formatter -s
else else
echo "Warning: haxe formatter not found. Install with: haxelib install formatter" echo "Warning: haxe formatter not found. Install with: haxelib install formatter"
fi fi

View File

@ -32,9 +32,9 @@ show_help() {
echo "" echo ""
echo "Tools used:" echo "Tools used:"
echo " Java: Spotless with Eclipse formatter" echo " Java: Spotless with Eclipse formatter"
echo " TypeScript: Biome" echo " TypeScript: tsfmt (typescript-formatter)"
echo " C/C++: clang-format" echo " C/C++: clang-format"
echo " C#: dotnet-format" echo " C#: dotnet format"
echo " Haxe: haxe formatter" echo " Haxe: haxe formatter"
echo " Dart: dart format" echo " Dart: dart format"
echo " Swift: swift-format" echo " Swift: swift-format"

View File

@ -35,12 +35,10 @@ import starlingExamples.Scene.SceneManager;
import starling.core.Starling; import starling.core.Starling;
import flixel.FlxG; import flixel.FlxG;
import flixel.FlxGame; import flixel.FlxGame;
import openfl.display.Sprite; import openfl.display.Sprite;
import openfl.text.TextField; import openfl.text.TextField;
import openfl.text.TextFormat; import openfl.text.TextFormat;
import openfl.events.MouseEvent; import openfl.events.MouseEvent;
import openfl.geom.Rectangle; import openfl.geom.Rectangle;
import starling.events.Event; import starling.events.Event;
@ -157,6 +155,7 @@ class Main extends Sprite {
} }
private var starlingSingleton:Starling; private var starlingSingleton:Starling;
private function onStarlingClick(e:MouseEvent):Void { private function onStarlingClick(e:MouseEvent):Void {
trace("Launching Starling game"); trace("Launching Starling game");
starlingSingleton = new Starling(starling.display.Sprite, stage, new Rectangle(0, 0, 800, 600)); starlingSingleton = new Starling(starling.display.Sprite, stage, new Rectangle(0, 0, 800, 600));

View File

@ -34,10 +34,8 @@ import flixel.FlxG;
import flixel.FlxGame; import flixel.FlxGame;
import openfl.display.Sprite; import openfl.display.Sprite;
class MainFlixel extends Sprite class MainFlixel extends Sprite {
{ public function new() {
public function new()
{
super(); super();
addChild(new FlxGame(640, 480, FlixelState)); addChild(new FlxGame(640, 480, FlixelState));
FlxG.autoPause = false; FlxG.autoPause = false;

View File

@ -29,7 +29,6 @@
package flixelExamples; package flixelExamples;
import flixel.util.FlxColor; import flixel.util.FlxColor;
import flixel.text.FlxText; import flixel.text.FlxText;
import spine.Skin; import spine.Skin;

View File

@ -43,6 +43,7 @@ class BasicExample extends FlxState {
var loadBinary = true; var loadBinary = true;
var skeletonSprite:SkeletonSprite; var skeletonSprite:SkeletonSprite;
override public function create():Void { override public function create():Void {
FlxG.cameras.bgColor = 0xffa1b2b0; FlxG.cameras.bgColor = 0xffa1b2b0;
@ -66,8 +67,7 @@ class BasicExample extends FlxState {
trace("loaded"); trace("loaded");
} }
override public function update(elapsed:Float):Void override public function update(elapsed:Float):Void {
{
if (FlxG.keys.anyPressed([RIGHT])) { if (FlxG.keys.anyPressed([RIGHT])) {
skeletonSprite.x += 15; skeletonSprite.x += 15;
} }
@ -83,5 +83,4 @@ class BasicExample extends FlxState {
super.update(elapsed); super.update(elapsed);
} }
} }

View File

@ -29,7 +29,6 @@
package flixelExamples; package flixelExamples;
import flixel.text.FlxText; import flixel.text.FlxText;
import flixel.math.FlxPoint; import flixel.math.FlxPoint;
import spine.Skin; import spine.Skin;
@ -47,6 +46,7 @@ class CelestialCircusExample extends FlxState {
var loadBinary = true; var loadBinary = true;
var skeletonSprite:SkeletonSprite; var skeletonSprite:SkeletonSprite;
override public function create():Void { override public function create():Void {
FlxG.cameras.bgColor = 0xffa1b2b0; FlxG.cameras.bgColor = 0xffa1b2b0;
@ -55,7 +55,8 @@ class CelestialCircusExample extends FlxState {
add(button); add(button);
var atlas = new TextureAtlas(Assets.getText("assets/celestial-circus.atlas"), new FlixelTextureLoader("assets/celestial-circus.atlas")); var atlas = new TextureAtlas(Assets.getText("assets/celestial-circus.atlas"), new FlixelTextureLoader("assets/celestial-circus.atlas"));
var data = SkeletonData.from(loadBinary ? Assets.getBytes("assets/celestial-circus-pro.skel") : Assets.getText("assets/celestial-circus-pro.json"), atlas, .15); var data = SkeletonData.from(loadBinary ? Assets.getBytes("assets/celestial-circus-pro.skel") : Assets.getText("assets/celestial-circus-pro.json"),
atlas, .15);
var animationStateData = new AnimationStateData(data); var animationStateData = new AnimationStateData(data);
animationStateData.defaultMix = 0.25; animationStateData.defaultMix = 0.25;
@ -73,32 +74,27 @@ class CelestialCircusExample extends FlxState {
var dragging:Bool = false; var dragging:Bool = false;
var lastX:Float = 0; var lastX:Float = 0;
var lastY:Float = 0; var lastY:Float = 0;
override public function update(elapsed:Float):Void
{ override public function update(elapsed:Float):Void {
super.update(elapsed); super.update(elapsed);
mousePosition = FlxG.mouse.getPosition(); mousePosition = FlxG.mouse.getPosition();
if (FlxG.mouse.justPressed && skeletonSprite.overlapsPoint(mousePosition)) if (FlxG.mouse.justPressed && skeletonSprite.overlapsPoint(mousePosition)) {
{
dragging = true; dragging = true;
lastX = mousePosition.x; lastX = mousePosition.x;
lastY = mousePosition.y; lastY = mousePosition.y;
} }
if (FlxG.mouse.justReleased) dragging = false; if (FlxG.mouse.justReleased)
dragging = false;
if (dragging) if (dragging) {
{
skeletonSprite.x += mousePosition.x - lastX; skeletonSprite.x += mousePosition.x - lastX;
skeletonSprite.y += mousePosition.y - lastY; skeletonSprite.y += mousePosition.y - lastY;
skeletonSprite.skeleton.physicsTranslate( skeletonSprite.skeleton.physicsTranslate(mousePosition.x - lastX, mousePosition.y - lastY,);
mousePosition.x - lastX,
mousePosition.y - lastY,
);
lastX = mousePosition.x; lastX = mousePosition.x;
lastY = mousePosition.y; lastY = mousePosition.y;
} }
} }
} }

View File

@ -29,7 +29,6 @@
package flixelExamples; package flixelExamples;
import spine.Skin; import spine.Skin;
import flixel.ui.FlxButton; import flixel.ui.FlxButton;
import flixel.FlxG; import flixel.FlxG;

View File

@ -29,7 +29,6 @@
package flixelExamples; package flixelExamples;
import flixel.util.FlxSave; import flixel.util.FlxSave;
import flixel.math.FlxPoint; import flixel.math.FlxPoint;
import flixel.util.FlxColor; import flixel.util.FlxColor;
@ -50,6 +49,7 @@ class ControlBonesExample extends FlxState {
private var controlBones = []; private var controlBones = [];
private var controls:Array<FlxSprite> = []; private var controls:Array<FlxSprite> = [];
override public function create():Void { override public function create():Void {
FlxG.cameras.bgColor = 0xffa1b2b0; FlxG.cameras.bgColor = 0xffa1b2b0;
@ -111,25 +111,24 @@ class ControlBonesExample extends FlxState {
var offsetX:Float = 0; var offsetX:Float = 0;
var offsetY:Float = 0; var offsetY:Float = 0;
var sprite:FlxSprite; var sprite:FlxSprite;
override public function update(elapsed:Float):Void
{ override public function update(elapsed:Float):Void {
super.update(elapsed); super.update(elapsed);
mousePosition = FlxG.mouse.getPosition(); mousePosition = FlxG.mouse.getPosition();
for (control in controls) { for (control in controls) {
if (FlxG.mouse.justPressed && control.overlapsPoint(mousePosition)) if (FlxG.mouse.justPressed && control.overlapsPoint(mousePosition)) {
{
sprite = control; sprite = control;
offsetX = mousePosition.x - sprite.x; offsetX = mousePosition.x - sprite.x;
offsetY = mousePosition.y - sprite.y; offsetY = mousePosition.y - sprite.y;
} }
} }
if (FlxG.mouse.justReleased) sprite = null; if (FlxG.mouse.justReleased)
sprite = null;
if (sprite != null) if (sprite != null) {
{
sprite.x = mousePosition.x - offsetX; sprite.x = mousePosition.x - offsetX;
sprite.y = mousePosition.y - offsetY; sprite.y = mousePosition.y - offsetY;
} }

View File

@ -29,7 +29,6 @@
package flixelExamples; package flixelExamples;
import flixel.text.FlxText; import flixel.text.FlxText;
import flixel.ui.FlxButton; import flixel.ui.FlxButton;
import flixel.FlxG; import flixel.FlxG;
@ -76,9 +75,7 @@ class EventsExample extends FlxState {
skeletonSprite.skeleton.setupPoseBones(); skeletonSprite.skeleton.setupPoseBones();
add(skeletonSprite); add(skeletonSprite);
trackEntry.onEvent.add( trackEntry.onEvent.add((entry, event) -> log('Custom event for ${entry.animation.name}: ${event.data.name}'));
(entry, event) -> log('Custom event for ${entry.animation.name}: ${event.data.name}'));
add(textContainer); add(textContainer);
super.create(); super.create();
@ -88,6 +85,7 @@ class EventsExample extends FlxState {
private var logs = new Array<FlxText>(); private var logs = new Array<FlxText>();
private var logsNumber = 0; private var logsNumber = 0;
private var yOffset = 12; private var yOffset = 12;
private function log(text:String) { private function log(text:String) {
var length = logs.length; var length = logs.length;
var newLog = new FlxText(250, 30, text); var newLog = new FlxText(250, 30, text);

View File

@ -43,8 +43,7 @@ import flixel.FlxG;
import flixel.FlxState; import flixel.FlxState;
import flixel.text.FlxText; import flixel.text.FlxText;
class FlixelState extends FlxState class FlixelState extends FlxState {
{
var spineSprite:SkeletonSprite; var spineSprite:SkeletonSprite;
var sprite:FlxSprite; var sprite:FlxSprite;
var sprite2:FlxSprite; var sprite2:FlxSprite;
@ -57,8 +56,7 @@ class FlixelState extends FlxState
var scale = 4; var scale = 4;
var speed:Float; var speed:Float;
override public function create():Void override public function create():Void {
{
FlxG.cameras.bgColor = 0xffa1b2b0; FlxG.cameras.bgColor = 0xffa1b2b0;
// setting speed of spineboy (450 is the speed to not let him slide) // setting speed of spineboy (450 is the speed to not let him slide)
@ -166,8 +164,8 @@ class FlixelState extends FlxState
} }
var justSetIdle = true; var justSetIdle = true;
override public function update(elapsed:Float):Void
{ override public function update(elapsed:Float):Void {
if (FlxG.overlap(spineSprite, group)) { if (FlxG.overlap(spineSprite, group)) {
myText.text = "Overlapping"; myText.text = "Overlapping";
} else { } else {
@ -191,11 +189,13 @@ class FlixelState extends FlxState
var flipped = false; var flipped = false;
var deltaX; var deltaX;
if (FlxG.keys.anyPressed([RIGHT])) { if (FlxG.keys.anyPressed([RIGHT])) {
if (spineSprite.flipX == true) flipped = true; if (spineSprite.flipX == true)
flipped = true;
spineSprite.flipX = false; spineSprite.flipX = false;
} }
if (FlxG.keys.anyPressed([LEFT])) { if (FlxG.keys.anyPressed([LEFT])) {
if (spineSprite.flipX == false) flipped = true; if (spineSprite.flipX == false)
flipped = true;
spineSprite.flipX = true; spineSprite.flipX = true;
} }
@ -211,14 +211,12 @@ class FlixelState extends FlxState
spineSprite.state.setAnimationByName(0, "walk", true); spineSprite.state.setAnimationByName(0, "walk", true);
} }
} }
} else if (!jumping && !justSetIdle) { } else if (!jumping && !justSetIdle) {
justSetWalking = false; justSetWalking = false;
justSetIdle = true; justSetIdle = true;
spineSprite.state.setAnimationByName(0, "idle", true); spineSprite.state.setAnimationByName(0, "idle", true);
} }
super.update(elapsed); super.update(elapsed);
} }
} }

View File

@ -29,7 +29,6 @@
package flixelExamples; package flixelExamples;
import spine.Skin; import spine.Skin;
import flixel.ui.FlxButton; import flixel.ui.FlxButton;
import flixel.FlxG; import flixel.FlxG;
@ -43,9 +42,10 @@ import spine.atlas.TextureAtlas;
class MixAndMatchExample extends FlxState { class MixAndMatchExample extends FlxState {
var loadBinary = false; var loadBinary = false;
// var loadBinary = true;
// var loadBinary = true;
var skeletonSprite:SkeletonSprite; var skeletonSprite:SkeletonSprite;
override public function create():Void { override public function create():Void {
FlxG.cameras.bgColor = 0xffa1b2b0; FlxG.cameras.bgColor = 0xffa1b2b0;
@ -54,7 +54,8 @@ class MixAndMatchExample extends FlxState {
add(button); add(button);
var atlas = new TextureAtlas(Assets.getText("assets/mix-and-match.atlas"), new FlixelTextureLoader("assets/mix-and-match.atlas")); var atlas = new TextureAtlas(Assets.getText("assets/mix-and-match.atlas"), new FlixelTextureLoader("assets/mix-and-match.atlas"));
var data = SkeletonData.from(loadBinary ? Assets.getBytes("assets/mix-and-match-pro.skel") : Assets.getText("assets/mix-and-match-pro.json"), atlas, .5); var data = SkeletonData.from(loadBinary ? Assets.getBytes("assets/mix-and-match-pro.skel") : Assets.getText("assets/mix-and-match-pro.json"), atlas,
.5);
var animationStateData = new AnimationStateData(data); var animationStateData = new AnimationStateData(data);
animationStateData.defaultMix = 0.25; animationStateData.defaultMix = 0.25;
@ -80,5 +81,4 @@ class MixAndMatchExample extends FlxState {
super.create(); super.create();
} }
} }

View File

@ -29,7 +29,6 @@
package flixelExamples; package flixelExamples;
import spine.Skin; import spine.Skin;
import flixel.ui.FlxButton; import flixel.ui.FlxButton;
import flixel.FlxG; import flixel.FlxG;

View File

@ -29,7 +29,6 @@
package flixelExamples; package flixelExamples;
import flixel.ui.FlxButton; import flixel.ui.FlxButton;
import flixel.FlxG; import flixel.FlxG;
import spine.flixel.SkeletonSprite; import spine.flixel.SkeletonSprite;
@ -44,6 +43,7 @@ class SequenceExample extends FlxState {
var loadBinary = true; var loadBinary = true;
var skeletonSprite:SkeletonSprite; var skeletonSprite:SkeletonSprite;
override public function create():Void { override public function create():Void {
FlxG.cameras.bgColor = 0xffa1b2b0; FlxG.cameras.bgColor = 0xffa1b2b0;
@ -64,5 +64,4 @@ class SequenceExample extends FlxState {
add(skeletonSprite); add(skeletonSprite);
super.create(); super.create();
} }
} }

View File

@ -29,7 +29,6 @@
package flixelExamples; package flixelExamples;
import spine.Skin; import spine.Skin;
import flixel.ui.FlxButton; import flixel.ui.FlxButton;
import flixel.FlxG; import flixel.FlxG;

View File

@ -29,7 +29,6 @@
package flixelExamples; package flixelExamples;
import spine.Skin; import spine.Skin;
import flixel.ui.FlxButton; import flixel.ui.FlxButton;
import flixel.FlxG; import flixel.FlxG;

View File

@ -29,7 +29,6 @@
package flixelExamples; package flixelExamples;
import spine.Skin; import spine.Skin;
import flixel.ui.FlxButton; import flixel.ui.FlxButton;
import flixel.FlxG; import flixel.FlxG;

View File

@ -46,6 +46,7 @@ class AnimationBoundExample extends Scene {
var loadBinary = false; var loadBinary = false;
var skeletonSpriteClipping:SkeletonSprite; var skeletonSpriteClipping:SkeletonSprite;
var skeletonSpriteNoClipping:SkeletonSprite; var skeletonSpriteNoClipping:SkeletonSprite;
public function load():Void { public function load():Void {
background.color = 0x333333; background.color = 0x333333;
var scale = .2; var scale = .2;

View File

@ -52,7 +52,8 @@ class CelestialCircusExample extends Scene {
background.color = 0x333333; background.color = 0x333333;
var atlas = new TextureAtlas(Assets.getText("assets/celestial-circus.atlas"), new StarlingTextureLoader("assets/celestial-circus.atlas")); var atlas = new TextureAtlas(Assets.getText("assets/celestial-circus.atlas"), new StarlingTextureLoader("assets/celestial-circus.atlas"));
var skeletondata = SkeletonData.from(loadBinary ? Assets.getBytes("assets/celestial-circus-pro.skel") : Assets.getText("assets/celestial-circus-pro.json"), atlas); var skeletondata = SkeletonData.from(loadBinary ? Assets.getBytes("assets/celestial-circus-pro.skel") : Assets.getText("assets/celestial-circus-pro.json"),
atlas);
var animationStateData = new AnimationStateData(skeletondata); var animationStateData = new AnimationStateData(skeletondata);
animationStateData.defaultMix = 0.25; animationStateData.defaultMix = 0.25;
@ -83,10 +84,7 @@ class CelestialCircusExample extends Scene {
skeletonTouch.getMovement(this, movement); skeletonTouch.getMovement(this, movement);
skeletonSprite.x += movement.x; skeletonSprite.x += movement.x;
skeletonSprite.y += movement.y; skeletonSprite.y += movement.y;
skeletonSprite.skeleton.physicsTranslate( skeletonSprite.skeleton.physicsTranslate(movement.x / skeletonSprite.scale, movement.y / skeletonSprite.scale,);
movement.x / skeletonSprite.scale,
movement.y / skeletonSprite.scale,
);
} }
} else { } else {
var sceneTouch = e.getTouch(this); var sceneTouch = e.getTouch(this);
@ -94,8 +92,5 @@ class CelestialCircusExample extends Scene {
SceneManager.getInstance().switchScene(new SnowglobeExample()); SceneManager.getInstance().switchScene(new SnowglobeExample());
} }
} }
} }
} }

View File

@ -58,7 +58,6 @@ class CloudPotExample extends Scene {
skeletonSprite.skeleton.updateWorldTransform(Physics.update); skeletonSprite.skeleton.updateWorldTransform(Physics.update);
var bounds = skeletonSprite.skeleton.getBounds(); var bounds = skeletonSprite.skeleton.getBounds();
skeletonSprite.scale = 0.2; skeletonSprite.scale = 0.2;
skeletonSprite.x = Starling.current.stage.stageWidth / 2; skeletonSprite.x = Starling.current.stage.stageWidth / 2;
skeletonSprite.y = Starling.current.stage.stageHeight / 2; skeletonSprite.y = Starling.current.stage.stageHeight / 2;

View File

@ -52,7 +52,8 @@ class ControlBonesExample extends Scene {
public function load():Void { public function load():Void {
var atlas = new TextureAtlas(Assets.getText("assets/stretchyman.atlas"), new StarlingTextureLoader("assets/stretchyman.atlas")); var atlas = new TextureAtlas(Assets.getText("assets/stretchyman.atlas"), new StarlingTextureLoader("assets/stretchyman.atlas"));
var skeletondata = SkeletonData.from(loadBinary ? Assets.getBytes("assets/stretchyman-pro.skel") : Assets.getText("assets/stretchyman-pro.json"), atlas); var skeletondata = SkeletonData.from(loadBinary ? Assets.getBytes("assets/stretchyman-pro.skel") : Assets.getText("assets/stretchyman-pro.json"),
atlas);
var animationStateData = new AnimationStateData(skeletondata); var animationStateData = new AnimationStateData(skeletondata);
animationStateData.defaultMix = 0.25; animationStateData.defaultMix = 0.25;

View File

@ -66,8 +66,7 @@ class EventsExample extends Scene {
// add callback to the TrackEntry // add callback to the TrackEntry
skeletonSprite.state.setAnimationByName(0, "walk", true); skeletonSprite.state.setAnimationByName(0, "walk", true);
var trackEntry = skeletonSprite.state.addAnimationByName(0, "run", true, 3); var trackEntry = skeletonSprite.state.addAnimationByName(0, "run", true, 3);
trackEntry.onEvent.add( trackEntry.onEvent.add((entry, event) -> log('Custom event for ${entry.animation.name}: ${event.data.name}'));
(entry, event) -> log('Custom event for ${entry.animation.name}: ${event.data.name}'));
addChild(skeletonSprite); addChild(skeletonSprite);
juggler.add(skeletonSprite); juggler.add(skeletonSprite);
@ -83,6 +82,7 @@ class EventsExample extends Scene {
private var logs = new Array<TextField>(); private var logs = new Array<TextField>();
private var logsNumber = 0; private var logsNumber = 0;
private var yOffset = 12; private var yOffset = 12;
private function log(text:String) { private function log(text:String) {
var length = logs.length; var length = logs.length;
var newLog = new TextField(250, 30, text); var newLog = new TextField(250, 30, text);

View File

@ -57,7 +57,6 @@ class SnowglobeExample extends Scene {
skeletonSprite.skeleton.updateWorldTransform(Physics.update); skeletonSprite.skeleton.updateWorldTransform(Physics.update);
var bounds = skeletonSprite.skeleton.getBounds(); var bounds = skeletonSprite.skeleton.getBounds();
skeletonSprite.scale = 0.15; skeletonSprite.scale = 0.15;
skeletonSprite.x = Starling.current.stage.stageWidth / 2; skeletonSprite.x = Starling.current.stage.stageWidth / 2;
skeletonSprite.y = Starling.current.stage.stageHeight / 1.5; skeletonSprite.y = Starling.current.stage.stageHeight / 1.5;

View File

@ -37,6 +37,7 @@ package spine;
class Bone extends PosedActive<BoneData, BoneLocal, BonePose> { class Bone extends PosedActive<BoneData, BoneLocal, BonePose> {
static public var yDown:Bool = false; static public var yDown:Bool = false;
static public var yDir(get, never):Int; static public var yDir(get, never):Int;
static private function get_yDir():Int { static private function get_yDir():Int {
return Bone.yDown ? -1 : 1; return Bone.yDown ? -1 : 1;
} }

View File

@ -31,7 +31,6 @@ package spine;
/** The setup pose for a bone. */ /** The setup pose for a bone. */
class BoneData extends PosedData<BoneLocal> { class BoneData extends PosedData<BoneLocal> {
/** The index of the bone in spine.Skeleton.getBones(). */ /** The index of the bone in spine.Skeleton.getBones(). */
public final index:Int; public final index:Int;
@ -41,6 +40,7 @@ class BoneData extends PosedData<BoneLocal> {
public var length = 0.; public var length = 0.;
// Nonessential. // Nonessential.
/** The color of the bone as it was in Spine, or a default color if nonessential data was not exported. Bones are not usually /** The color of the bone as it was in Spine, or a default color if nonessential data was not exported. Bones are not usually
* rendered at runtime. */ * rendered at runtime. */
public var color = new Color(0, 0, 0, 0); public var color = new Color(0, 0, 0, 0);
@ -53,8 +53,10 @@ class BoneData extends PosedData<BoneLocal> {
public function new(index:Int, name:String, parent:BoneData) { public function new(index:Int, name:String, parent:BoneData) {
super(name, new BoneLocal()); super(name, new BoneLocal());
if (index < 0) throw new SpineException("index must be >= 0."); if (index < 0)
if (name == null) throw new SpineException("name cannot be null."); throw new SpineException("index must be >= 0.");
if (name == null)
throw new SpineException("name cannot be null.");
this.index = index; this.index = index;
this.parent = parent; this.parent = parent;
} }

View File

@ -31,7 +31,6 @@ package spine;
/** Stores a bone's local pose. */ /** Stores a bone's local pose. */
class BoneLocal implements Pose<BoneLocal> { class BoneLocal implements Pose<BoneLocal> {
/** The local x translation. */ /** The local x translation. */
public var x:Float = 0; public var x:Float = 0;
@ -55,17 +54,19 @@ class BoneLocal implements Pose<BoneLocal> {
/** Determines how parent world transforms affect this bone. */ /** Determines how parent world transforms affect this bone. */
public var inherit(default, set):Inherit; public var inherit(default, set):Inherit;
function set_inherit(value:Inherit):Inherit { function set_inherit(value:Inherit):Inherit {
if (value == null) throw new SpineException("inherit cannot be null."); if (value == null)
throw new SpineException("inherit cannot be null.");
inherit = value; inherit = value;
return value; return value;
} }
public function new () { public function new() {}
}
public function set(pose:BoneLocal):Void { public function set(pose:BoneLocal):Void {
if (pose == null) throw new SpineException("pose cannot be null."); if (pose == null)
throw new SpineException("pose cannot be null.");
x = pose.x; x = pose.x;
y = pose.y; y = pose.y;
rotation = pose.rotation; rotation = pose.rotation;
@ -75,5 +76,4 @@ class BoneLocal implements Pose<BoneLocal> {
shearY = pose.shearY; shearY = pose.shearY;
inherit = pose.inherit; inherit = pose.inherit;
} }
} }

View File

@ -32,7 +32,6 @@ package spine;
/** The applied pose for a bone. This is the {@link Bone} pose with constraints applied and the world transform computed by /** The applied pose for a bone. This is the {@link Bone} pose with constraints applied and the world transform computed by
* Skeleton.updateWorldTransform(Physics). */ * Skeleton.updateWorldTransform(Physics). */
class BonePose extends BoneLocal implements Update { class BonePose extends BoneLocal implements Update {
public var bone:Bone; public var bone:Bone;
/** Part of the world transform matrix for the X axis. If changed, updateAppliedTransform() should be called. */ /** Part of the world transform matrix for the X axis. If changed, updateAppliedTransform() should be called. */
@ -62,7 +61,8 @@ class BonePose extends BoneLocal implements Update {
/** Called by Skeleton.updateCache() to compute the world transform, if needed. */ /** Called by Skeleton.updateCache() to compute the world transform, if needed. */
public function update(skeleton:Skeleton, physics:Physics):Void { public function update(skeleton:Skeleton, physics:Physics):Void {
if (world != skeleton._update) updateWorldTransform(skeleton); if (world != skeleton._update)
updateWorldTransform(skeleton);
} }
/** Computes the world transform using the parent bone's applied pose and this pose. Child bones are not updated. /** Computes the world transform using the parent bone's applied pose and this pose. Child bones are not updated.
@ -139,15 +139,19 @@ class BonePose extends BoneLocal implements Update {
c = pc * la + pd * lc; c = pc * la + pd * lc;
d = pc * lb + pd * ld; d = pc * lb + pd * ld;
case Inherit.noScale, Inherit.noScaleOrReflection: case Inherit.noScale, Inherit.noScaleOrReflection:
var r = rotation * MathUtils.degRad, cos = Math.cos(r), sin = Math.sin(r); var r = rotation * MathUtils.degRad,
cos = Math.cos(r),
sin = Math.sin(r);
var za = (pa * cos + pb * sin) / skeleton.scaleX; var za = (pa * cos + pb * sin) / skeleton.scaleX;
var zc = (pc * cos + pd * sin) / skeleton.scaleY; var zc = (pc * cos + pd * sin) / skeleton.scaleY;
var s = Math.sqrt(za * za + zc * zc); var s = Math.sqrt(za * za + zc * zc);
if (s > 0.00001) s = 1 / s; if (s > 0.00001)
s = 1 / s;
za *= s; za *= s;
zc *= s; zc *= s;
s = Math.sqrt(za * za + zc * zc); s = Math.sqrt(za * za + zc * zc);
if (inherit == Inherit.noScale && ((pa * pd - pb * pc < 0) != ((skeleton.scaleX < 0) != (skeleton.scaleY < 0)))) s = -s; if (inherit == Inherit.noScale && ((pa * pd - pb * pc < 0) != ((skeleton.scaleX < 0) != (skeleton.scaleY < 0))))
s = -s;
r = Math.PI / 2 + Math.atan2(zc, za); r = Math.PI / 2 + Math.atan2(zc, za);
var zb:Float = Math.cos(r) * s; var zb:Float = Math.cos(r) * s;
var zd:Float = Math.sin(r) * s; var zd:Float = Math.sin(r) * s;
@ -215,15 +219,19 @@ class BonePose extends BoneLocal implements Update {
ia = pd * pid; ia = pd * pid;
ib = pb * pid; ib = pb * pid;
case Inherit.noScale, Inherit.noScaleOrReflection: case Inherit.noScale, Inherit.noScaleOrReflection:
var r = rotation * MathUtils.degRad, cos = Math.cos(rotation), sin = Math.sin(rotation); var r = rotation * MathUtils.degRad,
cos = Math.cos(rotation),
sin = Math.sin(rotation);
pa = (pa * cos + pb * sin) / skeleton.scaleX; pa = (pa * cos + pb * sin) / skeleton.scaleX;
pc = (pc * cos + pd * sin) / skeleton.scaleY; pc = (pc * cos + pd * sin) / skeleton.scaleY;
var s = Math.sqrt(pa * pa + pc * pc); var s = Math.sqrt(pa * pa + pc * pc);
if (s > 0.00001) s = 1 / s; if (s > 0.00001)
s = 1 / s;
pa *= s; pa *= s;
pc *= s; pc *= s;
s = Math.sqrt(pa * pa + pc * pc); s = Math.sqrt(pa * pa + pc * pc);
if (inherit == Inherit.noScale && (pid < 0 != ((skeleton.scaleX < 0) != (skeleton.scaleY < 0)))) s = -s; if (inherit == Inherit.noScale && (pid < 0 != ((skeleton.scaleX < 0) != (skeleton.scaleY < 0))))
s = -s;
r = MathUtils.PI / 2 + Math.atan2(pc, pa); r = MathUtils.PI / 2 + Math.atan2(pc, pa);
pb = Math.cos(r) * s; pb = Math.cos(r) * s;
pd = Math.sin(r) * s; pd = Math.sin(r) * s;
@ -257,11 +265,13 @@ class BonePose extends BoneLocal implements Update {
/** If the world transform has been modified and the local transform no longer matches, {@link #updateLocalTransform(Skeleton)} /** If the world transform has been modified and the local transform no longer matches, {@link #updateLocalTransform(Skeleton)}
* is called. */ * is called. */
public function validateLocalTransform(skeleton:Skeleton) { public function validateLocalTransform(skeleton:Skeleton) {
if (local == skeleton._update) updateLocalTransform(skeleton); if (local == skeleton._update)
updateLocalTransform(skeleton);
} }
public function modifyLocal(skeleton:Skeleton) { public function modifyLocal(skeleton:Skeleton) {
if (local == skeleton._update) updateLocalTransform(skeleton); if (local == skeleton._update)
updateLocalTransform(skeleton);
world = 0; world = 0;
resetWorld(skeleton._update); resetWorld(skeleton._update);
} }

View File

@ -34,7 +34,6 @@ abstract class Constraint< //
D:ConstraintData<T, P>, // D:ConstraintData<T, P>, //
P:Pose<Any>> // P:Pose<Any>> //
extends PosedActive<D, P, P> implements Update { extends PosedActive<D, P, P> implements Update {
public function new(data:D, pose:P, constrained:P) { public function new(data:D, pose:P, constrained:P) {
super(data, pose, constrained); super(data, pose, constrained);
} }

View File

@ -34,7 +34,6 @@ abstract class ConstraintData< //
T:Constraint<Dynamic, Dynamic, Dynamic>, // T:Constraint<Dynamic, Dynamic, Dynamic>, //
P:Pose<Any>> // P:Pose<Any>> //
extends PosedData<P> { extends PosedData<P> {
function new(name:String, setup:P) { function new(name:String, setup:P) {
super(name, setup); super(name, setup);
} }

View File

@ -50,7 +50,8 @@ class Event {
public var balance = 0.; public var balance = 0.;
public function new(time:Float, data:EventData) { public function new(time:Float, data:EventData) {
if (data == null) throw new SpineException("data cannot be null."); if (data == null)
throw new SpineException("data cannot be null.");
this.time = time; this.time = time;
this.data = data; this.data = data;
} }

View File

@ -32,12 +32,16 @@ package spine;
interface HasTextureRegion { interface HasTextureRegion {
/** The name used to find the region. */ /** The name used to find the region. */
public var path:String; public var path:String;
/** Sets the region used to draw the attachment. After setting the region or if the region's properties are changed, /** Sets the region used to draw the attachment. After setting the region or if the region's properties are changed,
* updateRegion() must be called. */ * updateRegion() must be called. */
public var region:TextureRegion; public var region:TextureRegion;
/** The color to tint the attachment. */ /** The color to tint the attachment. */
public var color:Color; public var color:Color;
public var sequence:Sequence; public var sequence:Sequence;
/** Updates any values the attachment calculates using the region. Must be called after setting the /** Updates any values the attachment calculates using the region. Must be called after setting the
* region or if the region's properties are changed. */ * region or if the region's properties are changed. */
public function updateRegion():Void; public function updateRegion():Void;

View File

@ -34,7 +34,6 @@ package spine;
* *
* @see https://esotericsoftware.com/spine-ik-constraints IK constraints in the Spine User Guide */ * @see https://esotericsoftware.com/spine-ik-constraints IK constraints in the Spine User Guide */
class IkConstraint extends Constraint<IkConstraint, IkConstraintData, IkConstraintPose> { class IkConstraint extends Constraint<IkConstraint, IkConstraintData, IkConstraintPose> {
/** The 1 or 2 bones that will be modified by this IK constraint. */ /** The 1 or 2 bones that will be modified by this IK constraint. */
public final bones:Array<BonePose>; public final bones:Array<BonePose>;
@ -43,7 +42,8 @@ class IkConstraint extends Constraint<IkConstraint, IkConstraintData, IkConstrai
public function new(data:IkConstraintData, skeleton:Skeleton) { public function new(data:IkConstraintData, skeleton:Skeleton) {
super(data, new IkConstraintPose(), new IkConstraintPose()); super(data, new IkConstraintPose(), new IkConstraintPose());
if (skeleton == null) throw new SpineException("skeleton cannot be null."); if (skeleton == null)
throw new SpineException("skeleton cannot be null.");
bones = new Array<BonePose>(); bones = new Array<BonePose>();
for (boneData in data.bones) for (boneData in data.bones)
@ -60,11 +60,14 @@ class IkConstraint extends Constraint<IkConstraint, IkConstraintData, IkConstrai
/** Applies the constraint to the constrained bones. */ /** Applies the constraint to the constrained bones. */
public function update(skeleton:Skeleton, physics:Physics):Void { public function update(skeleton:Skeleton, physics:Physics):Void {
var p = applied; var p = applied;
if (p.mix == 0) return; if (p.mix == 0)
return;
var target = target.applied; var target = target.applied;
switch (bones.length) { switch (bones.length) {
case 1: apply1(skeleton, bones[0], target.worldX, target.worldY, p.compress, p.stretch, data.uniform, p.mix); case 1:
case 2: apply2(skeleton, bones[0], bones[1], target.worldX, target.worldY, p.bendDirection, p.stretch, data.uniform, p.softness, p.mix); apply1(skeleton, bones[0], target.worldX, target.worldY, p.compress, p.stretch, data.uniform, p.mix);
case 2:
apply2(skeleton, bones[0], bones[1], target.worldX, target.worldY, p.bendDirection, p.stretch, data.uniform, p.softness, p.mix);
} }
} }
@ -76,7 +79,8 @@ class IkConstraint extends Constraint<IkConstraint, IkConstraintData, IkConstrai
parent.sorted = false; parent.sorted = false;
skeleton.sortReset(parent.children); skeleton.sortReset(parent.children);
skeleton.constrained(parent); skeleton.constrained(parent);
if (bones.length > 1) skeleton.constrained(bones[1].bone); if (bones.length > 1)
skeleton.constrained(bones[1].bone);
} }
override public function isSourceActive() { override public function isSourceActive() {
@ -84,16 +88,16 @@ class IkConstraint extends Constraint<IkConstraint, IkConstraintData, IkConstrai
} }
public function set_target(target:Bone):Bone { public function set_target(target:Bone):Bone {
if (target == null) throw new SpineException("target cannot be null."); if (target == null)
throw new SpineException("target cannot be null.");
this.target = target; this.target = target;
return target; return target;
} }
/** Applies 1 bone IK. The target is specified in the world coordinate system. */ /** Applies 1 bone IK. The target is specified in the world coordinate system. */
static public function apply1(skeleton:Skeleton, bone:BonePose, targetX:Float, targetY:Float, compress:Bool, stretch:Bool, static public function apply1(skeleton:Skeleton, bone:BonePose, targetX:Float, targetY:Float, compress:Bool, stretch:Bool, uniform:Bool, mix:Float) {
uniform:Bool, mix:Float) { if (bone == null)
throw new SpineException("bone cannot be null.");
if (bone == null) throw new SpineException("bone cannot be null.");
bone.modifyLocal(skeleton); bone.modifyLocal(skeleton);
var p = bone.bone.parent.applied; var p = bone.bone.parent.applied;
var pa = p.a, pb = p.b, pc = p.c, pd = p.d; var pa = p.a, pb = p.b, pc = p.c, pd = p.d;
@ -127,7 +131,8 @@ class IkConstraint extends Constraint<IkConstraint, IkConstraintData, IkConstrai
switchDefault(); switchDefault();
} }
rotationIK += MathUtils.atan2Deg(ty, tx); rotationIK += MathUtils.atan2Deg(ty, tx);
if (bone.scaleX < 0) rotationIK += 180; if (bone.scaleX < 0)
rotationIK += 180;
if (rotationIK > 180) if (rotationIK > 180)
rotationIK -= 360; rotationIK -= 360;
else if (rotationIK < -180) // else if (rotationIK < -180) //
@ -145,7 +150,8 @@ class IkConstraint extends Constraint<IkConstraint, IkConstraintData, IkConstrai
if ((compress && dd < b * b) || (stretch && dd > b * b)) { if ((compress && dd < b * b) || (stretch && dd > b * b)) {
var s = (Math.sqrt(dd) / b - 1) * mix + 1; var s = (Math.sqrt(dd) / b - 1) * mix + 1;
bone.scaleX *= s; bone.scaleX *= s;
if (uniform) bone.scaleY *= s; if (uniform)
bone.scaleY *= s;
} }
} }
} }
@ -153,12 +159,14 @@ class IkConstraint extends Constraint<IkConstraint, IkConstraintData, IkConstrai
/** Applies 2 bone IK. The target is specified in the world coordinate system. /** Applies 2 bone IK. The target is specified in the world coordinate system.
* @param child A direct descendant of the parent bone. */ * @param child A direct descendant of the parent bone. */
static public function apply2(skeleton:Skeleton, parent:BonePose, child:BonePose, targetX:Float, targetY:Float, bendDir:Int, static public function apply2(skeleton:Skeleton, parent:BonePose, child:BonePose, targetX:Float, targetY:Float, bendDir:Int, stretch:Bool, uniform:Bool,
stretch:Bool, uniform:Bool, softness:Float, mix:Float):Void { softness:Float, mix:Float):Void {
if (parent == null)
if (parent == null) throw new SpineException("parent cannot be null."); throw new SpineException("parent cannot be null.");
if (child == null) throw new SpineException("child cannot be null."); if (child == null)
if (parent.inherit != Inherit.normal || child.inherit != Inherit.normal) return; throw new SpineException("child cannot be null.");
if (parent.inherit != Inherit.normal || child.inherit != Inherit.normal)
return;
parent.modifyLocal(skeleton); parent.modifyLocal(skeleton);
child.modifyLocal(skeleton); child.modifyLocal(skeleton);
var px = parent.x, py = parent.y, psx = parent.scaleX, psy = parent.scaleY, csx = child.scaleX; var px = parent.x, py = parent.y, psx = parent.scaleX, psy = parent.scaleY, csx = child.scaleX;
@ -233,7 +241,8 @@ class IkConstraint extends Constraint<IkConstraint, IkConstraintData, IkConstrai
if (stretch) { if (stretch) {
a = (Math.sqrt(dd) / (l1 + l2) - 1) * mix + 1; a = (Math.sqrt(dd) / (l1 + l2) - 1) * mix + 1;
parent.scaleX *= a; parent.scaleX *= a;
if (uniform) parent.scaleY *= a; if (uniform)
parent.scaleY *= a;
} }
} }
a2 = Math.acos(cos) * bendDir; a2 = Math.acos(cos) * bendDir;

View File

@ -33,7 +33,6 @@ package spine;
* *
* @see https://esotericsoftware.com/spine-ik-constraints IK constraints in the Spine User Guide */ * @see https://esotericsoftware.com/spine-ik-constraints IK constraints in the Spine User Guide */
class IkConstraintData extends ConstraintData<IkConstraint, IkConstraintPose> { class IkConstraintData extends ConstraintData<IkConstraint, IkConstraintPose> {
/** The bones that are constrained by this IK constraint. */ /** The bones that are constrained by this IK constraint. */
public final bones:Array<BoneData> = new Array<BoneData>(); public final bones:Array<BoneData> = new Array<BoneData>();
@ -44,7 +43,6 @@ class IkConstraintData extends ConstraintData<IkConstraint, IkConstraintPose> {
* on both the X and Y axes. */ * on both the X and Y axes. */
public var uniform = false; public var uniform = false;
public function new(name:String) { public function new(name:String) {
super(name, new IkConstraintPose()); super(name, new IkConstraintPose());
} }
@ -54,7 +52,8 @@ class IkConstraintData extends ConstraintData<IkConstraint, IkConstraintPose> {
} }
public function set_target(target:BoneData) { public function set_target(target:BoneData) {
if (target == null) throw new SpineException("target cannot be null."); if (target == null)
throw new SpineException("target cannot be null.");
this.target = target; this.target = target;
return target; return target;
} }

View File

@ -31,7 +31,6 @@ package spine;
/** Stores the current pose for an IK constraint. */ /** Stores the current pose for an IK constraint. */
class IkConstraintPose implements Pose<IkConstraintPose> { class IkConstraintPose implements Pose<IkConstraintPose> {
/** For two bone IK, controls the bend direction of the IK bones, either 1 or -1. */ /** For two bone IK, controls the bend direction of the IK bones, either 1 or -1. */
public var bendDirection = 0; public var bendDirection = 0;
@ -53,8 +52,7 @@ class IkConstraintPose implements Pose<IkConstraintPose> {
* will not straighten completely until the target is this far out of range. */ * will not straighten completely until the target is this far out of range. */
public var softness = 0.; public var softness = 0.;
public function new () { public function new() {}
}
public function set(pose:IkConstraintPose) { public function set(pose:IkConstraintPose) {
mix = pose.mix; mix = pose.mix;
@ -63,5 +61,4 @@ class IkConstraintPose implements Pose<IkConstraintPose> {
compress = pose.compress; compress = pose.compress;
stretch = pose.stretch; stretch = pose.stretch;
} }
} }

View File

@ -58,7 +58,8 @@ class PathConstraint extends Constraint<PathConstraint, PathConstraintData, Path
public function new(data:PathConstraintData, skeleton:Skeleton) { public function new(data:PathConstraintData, skeleton:Skeleton) {
super(data, new PathConstraintPose(), new PathConstraintPose()); super(data, new PathConstraintPose(), new PathConstraintPose());
if (skeleton == null) throw new SpineException("skeleton cannot be null."); if (skeleton == null)
throw new SpineException("skeleton cannot be null.");
bones = new Array<BonePose>(); bones = new Array<BonePose>();
for (boneData in data.bones) for (boneData in data.bones)
@ -76,18 +77,23 @@ class PathConstraint extends Constraint<PathConstraint, PathConstraintData, Path
/** Applies the constraint to the constrained bones. */ /** Applies the constraint to the constrained bones. */
public function update(skeleton:Skeleton, physics:Physics):Void { public function update(skeleton:Skeleton, physics:Physics):Void {
var attachment = slot.applied.attachment; var attachment = slot.applied.attachment;
if (!Std.isOfType(attachment, PathAttachment)) return; if (!Std.isOfType(attachment, PathAttachment))
return;
var pathAttachment = cast(attachment, PathAttachment); var pathAttachment = cast(attachment, PathAttachment);
var p = applied; var p = applied;
var mixRotate = p.mixRotate, mixX = p.mixX, mixY = p.mixY; var mixRotate = p.mixRotate, mixX = p.mixX, mixY = p.mixY;
if (mixRotate == 0 && mixX == 0 && mixY == 0) return; if (mixRotate == 0 && mixX == 0 && mixY == 0)
return;
var data = data; var data = data;
var fTangents = data.rotateMode == RotateMode.tangent, fScale = data.rotateMode == RotateMode.chainScale; var fTangents = data.rotateMode == RotateMode.tangent,
var boneCount = bones.length, spacesCount = fTangents ? boneCount : boneCount + 1; fScale = data.rotateMode == RotateMode.chainScale;
var boneCount = bones.length,
spacesCount = fTangents ? boneCount : boneCount + 1;
ArrayUtils.resize(spaces, spacesCount, 0); ArrayUtils.resize(spaces, spacesCount, 0);
if (fScale) ArrayUtils.resize(lengths, boneCount, 0); if (fScale)
ArrayUtils.resize(lengths, boneCount, 0);
var spacing = p.spacing; var spacing = p.spacing;
var bones = bones; var bones = bones;
@ -102,7 +108,8 @@ class PathConstraint extends Constraint<PathConstraint, PathConstraintData, Path
lengths[i] = Math.sqrt(x * x + y * y); lengths[i] = Math.sqrt(x * x + y * y);
} }
} }
for (i in 1...spacesCount) spaces[i] = spacing; for (i in 1...spacesCount)
spaces[i] = spacing;
case SpacingMode.proportional: case SpacingMode.proportional:
var sum = 0.; var sum = 0.;
var i = 0, n = spacesCount - 1; var i = 0, n = spacesCount - 1;
@ -110,12 +117,14 @@ class PathConstraint extends Constraint<PathConstraint, PathConstraintData, Path
var bone = bones[i]; var bone = bones[i];
var setupLength:Float = bone.bone.data.length; var setupLength:Float = bone.bone.data.length;
if (setupLength < PathConstraint.epsilon) { if (setupLength < PathConstraint.epsilon) {
if (fScale) lengths[i] = 0; if (fScale)
lengths[i] = 0;
spaces[++i] = spacing; spaces[++i] = spacing;
} else { } else {
var x = setupLength * bone.a, y = setupLength * bone.c; var x = setupLength * bone.a, y = setupLength * bone.c;
var length = Math.sqrt(x * x + y * y); var length = Math.sqrt(x * x + y * y);
if (fScale) lengths[i] = length; if (fScale)
lengths[i] = length;
spaces[++i] = length; spaces[++i] = length;
sum += length; sum += length;
} }
@ -132,19 +141,23 @@ class PathConstraint extends Constraint<PathConstraint, PathConstraintData, Path
var bone = bones[i]; var bone = bones[i];
var setupLength = bone.bone.data.length; var setupLength = bone.bone.data.length;
if (setupLength < PathConstraint.epsilon) { if (setupLength < PathConstraint.epsilon) {
if (fScale) lengths[i] = 0; if (fScale)
lengths[i] = 0;
spaces[++i] = spacing; spaces[++i] = spacing;
} else { } else {
var x = setupLength * bone.a, y = setupLength * bone.c; var x = setupLength * bone.a, y = setupLength * bone.c;
var length = Math.sqrt(x * x + y * y); var length = Math.sqrt(x * x + y * y);
if (fScale) lengths[i] = length; if (fScale)
lengths[i] = length;
spaces[++i] = (lengthSpacing ? Math.max(0, setupLength + spacing) : spacing) * length / setupLength; spaces[++i] = (lengthSpacing ? Math.max(0, setupLength + spacing) : spacing) * length / setupLength;
} }
} }
} }
var positions = computeWorldPositions(skeleton, pathAttachment, spacesCount, fTangents); var positions = computeWorldPositions(skeleton, pathAttachment, spacesCount, fTangents);
var boneX = positions[0], boneY = positions[1], offsetRotation = data.offsetRotation; var boneX = positions[0],
boneY = positions[1],
offsetRotation = data.offsetRotation;
var tip = false; var tip = false;
if (offsetRotation == 0) if (offsetRotation == 0)
tip = data.rotateMode == RotateMode.chain; tip = data.rotateMode == RotateMode.chain;
@ -209,20 +222,26 @@ class PathConstraint extends Constraint<PathConstraint, PathConstraintData, Path
ArrayUtils.resize(positions, spacesCount * 3 + 2, 0); ArrayUtils.resize(positions, spacesCount * 3 + 2, 0);
var out:Array<Float> = positions, world = new Array<Float>(); var out:Array<Float> = positions, world = new Array<Float>();
var closed = path.closed; var closed = path.closed;
var verticesLength = path.worldVerticesLength, curveCount = Std.int(verticesLength / 6), prevCurve = NONE; var verticesLength = path.worldVerticesLength,
curveCount = Std.int(verticesLength / 6),
prevCurve = NONE;
if (!path.constantSpeed) { if (!path.constantSpeed) {
var lengths = path.lengths; var lengths = path.lengths;
curveCount -= closed ? 1 : 2; curveCount -= closed ? 1 : 2;
var pathLength = lengths[curveCount]; var pathLength = lengths[curveCount];
if (data.positionMode == PositionMode.percent) position *= pathLength; if (data.positionMode == PositionMode.percent)
position *= pathLength;
var multiplier:Float; var multiplier:Float;
switch (data.spacingMode) { switch (data.spacingMode) {
case SpacingMode.percent: multiplier = pathLength; case SpacingMode.percent:
case SpacingMode.proportional: multiplier = pathLength / spacesCount; multiplier = pathLength;
default: multiplier = 1; case SpacingMode.proportional:
multiplier = pathLength / spacesCount;
default:
multiplier = 1;
} }
ArrayUtils.resize(world, 8, 0); ArrayUtils.resize(world, 8, 0);
@ -234,7 +253,8 @@ class PathConstraint extends Constraint<PathConstraint, PathConstraintData, Path
if (closed) { if (closed) {
p %= pathLength; p %= pathLength;
if (p < 0) p += pathLength; if (p < 0)
p += pathLength;
curve = 0; curve = 0;
} else if (p < 0) { } else if (p < 0) {
if (prevCurve != BEFORE) { if (prevCurve != BEFORE) {
@ -276,8 +296,7 @@ class PathConstraint extends Constraint<PathConstraint, PathConstraintData, Path
path.computeWorldVertices(skeleton, slot, curve * 6 + 2, 8, world, 0, 2); path.computeWorldVertices(skeleton, slot, curve * 6 + 2, 8, world, 0, 2);
} }
} }
addCurvePosition(p, world[0], world[1], world[2], world[3], world[4], world[5], world[6], world[7], out, o, addCurvePosition(p, world[0], world[1], world[2], world[3], world[4], world[5], world[6], world[7], out, o, tangents || (i > 0 && space == 0));
tangents || (i > 0 && space == 0));
i++; i++;
o += 3; o += 3;
} }
@ -341,13 +360,17 @@ class PathConstraint extends Constraint<PathConstraint, PathConstraintData, Path
w += 6; w += 6;
} }
if (data.positionMode == PositionMode.percent) position *= pathLength; if (data.positionMode == PositionMode.percent)
position *= pathLength;
var multiplier:Float; var multiplier:Float;
switch (data.spacingMode) { switch (data.spacingMode) {
case SpacingMode.percent: multiplier = pathLength; case SpacingMode.percent:
case SpacingMode.proportional: multiplier = pathLength / spacesCount; multiplier = pathLength;
default: multiplier = 1; case SpacingMode.proportional:
multiplier = pathLength / spacesCount;
default:
multiplier = 1;
} }
var segments = segments; var segments = segments;
@ -360,7 +383,8 @@ class PathConstraint extends Constraint<PathConstraint, PathConstraintData, Path
if (closed) { if (closed) {
p %= pathLength; p %= pathLength;
if (p < 0) p += pathLength; if (p < 0)
p += pathLength;
curve = 0; curve = 0;
segment = 0; segment = 0;
} else if (p < 0) { } else if (p < 0) {
@ -512,7 +536,8 @@ class PathConstraint extends Constraint<PathConstraint, PathConstraintData, Path
public function sort(skeleton:Skeleton) { public function sort(skeleton:Skeleton) {
var slotIndex = slot.data.index; var slotIndex = slot.data.index;
var slotBone = slot.bone; var slotBone = slot.bone;
if (skeleton.skin != null) sortPathSlot(skeleton, skeleton.skin, slotIndex, slotBone); if (skeleton.skin != null)
sortPathSlot(skeleton, skeleton.skin, slotIndex, slotBone);
if (skeleton.data.defaultSkin != null && skeleton.data.defaultSkin != skeleton.skin) if (skeleton.data.defaultSkin != null && skeleton.data.defaultSkin != skeleton.skin)
sortPathSlot(skeleton, skeleton.data.defaultSkin, slotIndex, slotBone); sortPathSlot(skeleton, skeleton.data.defaultSkin, slotIndex, slotBone);
sortPath(skeleton, slot.pose.attachment, slotBone); sortPath(skeleton, slot.pose.attachment, slotBone);
@ -532,12 +557,14 @@ class PathConstraint extends Constraint<PathConstraint, PathConstraintData, Path
public function sortPathSlot(skeleton:Skeleton, skin:Skin, slotIndex:Int, slotBone:Bone) { public function sortPathSlot(skeleton:Skeleton, skin:Skin, slotIndex:Int, slotBone:Bone) {
var entries = skin.getAttachments(); var entries = skin.getAttachments();
for (entry in entries) { for (entry in entries) {
if (entry.slotIndex == slotIndex) sortPath(skeleton, entry.attachment, slotBone); if (entry.slotIndex == slotIndex)
sortPath(skeleton, entry.attachment, slotBone);
} }
} }
private function sortPath(skeleton:Skeleton, attachment:Attachment, slotBone:Bone) { private function sortPath(skeleton:Skeleton, attachment:Attachment, slotBone:Bone) {
if (!(Std.isOfType(attachment, PathAttachment))) return; if (!(Std.isOfType(attachment, PathAttachment)))
return;
var pathBones = cast(attachment, PathAttachment).bones; var pathBones = cast(attachment, PathAttachment).bones;
if (pathBones == null) if (pathBones == null)
skeleton.sortBone(slotBone); skeleton.sortBone(slotBone);

View File

@ -60,25 +60,29 @@ class PathConstraintData extends ConstraintData<PathConstraint, PathConstraintPo
} }
public function set_slot(slot:SlotData):SlotData { public function set_slot(slot:SlotData):SlotData {
if (slot == null) throw new SpineException("slot cannot be null."); if (slot == null)
throw new SpineException("slot cannot be null.");
this.slot = slot; this.slot = slot;
return slot; return slot;
} }
public function set_positionMode(positionMode:PositionMode):PositionMode { public function set_positionMode(positionMode:PositionMode):PositionMode {
if (positionMode == null) throw new SpineException("positionMode cannot be null."); if (positionMode == null)
throw new SpineException("positionMode cannot be null.");
this.positionMode = positionMode; this.positionMode = positionMode;
return positionMode; return positionMode;
} }
public function set_spacingMode(spacingMode:SpacingMode):SpacingMode { public function set_spacingMode(spacingMode:SpacingMode):SpacingMode {
if (spacingMode == null) throw new SpineException("spacingMode cannot be null."); if (spacingMode == null)
throw new SpineException("spacingMode cannot be null.");
this.spacingMode = spacingMode; this.spacingMode = spacingMode;
return spacingMode; return spacingMode;
} }
public function set_rotateMode(rotateMode:RotateMode):RotateMode { public function set_rotateMode(rotateMode:RotateMode):RotateMode {
if (rotateMode == null) throw new SpineException("rotateMode cannot be null."); if (rotateMode == null)
throw new SpineException("rotateMode cannot be null.");
this.rotateMode = rotateMode; this.rotateMode = rotateMode;
return rotateMode; return rotateMode;
} }

View File

@ -30,7 +30,6 @@
package spine; package spine;
class PathConstraintPose implements Pose<PathConstraintPose> { class PathConstraintPose implements Pose<PathConstraintPose> {
/** The position along the path. */ /** The position along the path. */
public var position = 0.; public var position = 0.;
@ -46,8 +45,7 @@ class PathConstraintPose implements Pose<PathConstraintPose> {
/** A percentage (0-1) that controls the mix between the constrained and unconstrained translation Y. */ /** A percentage (0-1) that controls the mix between the constrained and unconstrained translation Y. */
public var mixY = 0.; public var mixY = 0.;
public function new () { public function new() {}
}
public function set(pose:PathConstraintPose) { public function set(pose:PathConstraintPose) {
position = pose.position; position = pose.position;

View File

@ -33,10 +33,13 @@ package spine;
class Physics { class Physics {
/** Physics are not updated or applied. */ /** Physics are not updated or applied. */
public static var none(default, never):Physics = new Physics("none"); public static var none(default, never):Physics = new Physics("none");
/** Physics are reset to the current pose. */ /** Physics are reset to the current pose. */
public static var reset(default, never):Physics = new Physics("reset"); public static var reset(default, never):Physics = new Physics("reset");
/** Physics are updated and the pose from physics is applied. */ /** Physics are updated and the pose from physics is applied. */
public static var update(default, never):Physics = new Physics("update"); public static var update(default, never):Physics = new Physics("update");
/** Physics are not updated but the pose from physics is applied. */ /** Physics are not updated but the pose from physics is applied. */
public static var pose(default, never):Physics = new Physics("pose"); public static var pose(default, never):Physics = new Physics("pose");

View File

@ -35,7 +35,6 @@ package spine;
* @see https://esotericsoftware.com/spine-physics-constraints Physics constraints in the Spine User Guide * @see https://esotericsoftware.com/spine-physics-constraints Physics constraints in the Spine User Guide
*/ */
class PhysicsConstraint extends Constraint<PhysicsConstraint, PhysicsConstraintData, PhysicsConstraintPose> { class PhysicsConstraint extends Constraint<PhysicsConstraint, PhysicsConstraintData, PhysicsConstraintPose> {
/** The bone constrained by this physics constraint. */ /** The bone constrained by this physics constraint. */
public var bone:BonePose = null; public var bone:BonePose = null;
@ -64,7 +63,8 @@ class PhysicsConstraint extends Constraint<PhysicsConstraint, PhysicsConstraintD
public function new(data:PhysicsConstraintData, skeleton:Skeleton) { public function new(data:PhysicsConstraintData, skeleton:Skeleton) {
super(data, new PhysicsConstraintPose(), new PhysicsConstraintPose()); super(data, new PhysicsConstraintPose(), new PhysicsConstraintPose());
if (skeleton == null) throw new SpineException("skeleton cannot be null."); if (skeleton == null)
throw new SpineException("skeleton cannot be null.");
bone = skeleton.bones[data.bone.index].constrained; bone = skeleton.bones[data.bone.index].constrained;
} }
@ -105,7 +105,9 @@ class PhysicsConstraint extends Constraint<PhysicsConstraint, PhysicsConstraintD
/** Rotates the physics constraint so next update(Physics) forces are applied as if the bone rotated around the /** Rotates the physics constraint so next update(Physics) forces are applied as if the bone rotated around the
* specified point in world space. */ * specified point in world space. */
public function rotate(x:Float, y:Float, degrees:Float):Void { public function rotate(x:Float, y:Float, degrees:Float):Void {
var r = degrees * MathUtils.degRad, cos = Math.cos(r), sin = Math.sin(r); var r = degrees * MathUtils.degRad,
cos = Math.cos(r),
sin = Math.sin(r);
var dx = cx - x, dy = cy - y; var dx = cx - x, dy = cy - y;
translate(dx * cos - dy * sin - dx, dx * sin + dy * cos - dy); translate(dx * cos - dy * sin - dx, dx * sin + dy * cos - dy);
} }
@ -114,16 +116,21 @@ class PhysicsConstraint extends Constraint<PhysicsConstraint, PhysicsConstraintD
public function update(skeleton:Skeleton, physics:Physics):Void { public function update(skeleton:Skeleton, physics:Physics):Void {
var p = applied; var p = applied;
var mix = p.mix; var mix = p.mix;
if (mix == 0) return; if (mix == 0)
return;
var x = data.x > 0, y = data.y > 0, rotateOrShearX = data.rotate > 0 || data.shearX > 0, scaleX = data.scaleX > 0; var x = data.x > 0,
y = data.y > 0,
rotateOrShearX = data.rotate > 0 || data.shearX > 0,
scaleX = data.scaleX > 0;
var l = bone.bone.data.length, t = data.step, z = 0.; var l = bone.bone.data.length, t = data.step, z = 0.;
switch (physics) { switch (physics) {
case Physics.none: case Physics.none:
return; return;
case Physics.reset, Physics.update: case Physics.reset, Physics.update:
if (physics == Physics.reset) reset(skeleton); if (physics == Physics.reset)
reset(skeleton);
var delta = Math.max(skeleton.time - lastTime, 0), aa = remaining; var delta = Math.max(skeleton.time - lastTime, 0), aa = remaining;
remaining += delta; remaining += delta;
@ -135,8 +142,8 @@ class PhysicsConstraint extends Constraint<PhysicsConstraint, PhysicsConstraintD
ux = bx; ux = bx;
uy = by; uy = by;
} else { } else {
var a = remaining, i = p.inertia, f = skeleton.data.referenceScale, d = -1., m = 0., e = 0., ax = 0., ay = 0., var a = remaining, i = p.inertia, f = skeleton.data.referenceScale, d = -1., m = 0., e = 0., ax = 0., ay = 0., qx = data.limit * delta,
qx = data.limit * delta, qy = qx * Math.abs(skeleton.scaleY); qy = qx * Math.abs(skeleton.scaleY);
qx *= Math.abs(skeleton.scaleX); qx *= Math.abs(skeleton.scaleX);
if (x || y) { if (x || y) {
if (x) { if (x) {
@ -174,8 +181,10 @@ class PhysicsConstraint extends Constraint<PhysicsConstraint, PhysicsConstraintD
yLag = yOffset - ys; yLag = yOffset - ys;
} }
z = Math.max(0, 1 - a / t); z = Math.max(0, 1 - a / t);
if (x) bone.worldX += (xOffset - xLag * z) * mix * data.x; if (x)
if (y) bone.worldY += (yOffset - yLag * z) * mix * data.y; bone.worldX += (xOffset - xLag * z) * mix * data.x;
if (y)
bone.worldY += (yOffset - yLag * z) * mix * data.y;
} }
if (rotateOrShearX || scaleX) { if (rotateOrShearX || scaleX) {
var ca = Math.atan2(bone.c, bone.a), c = 0., s = 0., mr = 0., dx = cx - bone.worldX, dy = cy - bone.worldY; var ca = Math.atan2(bone.c, bone.a), c = 0., s = 0., mr = 0., dx = cx - bone.worldX, dy = cy - bone.worldY;
@ -198,20 +207,23 @@ class PhysicsConstraint extends Constraint<PhysicsConstraint, PhysicsConstraintD
s = Math.sin(r); s = Math.sin(r);
if (scaleX) { if (scaleX) {
r = l * bone.worldScaleX; r = l * bone.worldScaleX;
if (r > 0) scaleOffset += (dx * c + dy * s) * i / r; if (r > 0)
scaleOffset += (dx * c + dy * s) * i / r;
} }
} else { } else {
c = Math.cos(ca); c = Math.cos(ca);
s = Math.sin(ca); s = Math.sin(ca);
var r = l * bone.worldScaleX - scaleLag * Math.max(0, 1 - aa / t); var r = l * bone.worldScaleX - scaleLag * Math.max(0, 1 - aa / t);
if (r > 0) scaleOffset += (dx * c + dy * s) * i / r; if (r > 0)
scaleOffset += (dx * c + dy * s) * i / r;
} }
if (a >= t) { if (a >= t) {
if (d == -1) { if (d == -1) {
d = Math.pow(p.damping, 60 * t); d = Math.pow(p.damping, 60 * t);
m = t * p.massInverse; m = t * p.massInverse;
e = p.strength; e = p.strength;
var w = f * p.wind, g = f * p.gravity * Bone.yDir; var w = f * p.wind,
g = f * p.gravity * Bone.yDir;
ax = (w * skeleton.windX + g * skeleton.gravityX) * skeleton.scaleX; ax = (w * skeleton.windX + g * skeleton.gravityX) * skeleton.scaleX;
ay = (w * skeleton.windY + g * skeleton.gravityY) * skeleton.scaleY; ay = (w * skeleton.windY + g * skeleton.gravityY) * skeleton.scaleY;
} }
@ -227,7 +239,8 @@ class PhysicsConstraint extends Constraint<PhysicsConstraint, PhysicsConstraintD
rotateVelocity -= ((ax * s + ay * c) * h + rotateOffset * e) * m; rotateVelocity -= ((ax * s + ay * c) * h + rotateOffset * e) * m;
rotateOffset += rotateVelocity * t; rotateOffset += rotateVelocity * t;
rotateVelocity *= d; rotateVelocity *= d;
if (a < t) break; if (a < t)
break;
var r:Float = rotateOffset * mr + ca; var r:Float = rotateOffset * mr + ca;
c = Math.cos(r); c = Math.cos(r);
s = Math.sin(r); s = Math.sin(r);
@ -245,8 +258,10 @@ class PhysicsConstraint extends Constraint<PhysicsConstraint, PhysicsConstraintD
cy = bone.worldY; cy = bone.worldY;
case Physics.pose: case Physics.pose:
z = Math.max(0, 1 - remaining / t); z = Math.max(0, 1 - remaining / t);
if (x) bone.worldX += (xOffset - xLag * z) * mix * data.x; if (x)
if (y) bone.worldY += (yOffset - yLag * z) * mix * data.y; bone.worldX += (xOffset - xLag * z) * mix * data.x;
if (y)
bone.worldY += (yOffset - yLag * z) * mix * data.y;
} }
if (rotateOrShearX) { if (rotateOrShearX) {

View File

@ -33,7 +33,6 @@ package spine;
* *
* @see https://esotericsoftware.com/spine-physics-constraints Physics constraints in the Spine User Guide */ * @see https://esotericsoftware.com/spine-physics-constraints Physics constraints in the Spine User Guide */
class PhysicsConstraintData extends ConstraintData<PhysicsConstraint, PhysicsConstraintPose> { class PhysicsConstraintData extends ConstraintData<PhysicsConstraint, PhysicsConstraintPose> {
/** The bone constrained by this physics constraint. */ /** The bone constrained by this physics constraint. */
public var bone:BoneData; public var bone:BoneData;
@ -44,8 +43,10 @@ class PhysicsConstraintData extends ConstraintData<PhysicsConstraint, PhysicsCon
public var shearX = 0.; public var shearX = 0.;
public var limit = 0.; public var limit = 0.;
public var step = 0.; public var step = 0.;
/** A percentage (0-1) that controls the mix between the constrained and unconstrained poses. */ /** A percentage (0-1) that controls the mix between the constrained and unconstrained poses. */
public var mix = 0.; public var mix = 0.;
public var inertiaGlobal = false; public var inertiaGlobal = false;
public var strengthGlobal = false; public var strengthGlobal = false;
public var dampingGlobal = false; public var dampingGlobal = false;
@ -61,5 +62,4 @@ class PhysicsConstraintData extends ConstraintData<PhysicsConstraint, PhysicsCon
public function create(skeleton:Skeleton) { public function create(skeleton:Skeleton) {
return new PhysicsConstraint(this, skeleton); return new PhysicsConstraint(this, skeleton);
} }
} }

View File

@ -31,18 +31,17 @@ package spine;
/** Stores a pose for a physics constraint. */ /** Stores a pose for a physics constraint. */
class PhysicsConstraintPose implements Pose<PhysicsConstraintPose> { class PhysicsConstraintPose implements Pose<PhysicsConstraintPose> {
public var inertia = 0.; public var inertia = 0.;
public var strength = 0.; public var strength = 0.;
public var damping = 0.; public var damping = 0.;
public var massInverse = 0.; public var massInverse = 0.;
public var wind = 0.; public var wind = 0.;
public var gravity = 0.; public var gravity = 0.;
/** A percentage (0-1) that controls the mix between the constrained and unconstrained poses. */ /** A percentage (0-1) that controls the mix between the constrained and unconstrained poses. */
public var mix = 0.; public var mix = 0.;
public function new () { public function new() {}
}
public function set(pose:PhysicsConstraintPose) { public function set(pose:PhysicsConstraintPose) {
inertia = pose.inertia; inertia = pose.inertia;

View File

@ -33,15 +33,16 @@ abstract class Posed< //
D:PosedData<P>, // D:PosedData<P>, //
P:Pose<Any>, // P:Pose<Any>, //
A:P> { A:P> {
/** The constraint's setup pose data. */ /** The constraint's setup pose data. */
public final data:D; public final data:D;
public final pose:A; public final pose:A;
public final constrained:A; public final constrained:A;
public var applied:A; public var applied:A;
public function new(data:D, pose:A, constrained:A) { public function new(data:D, pose:A, constrained:A) {
if (data == null) throw new SpineException("data cannot be null."); if (data == null)
throw new SpineException("data cannot be null.");
this.data = data; this.data = data;
this.pose = pose; this.pose = pose;
this.constrained = constrained; this.constrained = constrained;

View File

@ -34,7 +34,6 @@ abstract class PosedActive< //
P:Pose<Any>, // P:Pose<Any>, //
A:P> // A:P> //
extends Posed<D, P, A> { extends Posed<D, P, A> {
public var active:Bool; public var active:Bool;
public function new(data:D, pose:A, constrained:A) { public function new(data:D, pose:A, constrained:A) {

View File

@ -43,7 +43,8 @@ abstract class PosedData<P:Pose<Any>> {
public var skinRequired:Bool; public var skinRequired:Bool;
public function new(name:String, setup:P) { public function new(name:String, setup:P) {
if (name == null) throw new SpineException("name cannot be null."); if (name == null)
throw new SpineException("name cannot be null.");
this.name = name; this.name = name;
this.setup = setup; this.setup = setup;
} }

View File

@ -35,6 +35,7 @@ package spine;
class RotateMode { class RotateMode {
public static var tangent(default, never):RotateMode = new RotateMode("tangent"); public static var tangent(default, never):RotateMode = new RotateMode("tangent");
public static var chain(default, never):RotateMode = new RotateMode("chain"); public static var chain(default, never):RotateMode = new RotateMode("chain");
/** When chain scale, constrained bones should all have the same parent. That way when the path constraint scales a bone, it /** When chain scale, constrained bones should all have the same parent. That way when the path constraint scales a bone, it
* doesn't affect other constrained bones. */ * doesn't affect other constrained bones. */
public static var chainScale(default, never):RotateMode = new RotateMode("chainScale"); public static var chainScale(default, never):RotateMode = new RotateMode("chainScale");

View File

@ -35,6 +35,7 @@ class Sequence {
/** Returns a unique ID for this attachment. */ /** Returns a unique ID for this attachment. */
public var id = _nextID++; public var id = _nextID++;
public var regions:Array<TextureRegion>; public var regions:Array<TextureRegion>;
public var start = 0; public var start = 0;
public var digits = 0; public var digits = 0;

View File

@ -92,6 +92,7 @@ class Skeleton {
* *
* Bones that do not inherit scale are still affected by this property. */ * Bones that do not inherit scale are still affected by this property. */
public var scaleY(get, default):Float = 1; public var scaleY(get, default):Float = 1;
function get_scaleY() { function get_scaleY() {
return scaleY * Bone.yDir; return scaleY * Bone.yDir;
} }
@ -110,7 +111,8 @@ class Skeleton {
/** Creates a new skeleton with the specified skeleton data. */ /** Creates a new skeleton with the specified skeleton data. */
public function new(data:SkeletonData) { public function new(data:SkeletonData) {
if (data == null) throw new SpineException("data cannot be null."); if (data == null)
throw new SpineException("data cannot be null.");
this.data = data; this.data = data;
bones = new Array<Bone>(); bones = new Array<Bone>();
@ -138,7 +140,8 @@ class Skeleton {
constraints = new Array<Constraint<Dynamic, Dynamic, Dynamic>>(); constraints = new Array<Constraint<Dynamic, Dynamic, Dynamic>>();
for (constraintData in data.constraints) { for (constraintData in data.constraints) {
var constraint = constraintData.create(this); var constraint = constraintData.create(this);
if (Std.isOfType(constraint, PhysicsConstraint)) physics.push(cast(constraint, PhysicsConstraint)); if (Std.isOfType(constraint, PhysicsConstraint))
physics.push(cast(constraint, PhysicsConstraint));
constraints.push(constraint); constraints.push(constraint);
} }
@ -180,7 +183,8 @@ class Skeleton {
var constraint:Constraint<Dynamic, Dynamic, Dynamic> = c; var constraint:Constraint<Dynamic, Dynamic, Dynamic> = c;
constraint.active = constraint.isSourceActive() constraint.active = constraint.isSourceActive()
&& (!constraint.data.skinRequired || (skin != null && contains(skin.constraints, constraint.data))); && (!constraint.data.skinRequired || (skin != null && contains(skin.constraints, constraint.data)));
if (constraint.active) constraint.sort(this); if (constraint.active)
constraint.sort(this);
} }
for (bone in bones) for (bone in bones)
@ -209,9 +213,11 @@ class Skeleton {
} }
public function sortBone(bone:Bone):Void { public function sortBone(bone:Bone):Void {
if (bone.sorted || !bone.active) return; if (bone.sorted || !bone.active)
return;
var parent = bone.parent; var parent = bone.parent;
if (parent != null) sortBone(parent); if (parent != null)
sortBone(parent);
bone.sorted = true; bone.sorted = true;
_updateCache.push(bone); _updateCache.push(bone);
} }
@ -219,7 +225,8 @@ class Skeleton {
public function sortReset(bones:Array<Bone>):Void { public function sortReset(bones:Array<Bone>):Void {
for (bone in bones) { for (bone in bones) {
if (bone.active) { if (bone.active) {
if (bone.sorted) sortReset(bone.children); if (bone.sorted)
sortReset(bone.children);
bone.sorted = false; bone.sorted = false;
} }
} }
@ -247,8 +254,10 @@ class Skeleton {
/** Sets the bones and constraints to their setup pose values. */ /** Sets the bones and constraints to their setup pose values. */
public function setupPoseBones():Void { public function setupPoseBones():Void {
for (bone in this.bones) bone.setupPose(); for (bone in this.bones)
for (constraint in this.constraints) constraint.setupPose(); bone.setupPose();
for (constraint in this.constraints)
constraint.setupPose();
} }
/** Sets the slots and draw order to their setup pose values. */ /** Sets the slots and draw order to their setup pose values. */
@ -270,18 +279,22 @@ class Skeleton {
/** Finds a bone by comparing each bone's name. It is more efficient to cache the results of this method than to call it /** Finds a bone by comparing each bone's name. It is more efficient to cache the results of this method than to call it
* repeatedly. */ * repeatedly. */
public function findBone(boneName:String):Bone { public function findBone(boneName:String):Bone {
if (boneName == null) throw new SpineException("boneName cannot be null."); if (boneName == null)
throw new SpineException("boneName cannot be null.");
for (bone in bones) for (bone in bones)
if (bone.data.name == boneName) return bone; if (bone.data.name == boneName)
return bone;
return null; return null;
} }
/** @return -1 if the bone was not found. */ /** @return -1 if the bone was not found. */
public function findBoneIndex(boneName:String):Int { public function findBoneIndex(boneName:String):Int {
if (boneName == null) throw new SpineException("boneName cannot be null."); if (boneName == null)
throw new SpineException("boneName cannot be null.");
var i:Int = 0; var i:Int = 0;
for (bone in bones) { for (bone in bones) {
if (bone.data.name == boneName) return i; if (bone.data.name == boneName)
return i;
i++; i++;
} }
return -1; return -1;
@ -290,9 +303,11 @@ class Skeleton {
/** Finds a slot by comparing each slot's name. It is more efficient to cache the results of this method than to call it /** Finds a slot by comparing each slot's name. It is more efficient to cache the results of this method than to call it
* repeatedly. */ * repeatedly. */
public function findSlot(slotName:String):Slot { public function findSlot(slotName:String):Slot {
if (slotName == null) throw new SpineException("slotName cannot be null."); if (slotName == null)
throw new SpineException("slotName cannot be null.");
for (slot in slots) for (slot in slots)
if (slot.data.name == slotName) return slot; if (slot.data.name == slotName)
return slot;
return null; return null;
} }
@ -337,7 +352,8 @@ class Skeleton {
var name:String = slot.data.attachmentName; var name:String = slot.data.attachmentName;
if (name != null) { if (name != null) {
var attachment:Attachment = newSkin.getAttachment(i, name); var attachment:Attachment = newSkin.getAttachment(i, name);
if (attachment != null) slot.pose.attachment = attachment; if (attachment != null)
slot.pose.attachment = attachment;
} }
i++; i++;
} }
@ -399,10 +415,13 @@ class Skeleton {
} }
public function findConstraint<T:Constraint<Dynamic, Dynamic, Dynamic>>(constraintName:String, type:Class<T>):Null<T> { public function findConstraint<T:Constraint<Dynamic, Dynamic, Dynamic>>(constraintName:String, type:Class<T>):Null<T> {
if (constraintName == null) throw new SpineException("constraintName cannot be null."); if (constraintName == null)
if (type == null) throw new SpineException("type cannot be null."); throw new SpineException("constraintName cannot be null.");
if (type == null)
throw new SpineException("type cannot be null.");
for (constraint in constraints) for (constraint in constraints)
if (Std.isOfType(constraint, type) && constraint.data.name == constraintName) return Std.downcast(constraint, type); if (Std.isOfType(constraint, type) && constraint.data.name == constraintName)
return Std.downcast(constraint, type);
return null; return null;
} }
@ -456,10 +475,12 @@ class Skeleton {
ii += 2; ii += 2;
} }
} }
if (clipper != null) clipper.clipEnd(slot); if (clipper != null)
clipper.clipEnd(slot);
} }
} }
if (clipper != null) clipper.clipEnd(); if (clipper != null)
clipper.clipEnd();
_bounds.x = minX; _bounds.x = minX;
_bounds.y = minY; _bounds.y = minY;
_bounds.width = maxX - minX; _bounds.width = maxX - minX;

View File

@ -219,11 +219,13 @@ class SkeletonBinary {
data.setup.color.setFromRgba8888(input.readInt32()); data.setup.color.setFromRgba8888(input.readInt32());
var darkColor = input.readInt32(); var darkColor = input.readInt32();
if (darkColor != -1) data.setup.darkColor = new Color(0, 0, 0).setFromRgb888(darkColor); if (darkColor != -1)
data.setup.darkColor = new Color(0, 0, 0).setFromRgb888(darkColor);
data.attachmentName = input.readStringRef(); data.attachmentName = input.readStringRef();
data.blendMode = BlendMode.values[input.readInt(true)]; data.blendMode = BlendMode.values[input.readInt(true)];
if (nonessential) data.visible = input.readBoolean(); if (nonessential)
data.visible = input.readBoolean();
slots.push(data); slots.push(data);
} }
@ -248,8 +250,10 @@ class SkeletonBinary {
setup.bendDirection = (flags & 4) != 0 ? 1 : -1; setup.bendDirection = (flags & 4) != 0 ? 1 : -1;
setup.compress = (flags & 8) != 0; setup.compress = (flags & 8) != 0;
setup.stretch = (flags & 16) != 0; setup.stretch = (flags & 16) != 0;
if ((flags & 32) != 0) setup.mix = (flags & 64) != 0 ? input.readFloat() : 1; if ((flags & 32) != 0)
if ((flags & 128) != 0) setup.softness = input.readFloat() * scale; setup.mix = (flags & 64) != 0 ? input.readFloat() : 1;
if ((flags & 128) != 0)
setup.softness = input.readFloat() * scale;
constraints[i] = data; constraints[i] = data;
case CONSTRAINT_TRANSFORM: case CONSTRAINT_TRANSFORM:
var data = new TransformConstraintData(name); var data = new TransformConstraintData(name);
@ -309,20 +313,32 @@ class SkeletonBinary {
froms[ii] = from; froms[ii] = from;
} }
flags = input.readByte(); flags = input.readByte();
if ((flags & 1) != 0) data.offsets[TransformConstraintData.ROTATION] = input.readFloat(); if ((flags & 1) != 0)
if ((flags & 2) != 0) data.offsets[TransformConstraintData.X] = input.readFloat() * scale; data.offsets[TransformConstraintData.ROTATION] = input.readFloat();
if ((flags & 4) != 0) data.offsets[TransformConstraintData.Y] = input.readFloat() * scale; if ((flags & 2) != 0)
if ((flags & 8) != 0) data.offsets[TransformConstraintData.SCALEX] = input.readFloat(); data.offsets[TransformConstraintData.X] = input.readFloat() * scale;
if ((flags & 16) != 0) data.offsets[TransformConstraintData.SCALEY] = input.readFloat(); if ((flags & 4) != 0)
if ((flags & 32) != 0) data.offsets[TransformConstraintData.SHEARY] = input.readFloat(); data.offsets[TransformConstraintData.Y] = input.readFloat() * scale;
if ((flags & 8) != 0)
data.offsets[TransformConstraintData.SCALEX] = input.readFloat();
if ((flags & 16) != 0)
data.offsets[TransformConstraintData.SCALEY] = input.readFloat();
if ((flags & 32) != 0)
data.offsets[TransformConstraintData.SHEARY] = input.readFloat();
flags = input.readByte(); flags = input.readByte();
var setup = data.setup; var setup = data.setup;
if ((flags & 1) != 0) setup.mixRotate = input.readFloat(); if ((flags & 1) != 0)
if ((flags & 2) != 0) setup.mixX = input.readFloat(); setup.mixRotate = input.readFloat();
if ((flags & 4) != 0) setup.mixY = input.readFloat(); if ((flags & 2) != 0)
if ((flags & 8) != 0) setup.mixScaleX = input.readFloat(); setup.mixX = input.readFloat();
if ((flags & 16) != 0) setup.mixScaleY = input.readFloat(); if ((flags & 4) != 0)
if ((flags & 32) != 0) setup.mixShearY = input.readFloat(); setup.mixY = input.readFloat();
if ((flags & 8) != 0)
setup.mixScaleX = input.readFloat();
if ((flags & 16) != 0)
setup.mixScaleY = input.readFloat();
if ((flags & 32) != 0)
setup.mixShearY = input.readFloat();
constraints[i] = data; constraints[i] = data;
case CONSTRAINT_PATH: case CONSTRAINT_PATH:
var data = new PathConstraintData(name); var data = new PathConstraintData(name);
@ -336,12 +352,15 @@ class SkeletonBinary {
data.positionMode = PositionMode.values[(flags >> 1) & 2]; data.positionMode = PositionMode.values[(flags >> 1) & 2];
data.spacingMode = SpacingMode.values[(flags >> 2) & 3]; data.spacingMode = SpacingMode.values[(flags >> 2) & 3];
data.rotateMode = RotateMode.values[(flags >> 4) & 3]; data.rotateMode = RotateMode.values[(flags >> 4) & 3];
if ((flags & 128) != 0) data.offsetRotation = input.readFloat(); if ((flags & 128) != 0)
data.offsetRotation = input.readFloat();
var setup = data.setup; var setup = data.setup;
setup.position = input.readFloat(); setup.position = input.readFloat();
if (data.positionMode == PositionMode.fixed) setup.position *= scale; if (data.positionMode == PositionMode.fixed)
setup.position *= scale;
setup.spacing = input.readFloat(); setup.spacing = input.readFloat();
if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) setup.spacing *= scale; if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed)
setup.spacing *= scale;
setup.mixRotate = input.readFloat(); setup.mixRotate = input.readFloat();
setup.mixX = input.readFloat(); setup.mixX = input.readFloat();
setup.mixY = input.readFloat(); setup.mixY = input.readFloat();
@ -351,11 +370,16 @@ class SkeletonBinary {
data.bone = bones[input.readInt(true)]; data.bone = bones[input.readInt(true)];
var flags = input.readByte(); var flags = input.readByte();
data.skinRequired = (flags & 1) != 0; data.skinRequired = (flags & 1) != 0;
if ((flags & 2) != 0) data.x = input.readFloat(); if ((flags & 2) != 0)
if ((flags & 4) != 0) data.y = input.readFloat(); data.x = input.readFloat();
if ((flags & 8) != 0) data.rotate = input.readFloat(); if ((flags & 4) != 0)
if ((flags & 16) != 0) data.scaleX = input.readFloat(); data.y = input.readFloat();
if ((flags & 32) != 0) data.shearX = input.readFloat(); if ((flags & 8) != 0)
data.rotate = input.readFloat();
if ((flags & 16) != 0)
data.scaleX = input.readFloat();
if ((flags & 32) != 0)
data.shearX = input.readFloat();
data.limit = ((flags & 64) != 0 ? input.readFloat() : 5000) * scale; data.limit = ((flags & 64) != 0 ? input.readFloat() : 5000) * scale;
data.step = .1 / input.readUnsignedByte(); data.step = .1 / input.readUnsignedByte();
var setup = data.setup; var setup = data.setup;
@ -366,13 +390,20 @@ class SkeletonBinary {
setup.wind = input.readFloat(); setup.wind = input.readFloat();
setup.gravity = input.readFloat(); setup.gravity = input.readFloat();
flags = input.readByte(); flags = input.readByte();
if ((flags & 1) != 0) data.inertiaGlobal = true; if ((flags & 1) != 0)
if ((flags & 2) != 0) data.strengthGlobal = true; data.inertiaGlobal = true;
if ((flags & 4) != 0) data.dampingGlobal = true; if ((flags & 2) != 0)
if ((flags & 8) != 0) data.massGlobal = true; data.strengthGlobal = true;
if ((flags & 16) != 0) data.windGlobal = true; if ((flags & 4) != 0)
if ((flags & 32) != 0) data.gravityGlobal = true; data.dampingGlobal = true;
if ((flags & 64) != 0) data.mixGlobal = true; if ((flags & 8) != 0)
data.massGlobal = true;
if ((flags & 16) != 0)
data.windGlobal = true;
if ((flags & 32) != 0)
data.gravityGlobal = true;
if ((flags & 64) != 0)
data.mixGlobal = true;
setup.mix = (flags & 128) != 0 ? input.readFloat() : 1; setup.mix = (flags & 128) != 0 ? input.readFloat() : 1;
constraints[i] = data; constraints[i] = data;
case CONSTRAINT_SLIDER: case CONSTRAINT_SLIDER:
@ -381,8 +412,10 @@ class SkeletonBinary {
data.skinRequired = (flags & 1) != 0; data.skinRequired = (flags & 1) != 0;
data.loop = (flags & 2) != 0; data.loop = (flags & 2) != 0;
data.additive = (flags & 4) != 0; data.additive = (flags & 4) != 0;
if ((flags & 8) != 0) data.setup.time = input.readFloat(); if ((flags & 8) != 0)
if ((flags & 16) != 0) data.setup.mix = (flags & 32) != 0 ? input.readFloat() : 1; data.setup.time = input.readFloat();
if ((flags & 16) != 0)
data.setup.mix = (flags & 32) != 0 ? input.readFloat() : 1;
if ((flags & 64) != 0) { if ((flags & 64) != 0) {
data.local = (flags & 128) != 0; data.local = (flags & 128) != 0;
data.bone = bones[input.readInt(true)]; data.bone = bones[input.readInt(true)];
@ -409,7 +442,6 @@ class SkeletonBinary {
} }
} }
// Default skin. // Default skin.
var defaultSkin:Skin = readSkin(input, skeletonData, true, nonessential); var defaultSkin:Skin = readSkin(input, skeletonData, true, nonessential);
if (defaultSkin != null) { if (defaultSkin != null) {
@ -481,7 +513,8 @@ class SkeletonBinary {
} else { } else {
skin = new Skin(input.readString()); skin = new Skin(input.readString());
if (nonessential) skin.color.setFromRgba8888(input.readInt32()); if (nonessential)
skin.color.setFromRgba8888(input.readInt32());
var n:Int; var n:Int;
var from1 = skeletonData.bones; var from1 = skeletonData.bones;
@ -622,7 +655,8 @@ class SkeletonBinary {
return mesh; return mesh;
case AttachmentType.linkedmesh: case AttachmentType.linkedmesh:
path = (flags & 16) != 0 ? input.readStringRef() : name; path = (flags & 16) != 0 ? input.readStringRef() : name;
if (path == null) throw new SpineException("Path of linked mesh must not be null"); if (path == null)
throw new SpineException("Path of linked mesh must not be null");
color = (flags & 32) != 0 ? input.readInt32() : 0xffffffff; color = (flags & 32) != 0 ? input.readInt32() : 0xffffffff;
var sequence = (flags & 64) != 0 ? this.readSequence(input) : null; var sequence = (flags & 64) != 0 ? this.readSequence(input) : null;
var inheritTimelines:Bool = (flags & 128) != 0; var inheritTimelines:Bool = (flags & 128) != 0;
@ -757,11 +791,7 @@ class SkeletonBinary {
var i:Int = 0, n:Int = 0, ii:Int = 0, nn:Int = 0; var i:Int = 0, n:Int = 0, ii:Int = 0, nn:Int = 0;
var index:Int, slotIndex:Int, timelineType:Int, timelineScale:Float; var index:Int, slotIndex:Int, timelineType:Int, timelineScale:Float;
var frameCount:Int, var frameCount:Int, frameLast:Int, frame:Int, bezierCount:Int, bezier:Int;
frameLast:Int,
frame:Int,
bezierCount:Int,
bezier:Int;
var time:Float, time2:Float; var time:Float, time2:Float;
// Slot timelines. // Slot timelines.
@ -1009,19 +1039,26 @@ class SkeletonBinary {
} }
bezierCount = input.readInt(true); bezierCount = input.readInt(true);
switch (timelineType) { switch (timelineType) {
case BONE_ROTATE: readTimeline(input, timelines, new RotateTimeline(frameCount, bezierCount, boneIndex), 1); case BONE_ROTATE:
readTimeline(input, timelines, new RotateTimeline(frameCount, bezierCount, boneIndex), 1);
case BONE_TRANSLATE: // case BONE_TRANSLATE: //
readTimeline2(input, timelines, new TranslateTimeline(frameCount, bezierCount, boneIndex), scale); readTimeline2(input, timelines, new TranslateTimeline(frameCount, bezierCount, boneIndex), scale);
case BONE_TRANSLATEX: // case BONE_TRANSLATEX: //
readTimeline(input, timelines, new TranslateXTimeline(frameCount, bezierCount, boneIndex), scale); readTimeline(input, timelines, new TranslateXTimeline(frameCount, bezierCount, boneIndex), scale);
case BONE_TRANSLATEY: // case BONE_TRANSLATEY: //
readTimeline(input, timelines, new TranslateYTimeline(frameCount, bezierCount, boneIndex), scale); readTimeline(input, timelines, new TranslateYTimeline(frameCount, bezierCount, boneIndex), scale);
case BONE_SCALE: readTimeline2(input, timelines, new ScaleTimeline(frameCount, bezierCount, boneIndex), 1); case BONE_SCALE:
case BONE_SCALEX: readTimeline(input, timelines, new ScaleXTimeline(frameCount, bezierCount, boneIndex), 1); readTimeline2(input, timelines, new ScaleTimeline(frameCount, bezierCount, boneIndex), 1);
case BONE_SCALEY: readTimeline(input, timelines, new ScaleYTimeline(frameCount, bezierCount, boneIndex), 1); case BONE_SCALEX:
case BONE_SHEAR: readTimeline2(input, timelines, new ShearTimeline(frameCount, bezierCount, boneIndex), 1); readTimeline(input, timelines, new ScaleXTimeline(frameCount, bezierCount, boneIndex), 1);
case BONE_SHEARX: readTimeline(input, timelines, new ShearXTimeline(frameCount, bezierCount, boneIndex), 1); case BONE_SCALEY:
case BONE_SHEARY: readTimeline(input, timelines, new ShearYTimeline(frameCount, bezierCount, boneIndex), 1); readTimeline(input, timelines, new ScaleYTimeline(frameCount, bezierCount, boneIndex), 1);
case BONE_SHEAR:
readTimeline2(input, timelines, new ShearTimeline(frameCount, bezierCount, boneIndex), 1);
case BONE_SHEARX:
readTimeline(input, timelines, new ShearXTimeline(frameCount, bezierCount, boneIndex), 1);
case BONE_SHEARY:
readTimeline(input, timelines, new ShearYTimeline(frameCount, bezierCount, boneIndex), 1);
} }
} }
} }
@ -1094,7 +1131,8 @@ class SkeletonBinary {
mixScaleY2:Float = input.readFloat(), mixScaleY2:Float = input.readFloat(),
mixShearY2:Float = input.readFloat(); mixShearY2:Float = input.readFloat();
switch (input.readByte()) { switch (input.readByte()) {
case CURVE_STEPPED: transformTimeline.setStepped(frame); case CURVE_STEPPED:
transformTimeline.setStepped(frame);
case CURVE_BEZIER: case CURVE_BEZIER:
setBezier(input, transformTimeline, bezier++, frame, 0, time, time2, mixRotate, mixRotate2, 1); setBezier(input, transformTimeline, bezier++, frame, 0, time, time2, mixRotate, mixRotate2, 1);
setBezier(input, transformTimeline, bezier++, frame, 1, time, time2, mixX, mixX2, 1); setBezier(input, transformTimeline, bezier++, frame, 1, time, time2, mixX, mixX2, 1);
@ -1122,15 +1160,16 @@ class SkeletonBinary {
index = input.readInt(true); index = input.readInt(true);
var data = cast(skeletonData.constraints[index], PathConstraintData); var data = cast(skeletonData.constraints[index], PathConstraintData);
for (ii in 0...input.readInt(true)) { for (ii in 0...input.readInt(true)) {
var type:Int = input.readByte(), frameCount:Int = input.readInt(true), bezierCount:Int = input.readInt(true); var type:Int = input.readByte(),
frameCount:Int = input.readInt(true),
bezierCount:Int = input.readInt(true);
switch (type) { switch (type) {
case PATH_POSITION: case PATH_POSITION:
readTimeline(input, timelines, new PathConstraintPositionTimeline(frameCount, bezierCount, index), readTimeline(input, timelines, new PathConstraintPositionTimeline(frameCount, bezierCount, index),
data.positionMode == PositionMode.fixed ? scale : 1); data.positionMode == PositionMode.fixed ? scale : 1);
case PATH_SPACING: case PATH_SPACING:
readTimeline(input, timelines, new PathConstraintSpacingTimeline(frameCount, bezierCount, index), readTimeline(input, timelines,
data.spacingMode == SpacingMode.length new PathConstraintSpacingTimeline(frameCount, bezierCount, index), data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed ? scale : 1);
|| data.spacingMode == SpacingMode.fixed ? scale : 1);
case PATH_MIX: case PATH_MIX:
var mixTimeline:PathConstraintMixTimeline = new PathConstraintMixTimeline(frameCount, bezierCount, index); var mixTimeline:PathConstraintMixTimeline = new PathConstraintMixTimeline(frameCount, bezierCount, index);
time = input.readFloat(); time = input.readFloat();
@ -1172,7 +1211,8 @@ class SkeletonBinary {
for (i in 0...input.readInt(true)) { for (i in 0...input.readInt(true)) {
var constraintIndex:Int = input.readInt(true) - 1; var constraintIndex:Int = input.readInt(true) - 1;
for (ii in 0...input.readInt(true)) { for (ii in 0...input.readInt(true)) {
var type:Int = input.readByte(), frameCount:Int = input.readInt(true); var type:Int = input.readByte(),
frameCount:Int = input.readInt(true);
if (type == PHYSICS_RESET) { if (type == PHYSICS_RESET) {
var timeline:PhysicsConstraintResetTimeline = new PhysicsConstraintResetTimeline(frameCount, constraintIndex); var timeline:PhysicsConstraintResetTimeline = new PhysicsConstraintResetTimeline(frameCount, constraintIndex);
for (frame in 0...frameCount) for (frame in 0...frameCount)
@ -1183,14 +1223,22 @@ class SkeletonBinary {
var bezierCount = input.readInt(true); var bezierCount = input.readInt(true);
var timeline:CurveTimeline1; var timeline:CurveTimeline1;
switch (type) { switch (type) {
case PHYSICS_INERTIA: timeline = new PhysicsConstraintInertiaTimeline(frameCount, bezierCount, constraintIndex); case PHYSICS_INERTIA:
case PHYSICS_STRENGTH: timeline = new PhysicsConstraintStrengthTimeline(frameCount, bezierCount, constraintIndex); timeline = new PhysicsConstraintInertiaTimeline(frameCount, bezierCount, constraintIndex);
case PHYSICS_DAMPING: timeline = new PhysicsConstraintDampingTimeline(frameCount, bezierCount, constraintIndex); case PHYSICS_STRENGTH:
case PHYSICS_MASS: timeline = new PhysicsConstraintMassTimeline(frameCount, bezierCount, constraintIndex); timeline = new PhysicsConstraintStrengthTimeline(frameCount, bezierCount, constraintIndex);
case PHYSICS_WIND: timeline = new PhysicsConstraintWindTimeline(frameCount, bezierCount, constraintIndex); case PHYSICS_DAMPING:
case PHYSICS_GRAVITY: timeline = new PhysicsConstraintGravityTimeline(frameCount, bezierCount, constraintIndex); timeline = new PhysicsConstraintDampingTimeline(frameCount, bezierCount, constraintIndex);
case PHYSICS_MIX: timeline = new PhysicsConstraintMixTimeline(frameCount, bezierCount, constraintIndex); case PHYSICS_MASS:
default: throw new SpineException("Unknown physics timeline type: " + type); timeline = new PhysicsConstraintMassTimeline(frameCount, bezierCount, constraintIndex);
case PHYSICS_WIND:
timeline = new PhysicsConstraintWindTimeline(frameCount, bezierCount, constraintIndex);
case PHYSICS_GRAVITY:
timeline = new PhysicsConstraintGravityTimeline(frameCount, bezierCount, constraintIndex);
case PHYSICS_MIX:
timeline = new PhysicsConstraintMixTimeline(frameCount, bezierCount, constraintIndex);
default:
throw new SpineException("Unknown physics timeline type: " + type);
} }
readTimeline(input, timelines, timeline, 1); readTimeline(input, timelines, timeline, 1);
} }
@ -1200,12 +1248,17 @@ class SkeletonBinary {
for (i in 0...input.readInt(true)) { for (i in 0...input.readInt(true)) {
var index = input.readInt(true); var index = input.readInt(true);
for (ii in 0...input.readInt(true)) { for (ii in 0...input.readInt(true)) {
var type = input.readByte(), frameCount = input.readInt(true), bezierCount = input.readInt(true); var type = input.readByte(),
frameCount = input.readInt(true),
bezierCount = input.readInt(true);
var timeline:CurveTimeline1; var timeline:CurveTimeline1;
switch (type) { switch (type) {
case SLIDER_TIME: timeline = new SliderTimeline(frameCount, bezierCount, index); case SLIDER_TIME:
case SLIDER_MIX: timeline = new SliderMixTimeline(frameCount, bezierCount, index); timeline = new SliderTimeline(frameCount, bezierCount, index);
default: throw new SpineException("Unknown slider timeline type: " + type); case SLIDER_MIX:
timeline = new SliderMixTimeline(frameCount, bezierCount, index);
default:
throw new SpineException("Unknown slider timeline type: " + type);
} }
readTimeline(input, timelines, timeline, 1); readTimeline(input, timelines, timeline, 1);
} }
@ -1350,7 +1403,8 @@ class SkeletonBinary {
event.intValue = input.readInt(false); event.intValue = input.readInt(false);
event.floatValue = input.readFloat(); event.floatValue = input.readFloat();
event.stringValue = input.readString(); event.stringValue = input.readString();
if (event.stringValue == null) event.stringValue = eventData.stringValue; if (event.stringValue == null)
event.stringValue = eventData.stringValue;
if (event.data.audioPath != null) { if (event.data.audioPath != null) {
event.volume = input.readFloat(); event.volume = input.readFloat();
event.balance = input.readFloat(); event.balance = input.readFloat();
@ -1370,9 +1424,7 @@ class SkeletonBinary {
var time:Float = input.readFloat(), var time:Float = input.readFloat(),
value:Float = input.readFloat() * scale; value:Float = input.readFloat() * scale;
var frame:Int = 0, var frame:Int = 0, bezier:Int = 0, frameLast:Int = timeline.getFrameCount() - 1;
bezier:Int = 0,
frameLast:Int = timeline.getFrameCount() - 1;
while (true) { while (true) {
timeline.setFrame(frame, time, value); timeline.setFrame(frame, time, value);
if (frame == frameLast) if (frame == frameLast)
@ -1381,8 +1433,10 @@ class SkeletonBinary {
var time2:Float = input.readFloat(), var time2:Float = input.readFloat(),
value2:Float = input.readFloat() * scale; value2:Float = input.readFloat() * scale;
switch (input.readByte()) { switch (input.readByte()) {
case CURVE_STEPPED: timeline.setStepped(frame); case CURVE_STEPPED:
case CURVE_BEZIER: setBezier(input, timeline, bezier++, frame, 0, time, time2, value, value2, scale); timeline.setStepped(frame);
case CURVE_BEZIER:
setBezier(input, timeline, bezier++, frame, 0, time, time2, value, value2, scale);
} }
time = time2; time = time2;
value = value2; value = value2;
@ -1397,9 +1451,7 @@ class SkeletonBinary {
value1:Float = input.readFloat() * scale, value1:Float = input.readFloat() * scale,
value2:Float = input.readFloat() * scale; value2:Float = input.readFloat() * scale;
var frame:Int = 0, var frame:Int = 0, bezier:Int = 0, frameLast:Int = timeline.getFrameCount() - 1;
bezier:Int = 0,
frameLast:Int = timeline.getFrameCount() - 1;
while (true) { while (true) {
timeline.setFrame(frame, time, value1, value2); timeline.setFrame(frame, time, value1, value2);
if (frame == frameLast) if (frame == frameLast)
@ -1409,7 +1461,8 @@ class SkeletonBinary {
nvalue1:Float = input.readFloat() * scale, nvalue1:Float = input.readFloat() * scale,
nvalue2:Float = input.readFloat() * scale; nvalue2:Float = input.readFloat() * scale;
switch (input.readByte()) { switch (input.readByte()) {
case CURVE_STEPPED: timeline.setStepped(frame); case CURVE_STEPPED:
timeline.setStepped(frame);
case CURVE_BEZIER: case CURVE_BEZIER:
setBezier(input, timeline, bezier++, frame, 0, time, time2, value1, nvalue1, scale); setBezier(input, timeline, bezier++, frame, 0, time, time2, value1, nvalue1, scale);
setBezier(input, timeline, bezier++, frame, 1, time, time2, value2, nvalue2, scale); setBezier(input, timeline, bezier++, frame, 1, time, time2, value2, nvalue2, scale);

View File

@ -48,9 +48,11 @@ class SkeletonClipping {
public function new() {} public function new() {}
public function clipStart(skeleton:Skeleton, slot:Slot, clip:ClippingAttachment):Int { public function clipStart(skeleton:Skeleton, slot:Slot, clip:ClippingAttachment):Int {
if (clipAttachment != null) return 0; if (clipAttachment != null)
return 0;
var n = clip.worldVerticesLength; var n = clip.worldVerticesLength;
if (n < 6) return 0; if (n < 6)
return 0;
clipAttachment = clip; clipAttachment = clip;
clippingPolygon.resize(n); clippingPolygon.resize(n);
@ -66,7 +68,8 @@ class SkeletonClipping {
} }
public function clipEnd(?slot:Slot):Void { public function clipEnd(?slot:Slot):Void {
if (clipAttachment == null || (slot != null && clipAttachment.endSlot != slot.data)) return; if (clipAttachment == null || (slot != null && clipAttachment.endSlot != slot.data))
return;
clipAttachment = null; clipAttachment = null;
clippingPolygons = null; clippingPolygons = null;
clippedVertices.resize(0); clippedVertices.resize(0);
@ -203,7 +206,8 @@ class SkeletonClipping {
var ii:Int = 0; var ii:Int = 0;
while (ii < clipOutputLength) { while (ii < clipOutputLength) {
var x = clipOutputItems[ii], y = clipOutputItems[ii + 1]; var x = clipOutputItems[ii],
y = clipOutputItems[ii + 1];
clippedVerticesItems[s] = x; clippedVerticesItems[s] = x;
clippedVerticesItems[s + 1] = y; clippedVerticesItems[s + 1] = y;
var c0 = x - x3, c1 = y - y3; var c0 = x - x3, c1 = y - y3;

View File

@ -91,6 +91,7 @@ class SkeletonData {
public var hash:String; public var hash:String;
// Nonessential. // Nonessential.
/** The dopesheet FPS in Spine, or zero if nonessential data was not exported. */ /** The dopesheet FPS in Spine, or zero if nonessential data was not exported. */
public var fps:Float = 0; public var fps:Float = 0;
@ -123,9 +124,11 @@ class SkeletonData {
* @param boneName The name of the bone to find. * @param boneName The name of the bone to find.
* @return May be null. */ * @return May be null. */
public function findBone(boneName:String):BoneData { public function findBone(boneName:String):BoneData {
if (boneName == null) throw new SpineException("boneName cannot be null."); if (boneName == null)
throw new SpineException("boneName cannot be null.");
for (bone in bones) for (bone in bones)
if (bone.name == boneName) return bone; if (bone.name == boneName)
return bone;
return null; return null;
} }
@ -149,9 +152,11 @@ class SkeletonData {
* @param slotName The name of the slot to find. * @param slotName The name of the slot to find.
* @return May be null. */ * @return May be null. */
public function findSlot(slotName:String):SlotData { public function findSlot(slotName:String):SlotData {
if (slotName == null) throw new SpineException("slotName cannot be null."); if (slotName == null)
throw new SpineException("slotName cannot be null.");
for (slot in slots) for (slot in slots)
if (slot.name == slotName) return slot; if (slot.name == slotName)
return slot;
return null; return null;
} }
@ -162,9 +167,11 @@ class SkeletonData {
* @param skinName The name of the skin to find. * @param skinName The name of the skin to find.
* @return May be null. */ * @return May be null. */
public function findSkin(skinName:String):Skin { public function findSkin(skinName:String):Skin {
if (skinName == null) throw new SpineException("skinName cannot be null."); if (skinName == null)
throw new SpineException("skinName cannot be null.");
for (skin in skins) for (skin in skins)
if (skin.name == skinName) return skin; if (skin.name == skinName)
return skin;
return null; return null;
} }
@ -175,9 +182,11 @@ class SkeletonData {
* @param eventName The name of the event to find. * @param eventName The name of the event to find.
* @return May be null. */ * @return May be null. */
public function findEvent(eventName:String):EventData { public function findEvent(eventName:String):EventData {
if (eventName == null) throw new SpineException("eventName cannot be null."); if (eventName == null)
throw new SpineException("eventName cannot be null.");
for (eventData in events) for (eventData in events)
if (eventData.name == eventName) return eventData; if (eventData.name == eventName)
return eventData;
return null; return null;
} }
@ -188,17 +197,21 @@ class SkeletonData {
* @param animationName The name of the animation to find. * @param animationName The name of the animation to find.
* @return May be null. */ * @return May be null. */
public function findAnimation(animationName:String):Animation { public function findAnimation(animationName:String):Animation {
if (animationName == null) throw new SpineException("animationName cannot be null."); if (animationName == null)
throw new SpineException("animationName cannot be null.");
for (animation in animations) for (animation in animations)
if (animation.name == animationName) return animation; if (animation.name == animationName)
return animation;
return null; return null;
} }
// --- Constraints. // --- Constraints.
public function findConstraint<T:ConstraintData<Dynamic, Dynamic>>(constraintName:String, type:Class<T>):T { public function findConstraint<T:ConstraintData<Dynamic, Dynamic>>(constraintName:String, type:Class<T>):T {
if (constraintName == null) throw new SpineException("constraintName cannot be null."); if (constraintName == null)
if (type == null) throw new SpineException("type cannot be null."); throw new SpineException("constraintName cannot be null.");
if (type == null)
throw new SpineException("type cannot be null.");
for (constraint in constraints) { for (constraint in constraints) {
if (Std.isOfType(constraint, type) && constraint.name == constraintName) if (Std.isOfType(constraint, type) && constraint.name == constraintName)

View File

@ -140,7 +140,8 @@ class SkeletonJson {
data.skinRequired = Reflect.hasField(boneMap, "skin") ? cast(Reflect.getProperty(boneMap, "skin"), Bool) : false; data.skinRequired = Reflect.hasField(boneMap, "skin") ? cast(Reflect.getProperty(boneMap, "skin"), Bool) : false;
var color:String = Reflect.getProperty(boneMap, "color"); var color:String = Reflect.getProperty(boneMap, "color");
if (color != null) data.color.setFromString(color); if (color != null)
data.color.setFromString(color);
skeletonData.bones.push(data); skeletonData.bones.push(data);
} }
@ -150,15 +151,18 @@ class SkeletonJson {
var slotName:String = Reflect.getProperty(slotMap, "name"); var slotName:String = Reflect.getProperty(slotMap, "name");
var boneName:String = Reflect.getProperty(slotMap, "bone"); var boneName:String = Reflect.getProperty(slotMap, "bone");
var boneData = skeletonData.findBone(boneName); var boneData = skeletonData.findBone(boneName);
if (boneData == null) throw new SpineException("Slot bone not found: " + boneName); if (boneData == null)
throw new SpineException("Slot bone not found: " + boneName);
var data = new SlotData(skeletonData.slots.length, slotName, boneData); var data = new SlotData(skeletonData.slots.length, slotName, boneData);
var color:String = Reflect.getProperty(slotMap, "color"); var color:String = Reflect.getProperty(slotMap, "color");
if (color != null) data.setup.color.setFromString(color); if (color != null)
data.setup.color.setFromString(color);
var dark:String = Reflect.getProperty(slotMap, "dark"); var dark:String = Reflect.getProperty(slotMap, "dark");
if (dark != null) data.setup.darkColor = new Color(0, 0, 0).setFromString(dark); if (dark != null)
data.setup.darkColor = new Color(0, 0, 0).setFromString(dark);
data.attachmentName = Reflect.getProperty(slotMap, "attachment"); data.attachmentName = Reflect.getProperty(slotMap, "attachment");
data.blendMode = Reflect.hasField(slotMap, "blend") ? BlendMode.fromName(Reflect.getProperty(slotMap, "blend")) : BlendMode.normal; data.blendMode = Reflect.hasField(slotMap, "blend") ? BlendMode.fromName(Reflect.getProperty(slotMap, "blend")) : BlendMode.normal;
@ -179,20 +183,26 @@ class SkeletonJson {
for (boneName in cast(Reflect.getProperty(constraintMap, "bones"), Array<Dynamic>)) { for (boneName in cast(Reflect.getProperty(constraintMap, "bones"), Array<Dynamic>)) {
var bone = skeletonData.findBone(boneName); var bone = skeletonData.findBone(boneName);
if (bone == null) throw new SpineException("IK constraint bone not found: " + boneName); if (bone == null)
throw new SpineException("IK constraint bone not found: " + boneName);
data.bones.push(bone); data.bones.push(bone);
} }
data.target = skeletonData.findBone(Reflect.getProperty(constraintMap, "target")); data.target = skeletonData.findBone(Reflect.getProperty(constraintMap, "target"));
if (data.target == null) throw new SpineException("Target bone not found: " + Reflect.getProperty(constraintMap, "target")); if (data.target == null)
throw new SpineException("Target bone not found: " + Reflect.getProperty(constraintMap, "target"));
data.uniform = (Reflect.hasField(constraintMap, "uniform") && cast(Reflect.getProperty(constraintMap, "uniform"), Bool)); data.uniform = (Reflect.hasField(constraintMap, "uniform")
&& cast(Reflect.getProperty(constraintMap, "uniform"), Bool));
var setup = data.setup; var setup = data.setup;
setup.mix = getFloat(constraintMap, "mix", 1); setup.mix = getFloat(constraintMap, "mix", 1);
setup.softness = getFloat(constraintMap, "softness", 0) * scale; setup.softness = getFloat(constraintMap, "softness", 0) * scale;
setup.bendDirection = (!Reflect.hasField(constraintMap, "bendPositive") || cast(Reflect.getProperty(constraintMap, "bendPositive"), Bool)) ? 1 : -1; setup.bendDirection = (!Reflect.hasField(constraintMap, "bendPositive")
setup.compress = (Reflect.hasField(constraintMap, "compress") && cast(Reflect.getProperty(constraintMap, "compress"), Bool)); || cast(Reflect.getProperty(constraintMap, "bendPositive"), Bool)) ? 1 : -1;
setup.stretch = (Reflect.hasField(constraintMap, "stretch") && cast(Reflect.getProperty(constraintMap, "stretch"), Bool)); setup.compress = (Reflect.hasField(constraintMap, "compress")
&& cast(Reflect.getProperty(constraintMap, "compress"), Bool));
setup.stretch = (Reflect.hasField(constraintMap, "stretch")
&& cast(Reflect.getProperty(constraintMap, "stretch"), Bool));
skeletonData.constraints.push(data); skeletonData.constraints.push(data);
case "transform": case "transform":
@ -201,15 +211,19 @@ class SkeletonJson {
for (boneName in cast(Reflect.getProperty(constraintMap, "bones"), Array<Dynamic>)) { for (boneName in cast(Reflect.getProperty(constraintMap, "bones"), Array<Dynamic>)) {
var bone = skeletonData.findBone(boneName); var bone = skeletonData.findBone(boneName);
if (bone == null) throw new SpineException("Transform constraint bone not found: " + boneName); if (bone == null)
throw new SpineException("Transform constraint bone not found: " + boneName);
data.bones.push(bone); data.bones.push(bone);
} }
data.source = skeletonData.findBone(Reflect.getProperty(constraintMap, "source")); data.source = skeletonData.findBone(Reflect.getProperty(constraintMap, "source"));
if (data.source == null) throw new SpineException("Transform constraint source bone not found: " + Reflect.getProperty(constraintMap, "source")); if (data.source == null)
throw new SpineException("Transform constraint source bone not found: " + Reflect.getProperty(constraintMap, "source"));
data.localSource = Reflect.hasField(constraintMap, "localSource") ? cast(Reflect.getProperty(constraintMap, "localSource"), Bool) : false; data.localSource = Reflect.hasField(constraintMap,
data.localTarget = Reflect.hasField(constraintMap, "localTarget") ? cast(Reflect.getProperty(constraintMap, "localTarget"), Bool) : false; "localSource") ? cast(Reflect.getProperty(constraintMap, "localSource"), Bool) : false;
data.localTarget = Reflect.hasField(constraintMap,
"localTarget") ? cast(Reflect.getProperty(constraintMap, "localTarget"), Bool) : false;
data.additive = Reflect.hasField(constraintMap, "additive") ? cast(Reflect.getProperty(constraintMap, "additive"), Bool) : false; data.additive = Reflect.hasField(constraintMap, "additive") ? cast(Reflect.getProperty(constraintMap, "additive"), Bool) : false;
data.clamp = Reflect.hasField(constraintMap, "clamp") ? cast(Reflect.getProperty(constraintMap, "clamp"), Bool) : false; data.clamp = Reflect.hasField(constraintMap, "clamp") ? cast(Reflect.getProperty(constraintMap, "clamp"), Bool) : false;
@ -259,7 +273,8 @@ class SkeletonJson {
to.scale = getFloat(toEntry, "scale") * toScale / fromScale; to.scale = getFloat(toEntry, "scale") * toScale / fromScale;
from.to.push(to); from.to.push(to);
} }
if (from.to.length > 0) data.properties.push(from); if (from.to.length > 0)
data.properties.push(from);
} }
data.offsets[TransformConstraintData.ROTATION] = getFloat(constraintMap, "rotation", 0); data.offsets[TransformConstraintData.ROTATION] = getFloat(constraintMap, "rotation", 0);
@ -270,12 +285,18 @@ class SkeletonJson {
data.offsets[TransformConstraintData.SHEARY] = getFloat(constraintMap, "shearY", 0); data.offsets[TransformConstraintData.SHEARY] = getFloat(constraintMap, "shearY", 0);
var setup = data.setup; var setup = data.setup;
if (rotate) setup.mixRotate = getFloat(constraintMap, "mixRotate", 1); if (rotate)
if (x) setup.mixX = getFloat(constraintMap, "mixX", 1); setup.mixRotate = getFloat(constraintMap, "mixRotate", 1);
if (y) setup.mixY = getFloat(constraintMap, "mixY", setup.mixX); if (x)
if (scaleX) setup.mixScaleX = getFloat(constraintMap, "mixScaleX", 1); setup.mixX = getFloat(constraintMap, "mixX", 1);
if (scaleY) setup.mixScaleY = getFloat(constraintMap, "mixScaleY", setup.mixScaleX); if (y)
if (shearY) setup.mixShearY = getFloat(constraintMap, "mixShearY", 1); setup.mixY = getFloat(constraintMap, "mixY", setup.mixX);
if (scaleX)
setup.mixScaleX = getFloat(constraintMap, "mixScaleX", 1);
if (scaleY)
setup.mixScaleY = getFloat(constraintMap, "mixScaleY", setup.mixScaleX);
if (shearY)
setup.mixShearY = getFloat(constraintMap, "mixShearY", 1);
skeletonData.constraints.push(data); skeletonData.constraints.push(data);
case "path": case "path":
@ -284,23 +305,30 @@ class SkeletonJson {
for (boneName in cast(Reflect.getProperty(constraintMap, "bones"), Array<Dynamic>)) { for (boneName in cast(Reflect.getProperty(constraintMap, "bones"), Array<Dynamic>)) {
var bone = skeletonData.findBone(boneName); var bone = skeletonData.findBone(boneName);
if (bone == null) throw new SpineException("Path bone not found: " + boneName); if (bone == null)
throw new SpineException("Path bone not found: " + boneName);
data.bones.push(bone); data.bones.push(bone);
} }
var slotName = getString(constraintMap, "slot", ""); var slotName = getString(constraintMap, "slot", "");
data.slot = skeletonData.findSlot(slotName); data.slot = skeletonData.findSlot(slotName);
if (data.slot == null) throw new SpineException("Path slot not found: " + slotName); if (data.slot == null)
throw new SpineException("Path slot not found: " + slotName);
data.positionMode = Reflect.hasField(constraintMap, "positionMode") ? PositionMode.fromName(Reflect.getProperty(constraintMap, "positionMode")) : PositionMode.percent; data.positionMode = Reflect.hasField(constraintMap,
data.spacingMode = Reflect.hasField(constraintMap, "spacingMode") ? SpacingMode.fromName(Reflect.getProperty(constraintMap, "spacingMode")) : SpacingMode.length; "positionMode") ? PositionMode.fromName(Reflect.getProperty(constraintMap, "positionMode")) : PositionMode.percent;
data.rotateMode = Reflect.hasField(constraintMap, "rotateMode") ? RotateMode.fromName(Reflect.getProperty(constraintMap, "rotateMode")) : RotateMode.tangent; data.spacingMode = Reflect.hasField(constraintMap,
"spacingMode") ? SpacingMode.fromName(Reflect.getProperty(constraintMap, "spacingMode")) : SpacingMode.length;
data.rotateMode = Reflect.hasField(constraintMap,
"rotateMode") ? RotateMode.fromName(Reflect.getProperty(constraintMap, "rotateMode")) : RotateMode.tangent;
data.offsetRotation = getFloat(constraintMap, "rotation", 0); data.offsetRotation = getFloat(constraintMap, "rotation", 0);
var setup = data.setup; var setup = data.setup;
setup.position = getFloat(constraintMap, "position", 0); setup.position = getFloat(constraintMap, "position", 0);
if (data.positionMode == PositionMode.fixed) setup.position *= scale; if (data.positionMode == PositionMode.fixed)
setup.position *= scale;
setup.spacing = getFloat(constraintMap, "spacing", 0); setup.spacing = getFloat(constraintMap, "spacing", 0);
if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed) setup.spacing *= scale; if (data.spacingMode == SpacingMode.length || data.spacingMode == SpacingMode.fixed)
setup.spacing *= scale;
setup.mixRotate = getFloat(constraintMap, "mixRotate", 1); setup.mixRotate = getFloat(constraintMap, "mixRotate", 1);
setup.mixX = getFloat(constraintMap, "mixX", 1); setup.mixX = getFloat(constraintMap, "mixX", 1);
setup.mixY = getFloat(constraintMap, "mixY", setup.mixX); setup.mixY = getFloat(constraintMap, "mixY", setup.mixX);
@ -312,7 +340,8 @@ class SkeletonJson {
var boneName:String = getString(constraintMap, "bone"); var boneName:String = getString(constraintMap, "bone");
data.bone = skeletonData.findBone(boneName); data.bone = skeletonData.findBone(boneName);
if (data.bone == null) throw new SpineException("Physics bone not found: " + boneName); if (data.bone == null)
throw new SpineException("Physics bone not found: " + boneName);
data.x = getFloat(constraintMap, "x"); data.x = getFloat(constraintMap, "x");
data.y = getFloat(constraintMap, "y"); data.y = getFloat(constraintMap, "y");
@ -329,12 +358,17 @@ class SkeletonJson {
setup.wind = getFloat(constraintMap, "wind", 0); setup.wind = getFloat(constraintMap, "wind", 0);
setup.gravity = getFloat(constraintMap, "gravity", 0); setup.gravity = getFloat(constraintMap, "gravity", 0);
setup.mix = getValue(constraintMap, "mix", 1); setup.mix = getValue(constraintMap, "mix", 1);
data.inertiaGlobal = Reflect.hasField(constraintMap, "inertiaGlobal") ? cast(Reflect.getProperty(constraintMap, "inertiaGlobal"), Bool) : false; data.inertiaGlobal = Reflect.hasField(constraintMap,
data.strengthGlobal = Reflect.hasField(constraintMap, "strengthGlobal") ? cast(Reflect.getProperty(constraintMap, "strengthGlobal"), Bool) : false; "inertiaGlobal") ? cast(Reflect.getProperty(constraintMap, "inertiaGlobal"), Bool) : false;
data.dampingGlobal = Reflect.hasField(constraintMap, "dampingGlobal") ? cast(Reflect.getProperty(constraintMap, "dampingGlobal"), Bool) : false; data.strengthGlobal = Reflect.hasField(constraintMap,
data.dampingGlobal = Reflect.hasField(constraintMap, "dampingGlobal") ? cast(Reflect.getProperty(constraintMap, "dampingGlobal"), Bool) : false; "strengthGlobal") ? cast(Reflect.getProperty(constraintMap, "strengthGlobal"), Bool) : false;
data.dampingGlobal = Reflect.hasField(constraintMap,
"dampingGlobal") ? cast(Reflect.getProperty(constraintMap, "dampingGlobal"), Bool) : false;
data.dampingGlobal = Reflect.hasField(constraintMap,
"dampingGlobal") ? cast(Reflect.getProperty(constraintMap, "dampingGlobal"), Bool) : false;
data.windGlobal = Reflect.hasField(constraintMap, "windGlobal") ? cast(Reflect.getProperty(constraintMap, "windGlobal"), Bool) : false; data.windGlobal = Reflect.hasField(constraintMap, "windGlobal") ? cast(Reflect.getProperty(constraintMap, "windGlobal"), Bool) : false;
data.gravityGlobal = Reflect.hasField(constraintMap, "gravityGlobal") ? cast(Reflect.getProperty(constraintMap, "gravityGlobal"), Bool) : false; data.gravityGlobal = Reflect.hasField(constraintMap,
"gravityGlobal") ? cast(Reflect.getProperty(constraintMap, "gravityGlobal"), Bool) : false;
data.mixGlobal = Reflect.hasField(constraintMap, "mixGlobal") ? cast(Reflect.getProperty(constraintMap, "mixGlobal"), Bool) : false; data.mixGlobal = Reflect.hasField(constraintMap, "mixGlobal") ? cast(Reflect.getProperty(constraintMap, "mixGlobal"), Bool) : false;
skeletonData.constraints.push(data); skeletonData.constraints.push(data);
@ -349,7 +383,8 @@ class SkeletonJson {
var boneName = getString(constraintMap, "bone", null); var boneName = getString(constraintMap, "bone", null);
if (boneName != null) { if (boneName != null) {
data.bone = skeletonData.findBone(boneName); data.bone = skeletonData.findBone(boneName);
if (data.bone == null) throw new SpineException("Slider bone not found: " + boneName); if (data.bone == null)
throw new SpineException("Slider bone not found: " + boneName);
var property = getString(constraintMap, "property"); var property = getString(constraintMap, "property");
data.property = fromProperty(property); data.property = fromProperty(property);
var propertyScale = propertyScale(property, scale); var propertyScale = propertyScale(property, scale);
@ -364,7 +399,6 @@ class SkeletonJson {
} }
} }
// Skins. // Skins.
if (Reflect.hasField(root, "skins")) { if (Reflect.hasField(root, "skins")) {
for (skinMap in cast(Reflect.getProperty(root, "skins"), Array<Dynamic>)) { for (skinMap in cast(Reflect.getProperty(root, "skins"), Array<Dynamic>)) {
@ -424,7 +458,8 @@ class SkeletonJson {
var slider = cast(Reflect.getProperty(skinMap, "slider"), Array<Dynamic>); var slider = cast(Reflect.getProperty(skinMap, "slider"), Array<Dynamic>);
for (ii in 0...slider.length) { for (ii in 0...slider.length) {
var constraint = skeletonData.findConstraint(slider[ii], SliderData); var constraint = skeletonData.findConstraint(slider[ii], SliderData);
if (constraint == null) throw new SpineException("Skin slider constraint not found: " + slider[ii]); if (constraint == null)
throw new SpineException("Skin slider constraint not found: " + slider[ii]);
skin.constraints.push(constraint); skin.constraints.push(constraint);
} }
} }
@ -495,7 +530,8 @@ class SkeletonJson {
var data = skeletonData.findConstraint(getString(constraintMap, "name"), SliderData); var data = skeletonData.findConstraint(getString(constraintMap, "name"), SliderData);
var animationName = getString(constraintMap, "animation", ""); var animationName = getString(constraintMap, "animation", "");
data.animation = skeletonData.findAnimation(animationName); data.animation = skeletonData.findAnimation(animationName);
if (data.animation == null) throw new SpineException("Slider animation not found: " + animationName); if (data.animation == null)
throw new SpineException("Slider animation not found: " + animationName);
} }
} }
} }
@ -506,13 +542,20 @@ class SkeletonJson {
private function fromProperty(type:String):FromProperty { private function fromProperty(type:String):FromProperty {
var property:FromProperty; var property:FromProperty;
switch (type) { switch (type) {
case "rotate": property = new FromRotate(); case "rotate":
case "x": property = new FromX(); property = new FromRotate();
case "y": property = new FromY(); case "x":
case "scaleX": property = new FromScaleX(); property = new FromX();
case "scaleY": property = new FromScaleY(); case "y":
case "shearY": property = new FromShearY(); property = new FromY();
default: throw new SpineException("Invalid from property: " + type); case "scaleX":
property = new FromScaleX();
case "scaleY":
property = new FromScaleY();
case "shearY":
property = new FromShearY();
default:
throw new SpineException("Invalid from property: " + type);
}; };
return property; return property;
} }
@ -520,8 +563,10 @@ class SkeletonJson {
private function propertyScale(type:String, scale:Float):Float { private function propertyScale(type:String, scale:Float):Float {
var scaleValue:Float; var scaleValue:Float;
switch (type) { switch (type) {
case "x", "y": scaleValue = scale; case "x", "y":
default: scaleValue = 1; scaleValue = scale;
default:
scaleValue = 1;
}; };
return scaleValue; return scaleValue;
} }
@ -709,7 +754,8 @@ class SkeletonJson {
slotIndex = skeletonData.findSlot(slotName).index; slotIndex = skeletonData.findSlot(slotName).index;
for (timelineName in Reflect.fields(slotMap)) { for (timelineName in Reflect.fields(slotMap)) {
timelineMap = Reflect.field(slotMap, timelineName); timelineMap = Reflect.field(slotMap, timelineName);
if (timelineMap == null) continue; if (timelineMap == null)
continue;
switch (timelineName) { switch (timelineName) {
case "attachment": case "attachment":
@ -782,7 +828,8 @@ class SkeletonJson {
} }
timelines.push(rgbTimeline); timelines.push(rgbTimeline);
case "alpha": readTimeline(timelines, timelineMap, new AlphaTimeline(timelineMap.length, timelineMap.length, slotIndex), 0, 1); case "alpha":
readTimeline(timelines, timelineMap, new AlphaTimeline(timelineMap.length, timelineMap.length, slotIndex), 0, 1);
case "rgba2": case "rgba2":
var rgba2Timeline = new RGBA2Timeline(timelineMap.length, timelineMap.length * 7, slotIndex); var rgba2Timeline = new RGBA2Timeline(timelineMap.length, timelineMap.length * 7, slotIndex);
@ -862,7 +909,8 @@ class SkeletonJson {
} }
timelines.push(rgb2Timeline); timelines.push(rgb2Timeline);
default: throw new SpineException("Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")"); default:
throw new SpineException("Invalid timeline type for a slot: " + timelineName + " (" + slotName + ")");
} }
} }
} }
@ -871,24 +919,36 @@ class SkeletonJson {
var bones = Reflect.getProperty(map, "bones"); var bones = Reflect.getProperty(map, "bones");
for (boneName in Reflect.fields(bones)) { for (boneName in Reflect.fields(bones)) {
var boneIndex:Int = skeletonData.findBoneIndex(boneName); var boneIndex:Int = skeletonData.findBoneIndex(boneName);
if (boneIndex == -1) throw new SpineException("Bone not found: " + boneName); if (boneIndex == -1)
throw new SpineException("Bone not found: " + boneName);
var boneMap:Dynamic = Reflect.field(bones, boneName); var boneMap:Dynamic = Reflect.field(bones, boneName);
for (timelineName in Reflect.fields(boneMap)) { for (timelineName in Reflect.fields(boneMap)) {
timelineMap = Reflect.field(boneMap, timelineName); timelineMap = Reflect.field(boneMap, timelineName);
var frames = timelineMap.length; var frames = timelineMap.length;
if (frames == 0) continue; if (frames == 0)
continue;
switch (timelineName) { switch (timelineName) {
case "rotate": readTimeline(timelines, timelineMap, new RotateTimeline(frames, frames, boneIndex), 0, 1); case "rotate":
case "translate": readTimeline2(timelines, timelineMap, new TranslateTimeline(frames, frames << 1, boneIndex), "x", "y", 0, scale); readTimeline(timelines, timelineMap, new RotateTimeline(frames, frames, boneIndex), 0, 1);
case "translatex": readTimeline(timelines, timelineMap, new TranslateXTimeline(frames, frames, boneIndex), 0, scale); case "translate":
case "translatey": readTimeline(timelines, timelineMap, new TranslateYTimeline(frames, frames, boneIndex), 0, scale); readTimeline2(timelines, timelineMap, new TranslateTimeline(frames, frames << 1, boneIndex), "x", "y", 0, scale);
case "scale": readTimeline2(timelines, timelineMap, new ScaleTimeline(frames, frames << 1, boneIndex), "x", "y", 1, 1); case "translatex":
case "scalex": readTimeline(timelines, timelineMap, new ScaleXTimeline(frames, frames, boneIndex), 1, 1); readTimeline(timelines, timelineMap, new TranslateXTimeline(frames, frames, boneIndex), 0, scale);
case "scaley": readTimeline(timelines, timelineMap, new ScaleYTimeline(frames, frames, boneIndex), 1, 1); case "translatey":
case "shear": readTimeline2(timelines, timelineMap, new ShearTimeline(frames, frames << 1, boneIndex), "x", "y", 0, 1); readTimeline(timelines, timelineMap, new TranslateYTimeline(frames, frames, boneIndex), 0, scale);
case "shearx": readTimeline(timelines, timelineMap, new ShearXTimeline(frames, frames, boneIndex), 0, 1); case "scale":
case "sheary": readTimeline(timelines, timelineMap, new ShearYTimeline(frames, frames, boneIndex), 0, 1); readTimeline2(timelines, timelineMap, new ScaleTimeline(frames, frames << 1, boneIndex), "x", "y", 1, 1);
case "scalex":
readTimeline(timelines, timelineMap, new ScaleXTimeline(frames, frames, boneIndex), 1, 1);
case "scaley":
readTimeline(timelines, timelineMap, new ScaleYTimeline(frames, frames, boneIndex), 1, 1);
case "shear":
readTimeline2(timelines, timelineMap, new ShearTimeline(frames, frames << 1, boneIndex), "x", "y", 0, 1);
case "shearx":
readTimeline(timelines, timelineMap, new ShearXTimeline(frames, frames, boneIndex), 0, 1);
case "sheary":
readTimeline(timelines, timelineMap, new ShearYTimeline(frames, frames, boneIndex), 0, 1);
case "inherit": case "inherit":
var timeline = new InheritTimeline(frames, boneIndex); var timeline = new InheritTimeline(frames, boneIndex);
for (frame in 0...frames) { for (frame in 0...frames) {
@ -896,7 +956,8 @@ class SkeletonJson {
timeline.setFrame(frame, getFloat(aFrame, "time"), Inherit.fromName(getValue(aFrame, "inherit", "Normal"))); timeline.setFrame(frame, getFloat(aFrame, "time"), Inherit.fromName(getValue(aFrame, "inherit", "Normal")));
} }
timelines.push(timeline); timelines.push(timeline);
default: throw new SpineException("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")"); default:
throw new SpineException("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")");
} }
} }
} }
@ -906,12 +967,13 @@ class SkeletonJson {
for (ikConstraintName in Reflect.fields(iks)) { for (ikConstraintName in Reflect.fields(iks)) {
timelineMap = Reflect.field(iks, ikConstraintName); timelineMap = Reflect.field(iks, ikConstraintName);
keyMap = timelineMap[0]; keyMap = timelineMap[0];
if (keyMap == null) continue; if (keyMap == null)
continue;
var constraint = skeletonData.findConstraint(ikConstraintName, IkConstraintData); var constraint = skeletonData.findConstraint(ikConstraintName, IkConstraintData);
if (constraint == null) throw new SpineException("IK constraint not found: " + ikConstraintName); if (constraint == null)
var timeline = new IkConstraintTimeline(timelineMap.length, timelineMap.length << 1, throw new SpineException("IK constraint not found: " + ikConstraintName);
skeletonData.constraints.indexOf(constraint)); var timeline = new IkConstraintTimeline(timelineMap.length, timelineMap.length << 1, skeletonData.constraints.indexOf(constraint));
time = getFloat(keyMap, "time"); time = getFloat(keyMap, "time");
var mix:Float = getFloat(keyMap, "mix", 1); var mix:Float = getFloat(keyMap, "mix", 1);
@ -955,15 +1017,18 @@ class SkeletonJson {
for (transformName in Reflect.fields(transforms)) { for (transformName in Reflect.fields(transforms)) {
timelineMap = Reflect.field(transforms, transformName); timelineMap = Reflect.field(transforms, transformName);
keyMap = timelineMap[0]; keyMap = timelineMap[0];
if (keyMap == null) continue; if (keyMap == null)
continue;
var constraint = skeletonData.findConstraint(transformName, TransformConstraintData); var constraint = skeletonData.findConstraint(transformName, TransformConstraintData);
if (constraint == null) throw new SpineException("Transform constraint not found: " + transformName); if (constraint == null)
var timeline = new TransformConstraintTimeline(timelineMap.length, timelineMap.length * 6, throw new SpineException("Transform constraint not found: " + transformName);
skeletonData.constraints.indexOf(constraint)); var timeline = new TransformConstraintTimeline(timelineMap.length, timelineMap.length * 6, skeletonData.constraints.indexOf(constraint));
var time = getFloat(keyMap, "time", 0); var time = getFloat(keyMap, "time", 0);
var mixRotate = getFloat(keyMap, "mixRotate", 1); var mixRotate = getFloat(keyMap, "mixRotate", 1);
var mixX = getFloat(keyMap, "mixX", 1), mixY = getFloat(keyMap, "mixY", mixX); var mixX = getFloat(keyMap, "mixX", 1),
var mixScaleX:Float = getFloat(keyMap, "mixScaleX", 1), mixScaleY:Float = getFloat(keyMap, "mixScaleY", 1); mixY = getFloat(keyMap, "mixY", mixX);
var mixScaleX:Float = getFloat(keyMap, "mixScaleX", 1),
mixScaleY:Float = getFloat(keyMap, "mixScaleY", 1);
var mixShearY:Float = getFloat(keyMap, "mixShearY", 1); var mixShearY:Float = getFloat(keyMap, "mixShearY", 1);
frame = 0; frame = 0;
@ -978,8 +1043,10 @@ class SkeletonJson {
var time2 = getFloat(nextMap, "time", 0); var time2 = getFloat(nextMap, "time", 0);
var mixRotate2 = getFloat(nextMap, "mixRotate", 1); var mixRotate2 = getFloat(nextMap, "mixRotate", 1);
var mixX2 = getFloat(nextMap, "mixX", 1), mixY2 = getFloat(nextMap, "mixY", mixX2); var mixX2 = getFloat(nextMap, "mixX", 1),
var mixScaleX2:Float = getFloat(nextMap, "mixScaleX", 1), mixScaleY2:Float = getFloat(nextMap, "mixScaleY", 1); mixY2 = getFloat(nextMap, "mixY", mixX2);
var mixScaleX2:Float = getFloat(nextMap, "mixScaleX", 1),
mixScaleY2:Float = getFloat(nextMap, "mixScaleY", 1);
var mixShearY2:Float = getFloat(nextMap, "mixShearY", 1); var mixShearY2:Float = getFloat(nextMap, "mixShearY", 1);
var curve = keyMap.curve; var curve = keyMap.curve;
if (curve != null) { if (curve != null) {
@ -1009,14 +1076,16 @@ class SkeletonJson {
var paths:Dynamic = Reflect.getProperty(map, "path"); var paths:Dynamic = Reflect.getProperty(map, "path");
for (pathName in Reflect.fields(paths)) { for (pathName in Reflect.fields(paths)) {
var constraint = skeletonData.findConstraint(pathName, PathConstraintData); var constraint = skeletonData.findConstraint(pathName, PathConstraintData);
if (constraint == null) throw new SpineException("Path constraint not found: " + pathName); if (constraint == null)
throw new SpineException("Path constraint not found: " + pathName);
var index = skeletonData.constraints.indexOf(constraint); var index = skeletonData.constraints.indexOf(constraint);
var pathMap:Dynamic = Reflect.field(paths, pathName); var pathMap:Dynamic = Reflect.field(paths, pathName);
for (timelineName in Reflect.fields(pathMap)) { for (timelineName in Reflect.fields(pathMap)) {
timelineMap = Reflect.field(pathMap, timelineName); timelineMap = Reflect.field(pathMap, timelineName);
keyMap = timelineMap[0]; keyMap = timelineMap[0];
if (keyMap == null) continue; if (keyMap == null)
continue;
switch (timelineName) { switch (timelineName) {
case "position": case "position":
@ -1024,8 +1093,8 @@ class SkeletonJson {
readTimeline(timelines, timelineMap, timeline, 0, constraint.positionMode == PositionMode.fixed ? scale : 1); readTimeline(timelines, timelineMap, timeline, 0, constraint.positionMode == PositionMode.fixed ? scale : 1);
case "spacing": case "spacing":
var timeline = new PathConstraintSpacingTimeline(timelineMap.length, timelineMap.length, index); var timeline = new PathConstraintSpacingTimeline(timelineMap.length, timelineMap.length, index);
readTimeline(timelines, timelineMap, timeline, 0, readTimeline(timelines, timelineMap, timeline,
constraint.spacingMode == SpacingMode.length || constraint.spacingMode == SpacingMode.fixed ? scale : 1); 0, constraint.spacingMode == SpacingMode.length || constraint.spacingMode == SpacingMode.fixed ? scale : 1);
case "mix": case "mix":
var timeline = new PathConstraintMixTimeline(timelineMap.length, timelineMap.length * 3, index); var timeline = new PathConstraintMixTimeline(timelineMap.length, timelineMap.length * 3, index);
var time = getFloat(keyMap, "time"); var time = getFloat(keyMap, "time");
@ -1072,14 +1141,16 @@ class SkeletonJson {
var index = -1; var index = -1;
if (physicsName.length > 0) { if (physicsName.length > 0) {
var constraint = skeletonData.findConstraint(physicsName, PhysicsConstraintData); var constraint = skeletonData.findConstraint(physicsName, PhysicsConstraintData);
if (constraint == null) throw new SpineException("Physics constraint not found: " + physicsName); if (constraint == null)
throw new SpineException("Physics constraint not found: " + physicsName);
index = skeletonData.constraints.indexOf(constraint); index = skeletonData.constraints.indexOf(constraint);
} }
var physicsMap:Dynamic = Reflect.field(physics, physicsName); var physicsMap:Dynamic = Reflect.field(physics, physicsName);
for (timelineName in Reflect.fields(physicsMap)) { for (timelineName in Reflect.fields(physicsMap)) {
timelineMap = Reflect.field(physicsMap, timelineName); timelineMap = Reflect.field(physicsMap, timelineName);
keyMap = timelineMap[0]; keyMap = timelineMap[0];
if (keyMap == null) continue; if (keyMap == null)
continue;
var frames = timelineMap.length; var frames = timelineMap.length;
@ -1092,17 +1163,25 @@ class SkeletonJson {
resetTimeline.setFrame(frame, getFloat(keyMap, "time")); resetTimeline.setFrame(frame, getFloat(keyMap, "time"));
timelines.push(resetTimeline); timelines.push(resetTimeline);
continue; continue;
case "inertia": timeline = new PhysicsConstraintInertiaTimeline(frames, frames, index); case "inertia":
case "strength": timeline = new PhysicsConstraintStrengthTimeline(frames, frames, index); timeline = new PhysicsConstraintInertiaTimeline(frames, frames, index);
case "damping": timeline = new PhysicsConstraintDampingTimeline(frames, frames, index); case "strength":
case "mass": timeline = new PhysicsConstraintMassTimeline(frames, frames, index); timeline = new PhysicsConstraintStrengthTimeline(frames, frames, index);
case "wind": timeline = new PhysicsConstraintWindTimeline(frames, frames, index); case "damping":
case "gravity": timeline = new PhysicsConstraintGravityTimeline(frames, frames, index); timeline = new PhysicsConstraintDampingTimeline(frames, frames, index);
case "mix": { case "mass":
timeline = new PhysicsConstraintMassTimeline(frames, frames, index);
case "wind":
timeline = new PhysicsConstraintWindTimeline(frames, frames, index);
case "gravity":
timeline = new PhysicsConstraintGravityTimeline(frames, frames, index);
case "mix":
{
defaultValue = 1; defaultValue = 1;
timeline = new PhysicsConstraintMixTimeline(frames, frames, index); timeline = new PhysicsConstraintMixTimeline(frames, frames, index);
} }
default: continue; default:
continue;
} }
readTimeline(timelines, timelineMap, timeline, defaultValue, 1); readTimeline(timelines, timelineMap, timeline, defaultValue, 1);
} }
@ -1112,18 +1191,22 @@ class SkeletonJson {
var sliders:Dynamic = Reflect.getProperty(map, "slider"); var sliders:Dynamic = Reflect.getProperty(map, "slider");
for (sliderName in Reflect.fields(sliders)) { for (sliderName in Reflect.fields(sliders)) {
var constraint = skeletonData.findConstraint(sliderName, SliderData); var constraint = skeletonData.findConstraint(sliderName, SliderData);
if (constraint == null) throw new SpineException("Slider not found: " + sliderName); if (constraint == null)
throw new SpineException("Slider not found: " + sliderName);
var index = skeletonData.constraints.indexOf(constraint); var index = skeletonData.constraints.indexOf(constraint);
var timelineMap:Dynamic = Reflect.field(sliders, sliderName); var timelineMap:Dynamic = Reflect.field(sliders, sliderName);
for (timelineName in Reflect.fields(timelineMap)) { for (timelineName in Reflect.fields(timelineMap)) {
timelineMap = Reflect.field(timelineMap, timelineName); timelineMap = Reflect.field(timelineMap, timelineName);
keyMap = timelineMap[0]; keyMap = timelineMap[0];
if (keyMap == null) continue; if (keyMap == null)
continue;
var frames = timelineMap.length; var frames = timelineMap.length;
switch (timelineName) { switch (timelineName) {
case "time": readTimeline(timelines, keyMap, new SliderTimeline(frames, frames, index), 1, 1); case "time":
case "mix": readTimeline(timelines, keyMap, new SliderMixTimeline(frames, frames, index), 1, 1); readTimeline(timelines, keyMap, new SliderTimeline(frames, frames, index), 1, 1);
case "mix":
readTimeline(timelines, keyMap, new SliderMixTimeline(frames, frames, index), 1, 1);
} }
} }
} }
@ -1344,8 +1427,8 @@ class SkeletonJson {
} }
} }
static private function readTimeline2(timelines:Array<Timeline>, keys:Array<Dynamic>, timeline:BoneTimeline2, name1:String, name2:String, defaultValue:Float, static private function readTimeline2(timelines:Array<Timeline>, keys:Array<Dynamic>, timeline:BoneTimeline2, name1:String, name2:String,
scale:Float) { defaultValue:Float, scale:Float) {
var keyMap:Dynamic = keys[0]; var keyMap:Dynamic = keys[0];
var time:Float = getFloat(keyMap, "time"); var time:Float = getFloat(keyMap, "time");
var value1:Float = getFloat(keyMap, name1, defaultValue) * scale; var value1:Float = getFloat(keyMap, name1, defaultValue) * scale;

View File

@ -51,13 +51,15 @@ class Skin {
public final color:Color = new Color(0.99607843, 0.61960787, 0.30980393, 1); // fe9e4fff public final color:Color = new Color(0.99607843, 0.61960787, 0.30980393, 1); // fe9e4fff
public function new(name:String) { public function new(name:String) {
if (name == null) throw new SpineException("name cannot be null."); if (name == null)
throw new SpineException("name cannot be null.");
this.name = name; this.name = name;
} }
/** Adds an attachment to the skin for the specified slot index and name. */ /** Adds an attachment to the skin for the specified slot index and name. */
public function setAttachment(slotIndex:Int, name:String, attachment:Attachment):Void { public function setAttachment(slotIndex:Int, name:String, attachment:Attachment):Void {
if (attachment == null) throw new SpineException("attachment cannot be null."); if (attachment == null)
throw new SpineException("attachment cannot be null.");
if (slotIndex >= attachments.length) if (slotIndex >= attachments.length)
attachments.resize(slotIndex + 1); attachments.resize(slotIndex + 1);
if (attachments[slotIndex] == null) if (attachments[slotIndex] == null)
@ -218,7 +220,8 @@ class Skin {
var skinAttachment:Attachment = dictionary.get(name); var skinAttachment:Attachment = dictionary.get(name);
if (slotAttachment == skinAttachment) { if (slotAttachment == skinAttachment) {
var attachment:Attachment = getAttachment(slotIndex, name); var attachment:Attachment = getAttachment(slotIndex, name);
if (attachment != null) slot.attachment = attachment; if (attachment != null)
slot.attachment = attachment;
break; break;
} }
} }

View File

@ -34,8 +34,10 @@ import spine.attachments.Attachment;
/** Stores an entry in the skin consisting of the slot index and the attachment name. */ /** Stores an entry in the skin consisting of the slot index and the attachment name. */
class SkinEntry { class SkinEntry {
public var slotIndex:Int = 0; public var slotIndex:Int = 0;
/** The name the attachment is associated with, equivalent to the skin placeholder name in the Spine editor. */ /** The name the attachment is associated with, equivalent to the skin placeholder name in the Spine editor. */
public var name:String; public var name:String;
public var attachment:Attachment; public var attachment:Attachment;
public function new(slotIndex:Int, name:String, attachment:Attachment) { public function new(slotIndex:Int, name:String, attachment:Attachment) {

View File

@ -45,9 +45,11 @@ class Slider extends Constraint<Slider, SliderData, SliderPose> {
public function new(data:SliderData, skeleton:Skeleton) { public function new(data:SliderData, skeleton:Skeleton) {
super(data, new SliderPose(), new SliderPose()); super(data, new SliderPose(), new SliderPose());
if (skeleton == null) throw new SpineException("skeleton cannot be null."); if (skeleton == null)
throw new SpineException("skeleton cannot be null.");
if (data.bone != null) bone = skeleton.bones[data.bone.index]; if (data.bone != null)
bone = skeleton.bones[data.bone.index];
} }
public function copy(skeleton:Skeleton) { public function copy(skeleton:Skeleton) {
@ -58,14 +60,16 @@ class Slider extends Constraint<Slider, SliderData, SliderPose> {
public function update(skeleton:Skeleton, physics:Physics) { public function update(skeleton:Skeleton, physics:Physics) {
var p = applied; var p = applied;
if (p.mix == 0) return; if (p.mix == 0)
return;
var animation = data.animation; var animation = data.animation;
if (bone != null) { if (bone != null) {
if (!bone.active) return; if (!bone.active)
if (data.local) bone.applied.validateLocalTransform(skeleton); return;
p.time = data.offset if (data.local)
+ (data.property.value(skeleton, bone.applied, data.local, offsets) - data.property.offset) * data.scale; bone.applied.validateLocalTransform(skeleton);
p.time = data.offset + (data.property.value(skeleton, bone.applied, data.local, offsets) - data.property.offset) * data.scale;
if (data.loop) if (data.loop)
p.time = animation.duration + (p.time % animation.duration); p.time = animation.duration + (p.time % animation.duration);
else else
@ -78,12 +82,12 @@ class Slider extends Constraint<Slider, SliderData, SliderPose> {
while (i < n) while (i < n)
bones[indices[i++]].applied.modifyLocal(skeleton); bones[indices[i++]].applied.modifyLocal(skeleton);
animation.apply(skeleton, p.time, p.time, data.loop, null, p.mix, data.additive ? MixBlend.add : MixBlend.replace, animation.apply(skeleton, p.time, p.time, data.loop, null, p.mix, data.additive ? MixBlend.add : MixBlend.replace, MixDirection.mixIn, true);
MixDirection.mixIn, true);
} }
function sort(skeleton:Skeleton) { function sort(skeleton:Skeleton) {
if (bone != null && !data.local) skeleton.sortBone(bone); if (bone != null && !data.local)
skeleton.sortBone(bone);
skeleton._updateCache.push(this); skeleton._updateCache.push(this);
var bones = skeleton.bones; var bones = skeleton.bones;

View File

@ -1,5 +1,3 @@
/****************************************************************************** /******************************************************************************
* Spine Runtimes License Agreement * Spine Runtimes License Agreement
* Last updated April 5, 2025. Replaces all prior versions. * Last updated April 5, 2025. Replaces all prior versions.

View File

@ -34,8 +34,7 @@ class SliderPose implements Pose<SliderPose> {
public var time = 0.; public var time = 0.;
public var mix = 0.; public var mix = 0.;
public function new () { public function new() {}
}
public function set(pose:SliderPose) { public function set(pose:SliderPose) {
time = pose.time; time = pose.time;

View File

@ -36,7 +36,6 @@ import spine.attachments.VertexAttachment;
* state for an attachment. State cannot be stored in an attachment itself because attachments are stateless and may be shared * state for an attachment. State cannot be stored in an attachment itself because attachments are stateless and may be shared
* across multiple skeletons. */ * across multiple skeletons. */
class Slot extends Posed<SlotData, SlotPose, SlotPose> { class Slot extends Posed<SlotData, SlotPose, SlotPose> {
public var skeleton:Skeleton; public var skeleton:Skeleton;
/** The bone this slot belongs to. */ /** The bone this slot belongs to. */
@ -46,7 +45,8 @@ class Slot extends Posed<SlotData, SlotPose, SlotPose> {
public function new(data:SlotData, skeleton:Skeleton) { public function new(data:SlotData, skeleton:Skeleton) {
super(data, new SlotPose(), new SlotPose()); super(data, new SlotPose(), new SlotPose());
if (skeleton == null) throw new SpineException("skeleton cannot be null."); if (skeleton == null)
throw new SpineException("skeleton cannot be null.");
this.skeleton = skeleton; this.skeleton = skeleton;
bone = skeleton.bones[data.boneData.index]; bone = skeleton.bones[data.boneData.index];
if (data.setup.darkColor != null) { if (data.setup.darkColor != null) {
@ -59,8 +59,10 @@ class Slot extends Posed<SlotData, SlotPose, SlotPose> {
/** Copy method. */ /** Copy method. */
public function copy(slot:Slot, bone:Bone, skeleton:Skeleton):Slot { public function copy(slot:Slot, bone:Bone, skeleton:Skeleton):Slot {
var copy = new Slot(slot.data, skeleton); var copy = new Slot(slot.data, skeleton);
if (bone == null) throw new SpineException("bone cannot be null."); if (bone == null)
if (skeleton == null) throw new SpineException("skeleton cannot be null."); throw new SpineException("bone cannot be null.");
if (skeleton == null)
throw new SpineException("skeleton cannot be null.");
this.bone = bone; this.bone = bone;
if (data.setup.darkColor != null) { if (data.setup.darkColor != null) {
pose.darkColor = new Color(1, 1, 1, 1); pose.darkColor = new Color(1, 1, 1, 1);
@ -73,7 +75,8 @@ class Slot extends Posed<SlotData, SlotPose, SlotPose> {
/** Sets this slot to the setup pose. */ /** Sets this slot to the setup pose. */
override public function setupPose():Void { override public function setupPose():Void {
pose.color.setFromColor(data.setup.color); pose.color.setFromColor(data.setup.color);
if (pose.darkColor != null) pose.darkColor.setFromColor(data.setup.darkColor); if (pose.darkColor != null)
pose.darkColor.setFromColor(data.setup.darkColor);
pose.sequenceIndex = data.setup.sequenceIndex; pose.sequenceIndex = data.setup.sequenceIndex;
if (data.attachmentName == null) { if (data.attachmentName == null) {
pose.attachment = null; pose.attachment = null;

View File

@ -31,7 +31,6 @@ package spine;
/** Stores the setup pose for a spine.Slot. */ /** Stores the setup pose for a spine.Slot. */
class SlotData extends PosedData<SlotPose> { class SlotData extends PosedData<SlotPose> {
/** The index of the slot in spine.Skeleton.getSlots(). */ /** The index of the slot in spine.Skeleton.getSlots(). */
public final index:Int; public final index:Int;
@ -45,13 +44,16 @@ class SlotData extends PosedData<SlotPose> {
public var blendMode:BlendMode = BlendMode.normal; public var blendMode:BlendMode = BlendMode.normal;
// Nonessential. // Nonessential.
/** False if the slot was hidden in Spine and nonessential data was exported. Does not affect runtime rendering. */ /** False if the slot was hidden in Spine and nonessential data was exported. Does not affect runtime rendering. */
public var visible:Bool = true; public var visible:Bool = true;
public function new(index:Int, name:String, boneData:BoneData) { public function new(index:Int, name:String, boneData:BoneData) {
super(name, new SlotPose()); super(name, new SlotPose());
if (index < 0) throw new SpineException("index must be >= 0."); if (index < 0)
if (boneData == null) throw new SpineException("boneData cannot be null."); throw new SpineException("index must be >= 0.");
if (boneData == null)
throw new SpineException("boneData cannot be null.");
this.index = index; this.index = index;
this.boneData = boneData; this.boneData = boneData;
} }

View File

@ -36,7 +36,6 @@ import spine.attachments.VertexAttachment;
* for an attachment. State cannot be stored in an attachment itself because attachments are stateless and may be shared across * for an attachment. State cannot be stored in an attachment itself because attachments are stateless and may be shared across
* multiple skeletons. */ * multiple skeletons. */
class SlotPose implements Pose<SlotPose> { class SlotPose implements Pose<SlotPose> {
/** The color used to tint the slot's attachment. If SlotData.darkColor is set, this is used as the light color for two /** The color used to tint the slot's attachment. If SlotData.darkColor is set, this is used as the light color for two
* color tinting. */ * color tinting. */
public final color:Color = new Color(1, 1, 1, 1); public final color:Color = new Color(1, 1, 1, 1);
@ -57,25 +56,29 @@ class SlotPose implements Pose<SlotPose> {
* @see spine.animation.DeformTimeline */ * @see spine.animation.DeformTimeline */
public var deform:Array<Float> = new Array<Float>(); public var deform:Array<Float> = new Array<Float>();
public function new () { public function new() {}
}
public function set(pose:SlotPose):Void { public function set(pose:SlotPose):Void {
if (pose == null) throw new SpineException("pose cannot be null."); if (pose == null)
throw new SpineException("pose cannot be null.");
color.setFromColor(pose.color); color.setFromColor(pose.color);
if (darkColor != null) darkColor.setFromColor(pose.darkColor); if (darkColor != null)
darkColor.setFromColor(pose.darkColor);
attachment = pose.attachment; attachment = pose.attachment;
sequenceIndex = pose.sequenceIndex; sequenceIndex = pose.sequenceIndex;
deform.resize(0); deform.resize(0);
for (e in pose.deform) deform.push(e); for (e in pose.deform)
deform.push(e);
} }
/** Sets the slot's attachment and, if the attachment changed, resets sequenceIndex and clears the deform. /** Sets the slot's attachment and, if the attachment changed, resets sequenceIndex and clears the deform.
* The deform is not cleared if the old attachment has the same spine.attachments.VertexAttachment.timelineAttachment as the * The deform is not cleared if the old attachment has the same spine.attachments.VertexAttachment.timelineAttachment as the
* specified attachment. */ * specified attachment. */
public function set_attachment(attachmentNew:Attachment):Attachment { public function set_attachment(attachmentNew:Attachment):Attachment {
if (attachment == attachmentNew) return attachment; if (attachment == attachmentNew)
if (!Std.isOfType(attachmentNew, VertexAttachment) || !Std.isOfType(attachment, VertexAttachment) return attachment;
if (!Std.isOfType(attachmentNew, VertexAttachment)
|| !Std.isOfType(attachment, VertexAttachment)
|| cast(attachmentNew, VertexAttachment).timelineAttachment != cast(attachment, VertexAttachment).timelineAttachment) { || cast(attachmentNew, VertexAttachment).timelineAttachment != cast(attachment, VertexAttachment).timelineAttachment) {
deform = new Array<Float>(); deform = new Array<Float>();
} }
@ -83,5 +86,4 @@ class SlotPose implements Pose<SlotPose> {
sequenceIndex = -1; sequenceIndex = -1;
return attachment; return attachment;
} }
} }

View File

@ -34,7 +34,6 @@ package spine;
* *
* @see https://esotericsoftware.com/spine-transform-constraints Transform constraints in the Spine User Guide */ * @see https://esotericsoftware.com/spine-transform-constraints Transform constraints in the Spine User Guide */
class TransformConstraint extends Constraint<TransformConstraint, TransformConstraintData, TransformConstraintPose> { class TransformConstraint extends Constraint<TransformConstraint, TransformConstraintData, TransformConstraintPose> {
/** The bones that will be modified by this transform constraint. */ /** The bones that will be modified by this transform constraint. */
public final bones:Array<BonePose>; public final bones:Array<BonePose>;
@ -43,7 +42,8 @@ class TransformConstraint extends Constraint<TransformConstraint, TransformConst
public function new(data:TransformConstraintData, skeleton:Skeleton) { public function new(data:TransformConstraintData, skeleton:Skeleton) {
super(data, new TransformConstraintPose(), new TransformConstraintPose()); super(data, new TransformConstraintPose(), new TransformConstraintPose());
if (skeleton == null) throw new SpineException("skeleton cannot be null."); if (skeleton == null)
throw new SpineException("skeleton cannot be null.");
bones = new Array<BonePose>(); bones = new Array<BonePose>();
for (boneData in data.bones) for (boneData in data.bones)
@ -60,12 +60,17 @@ class TransformConstraint extends Constraint<TransformConstraint, TransformConst
/** Applies the constraint to the constrained bones. */ /** Applies the constraint to the constrained bones. */
public function update(skeleton:Skeleton, physics:Physics):Void { public function update(skeleton:Skeleton, physics:Physics):Void {
var p = applied; var p = applied;
if (p.mixRotate == 0 && p.mixX == 0 && p.mixY == 0 && p.mixScaleX == 0 && p.mixScaleY == 0 && p.mixShearY == 0) return; if (p.mixRotate == 0 && p.mixX == 0 && p.mixY == 0 && p.mixScaleX == 0 && p.mixScaleY == 0 && p.mixShearY == 0)
return;
var localSource = data.localSource, localTarget = data.localTarget, additive = data.additive, clamp = data.clamp; var localSource = data.localSource,
localTarget = data.localTarget,
additive = data.additive,
clamp = data.clamp;
var offsets = data.offsets; var offsets = data.offsets;
var source = this.source.applied; var source = this.source.applied;
if (localSource) source.validateLocalTransform(skeleton); if (localSource)
source.validateLocalTransform(skeleton);
var fromItems = data.properties; var fromItems = data.properties;
var fn = data.properties.length, update = skeleton.update; var fn = data.properties.length, update = skeleton.update;
var bones = this.bones; var bones = this.bones;
@ -104,7 +109,8 @@ class TransformConstraint extends Constraint<TransformConstraint, TransformConst
} }
public function sort(skeleton:Skeleton) { public function sort(skeleton:Skeleton) {
if (!data.localSource) skeleton.sortBone(source); if (!data.localSource)
skeleton.sortBone(source);
var bones = this.bones; var bones = this.bones;
var boneCount = this.bones.length; var boneCount = this.bones.length;
var worldTarget = !data.localTarget; var worldTarget = !data.localTarget;

View File

@ -68,16 +68,22 @@ class TransformConstraintData extends ConstraintData<TransformConstraint, Transf
/** An offset added to the constrained bone rotation. */ /** An offset added to the constrained bone rotation. */
public var offsetRotation:Float = 0; public var offsetRotation:Float = 0;
/** An offset added to the constrained bone X translation. */ /** An offset added to the constrained bone X translation. */
public var offsetX:Float = 0; public var offsetX:Float = 0;
/** An offset added to the constrained bone Y translation. */ /** An offset added to the constrained bone Y translation. */
public var offsetY:Float = 0; public var offsetY:Float = 0;
/** An offset added to the constrained bone scaleX. */ /** An offset added to the constrained bone scaleX. */
public var offsetScaleX:Float = 0; public var offsetScaleX:Float = 0;
/** An offset added to the constrained bone scaleY. */ /** An offset added to the constrained bone scaleY. */
public var offsetScaleY:Float = 0; public var offsetScaleY:Float = 0;
/** An offset added to the constrained bone shearY. */ /** An offset added to the constrained bone shearY. */
public var offsetShearY:Float = 0; public var offsetShearY:Float = 0;
public var relative:Bool = false; public var relative:Bool = false;
public var local:Bool = false; public var local:Bool = false;
@ -90,7 +96,8 @@ class TransformConstraintData extends ConstraintData<TransformConstraint, Transf
} }
public function set_source(source:BoneData):BoneData { public function set_source(source:BoneData):BoneData {
if (source == null) throw new SpineException("source cannot be null."); if (source == null)
throw new SpineException("source cannot be null.");
this.source = source; this.source = source;
return source; return source;
} }
@ -154,13 +161,11 @@ class TransformConstraintData extends ConstraintData<TransformConstraint, Transf
offsets[TransformConstraintData.SHEARY] = offsetShearY; offsets[TransformConstraintData.SHEARY] = offsetShearY;
return offsetShearY; return offsetShearY;
} }
} }
/** Source property for a {@link TransformConstraint}. */ /** Source property for a {@link TransformConstraint}. */
abstract class FromProperty { abstract class FromProperty {
public function new () { public function new() {}
}
/** The value of this property that corresponds to ToProperty.offset. */ /** The value of this property that corresponds to ToProperty.offset. */
public var offset:Float; public var offset:Float;
@ -174,8 +179,7 @@ abstract class FromProperty {
/** Constrained property for a TransformConstraint. */ /** Constrained property for a TransformConstraint. */
abstract class ToProperty { abstract class ToProperty {
public function new () { public function new() {}
}
/** The value of this property that corresponds to FromProperty.offset. */ /** The value of this property that corresponds to FromProperty.offset. */
public var offset:Float; public var offset:Float;
@ -195,11 +199,14 @@ abstract class ToProperty {
class FromRotate extends FromProperty { class FromRotate extends FromProperty {
public function value(skeleton:Skeleton, source:BonePose, local:Bool, offsets:Array<Float>):Float { public function value(skeleton:Skeleton, source:BonePose, local:Bool, offsets:Array<Float>):Float {
if (local) return source.rotation + offsets[TransformConstraintData.ROTATION]; if (local)
return source.rotation + offsets[TransformConstraintData.ROTATION];
var sx = skeleton.scaleX, sy = skeleton.scaleY; var sx = skeleton.scaleX, sy = skeleton.scaleY;
var value = Math.atan2(source.c / sy, source.a / sx) * MathUtils.radDeg var value = Math.atan2(source.c / sy, source.a / sx) * MathUtils.radDeg
+ ((source.a * source.d - source.b * source.c) * sx * sy > 0 ? offsets[TransformConstraintData.ROTATION] : -offsets[TransformConstraintData.ROTATION]); + ((source.a * source.d - source.b * source.c) * sx * sy > 0 ? offsets[TransformConstraintData.ROTATION] :
if (value < 0) value += 360; -offsets[TransformConstraintData.ROTATION]);
if (value < 0)
value += 360;
return value; return value;
} }
} }
@ -214,9 +221,13 @@ class ToRotate extends ToProperty {
bone.rotation += (additive ? value : value - bone.rotation) * pose.mixRotate; bone.rotation += (additive ? value : value - bone.rotation) * pose.mixRotate;
else { else {
var sx = skeleton.scaleX, sy = skeleton.scaleY, ix = 1 / sx, iy = 1 / sy; var sx = skeleton.scaleX, sy = skeleton.scaleY, ix = 1 / sx, iy = 1 / sy;
var a = bone.a * ix, b = bone.b * ix, c = bone.c * iy, d = bone.d * iy; var a = bone.a * ix,
b = bone.b * ix,
c = bone.c * iy,
d = bone.d * iy;
value *= MathUtils.degRad; value *= MathUtils.degRad;
if (!additive) value -= Math.atan2(c, a); if (!additive)
value -= Math.atan2(c, a);
if (value > MathUtils.PI) if (value > MathUtils.PI)
value -= MathUtils.PI2; value -= MathUtils.PI2;
else if (value < -MathUtils.PI) // else if (value < -MathUtils.PI) //
@ -233,9 +244,8 @@ class ToRotate extends ToProperty {
class FromX extends FromProperty { class FromX extends FromProperty {
public function value(skeleton:Skeleton, source:BonePose, local:Bool, offsets:Array<Float>):Float { public function value(skeleton:Skeleton, source:BonePose, local:Bool, offsets:Array<Float>):Float {
return local return local ? source.x + offsets[TransformConstraintData.X] : (offsets[TransformConstraintData.X] * source.a
? source.x + offsets[TransformConstraintData.X] + offsets[TransformConstraintData.Y] * source.b + source.worldX) / skeleton.scaleX;
: (offsets[TransformConstraintData.X] * source.a + offsets[TransformConstraintData.Y] * source.b + source.worldX) / skeleton.scaleX;
} }
} }
@ -248,7 +258,8 @@ class ToX extends ToProperty {
if (local) if (local)
bone.x += (additive ? value : value - bone.x) * pose.mixX; bone.x += (additive ? value : value - bone.x) * pose.mixX;
else { else {
if (!additive) value -= bone.worldX / skeleton.scaleX; if (!additive)
value -= bone.worldX / skeleton.scaleX;
bone.worldX += value * pose.mixX * skeleton.scaleX; bone.worldX += value * pose.mixX * skeleton.scaleX;
} }
} }
@ -256,9 +267,8 @@ class ToX extends ToProperty {
class FromY extends FromProperty { class FromY extends FromProperty {
public function value(skeleton:Skeleton, source:BonePose, local:Bool, offsets:Array<Float>):Float { public function value(skeleton:Skeleton, source:BonePose, local:Bool, offsets:Array<Float>):Float {
return local return local ? source.y + offsets[TransformConstraintData.Y] : (offsets[TransformConstraintData.X] * source.c
? source.y + offsets[TransformConstraintData.Y] + offsets[TransformConstraintData.Y] * source.d + source.worldY) / skeleton.scaleY;
: (offsets[TransformConstraintData.X] * source.c + offsets[TransformConstraintData.Y] * source.d + source.worldY) / skeleton.scaleY;
} }
} }
@ -271,7 +281,8 @@ class ToY extends ToProperty {
if (local) if (local)
bone.y += (additive ? value : value - bone.y) * pose.mixY; bone.y += (additive ? value : value - bone.y) * pose.mixY;
else { else {
if (!additive) value -= bone.worldY / skeleton.scaleY; if (!additive)
value -= bone.worldY / skeleton.scaleY;
bone.worldY += value * pose.mixY * skeleton.scaleY; bone.worldY += value * pose.mixY * skeleton.scaleY;
} }
} }
@ -279,7 +290,8 @@ class ToY extends ToProperty {
class FromScaleX extends FromProperty { class FromScaleX extends FromProperty {
public function value(skeleton:Skeleton, source:BonePose, local:Bool, offsets:Array<Float>):Float { public function value(skeleton:Skeleton, source:BonePose, local:Bool, offsets:Array<Float>):Float {
if (local) return source.scaleX + offsets[TransformConstraintData.SCALEX]; if (local)
return source.scaleX + offsets[TransformConstraintData.SCALEX];
var a = source.a / skeleton.scaleX, c = source.c / skeleton.scaleY; var a = source.a / skeleton.scaleX, c = source.c / skeleton.scaleY;
return Math.sqrt(a * a + c * c) + offsets[TransformConstraintData.SCALEX]; return Math.sqrt(a * a + c * c) + offsets[TransformConstraintData.SCALEX];
} }
@ -301,7 +313,9 @@ class ToScaleX extends ToProperty {
bone.a *= s; bone.a *= s;
bone.c *= s; bone.c *= s;
} else { } else {
var a = bone.a / skeleton.scaleX, c = bone.c / skeleton.scaleY, s = Math.sqrt(a * a + c * c); var a = bone.a / skeleton.scaleX,
c = bone.c / skeleton.scaleY,
s = Math.sqrt(a * a + c * c);
if (s != 0) { if (s != 0) {
s = 1 + (value - s) * pose.mixScaleX / s; s = 1 + (value - s) * pose.mixScaleX / s;
bone.a *= s; bone.a *= s;
@ -313,7 +327,8 @@ class ToScaleX extends ToProperty {
class FromScaleY extends FromProperty { class FromScaleY extends FromProperty {
public function value(skeleton:Skeleton, source:BonePose, local:Bool, offsets:Array<Float>):Float { public function value(skeleton:Skeleton, source:BonePose, local:Bool, offsets:Array<Float>):Float {
if (local) return source.scaleY + offsets[TransformConstraintData.SCALEY]; if (local)
return source.scaleY + offsets[TransformConstraintData.SCALEY];
var b = source.b / skeleton.scaleX, d = source.d / skeleton.scaleY; var b = source.b / skeleton.scaleX, d = source.d / skeleton.scaleY;
return Math.sqrt(b * b + d * d) + offsets[TransformConstraintData.SCALEY]; return Math.sqrt(b * b + d * d) + offsets[TransformConstraintData.SCALEY];
} }
@ -335,7 +350,9 @@ class ToScaleY extends ToProperty {
bone.b *= s; bone.b *= s;
bone.d *= s; bone.d *= s;
} else { } else {
var b = bone.b / skeleton.scaleX, d = bone.d / skeleton.scaleY, s = Math.sqrt(b * b + d * d); var b = bone.b / skeleton.scaleX,
d = bone.d / skeleton.scaleY,
s = Math.sqrt(b * b + d * d);
if (s != 0) { if (s != 0) {
s = 1 + (value - s) * pose.mixScaleY / s; s = 1 + (value - s) * pose.mixScaleY / s;
bone.b *= s; bone.b *= s;
@ -347,10 +364,13 @@ class ToScaleY extends ToProperty {
class FromShearY extends FromProperty { class FromShearY extends FromProperty {
public function value(skeleton:Skeleton, source:BonePose, local:Bool, offsets:Array<Float>):Float { public function value(skeleton:Skeleton, source:BonePose, local:Bool, offsets:Array<Float>):Float {
if (local) return source.shearY + offsets[TransformConstraintData.SHEARY]; if (local)
return source.shearY + offsets[TransformConstraintData.SHEARY];
var sx = 1 / skeleton.scaleX, sy = 1 / skeleton.scaleY; var sx = 1 / skeleton.scaleX, sy = 1 / skeleton.scaleY;
return (Math.atan2(source.d * sy, source.b * sx) - Math.atan2(source.c * sy, source.a * sx)) return (Math.atan2(source.d * sy, source.b * sx)
* MathUtils.radDeg - 90 + offsets[TransformConstraintData.SHEARY]; - Math.atan2(source.c * sy, source.a * sx)) * MathUtils.radDeg
- 90
+ offsets[TransformConstraintData.SHEARY];
} }
} }
@ -361,10 +381,15 @@ class ToShearY extends ToProperty {
public function apply(skeleton:Skeleton, pose:TransformConstraintPose, bone:BonePose, value:Float, local:Bool, additive:Bool):Void { public function apply(skeleton:Skeleton, pose:TransformConstraintPose, bone:BonePose, value:Float, local:Bool, additive:Bool):Void {
if (local) { if (local) {
if (!additive) value -= bone.shearY; if (!additive)
value -= bone.shearY;
bone.shearY += value * pose.mixShearY; bone.shearY += value * pose.mixShearY;
} else { } else {
var sx = skeleton.scaleX, sy = skeleton.scaleY, b = bone.b / sx, d = bone.d / sy, by = Math.atan2(d, b); var sx = skeleton.scaleX,
sy = skeleton.scaleY,
b = bone.b / sx,
d = bone.d / sy,
by = Math.atan2(d, b);
value = (value + 90) * MathUtils.degRad; value = (value + 90) * MathUtils.degRad;
if (additive) if (additive)
value -= MathUtils.PI / 2; value -= MathUtils.PI / 2;

View File

@ -31,27 +31,25 @@ package spine;
/** Stores a pose for a transform constraint. */ /** Stores a pose for a transform constraint. */
class TransformConstraintPose implements Pose<TransformConstraintPose> { class TransformConstraintPose implements Pose<TransformConstraintPose> {
/** A percentage (0-1) that controls the mix between the constrained and unconstrained rotation. */ /** A percentage (0-1) that controls the mix between the constrained and unconstrained rotation. */
public var mixRotate = 0.; public var mixRotate = 0.;
/** A percentage (0-1) that controls the mix between the constrained and unconstrained translation X. */ /** A percentage (0-1) that controls the mix between the constrained and unconstrained translation X. */
public var mixX = 0.; public var mixX = 0.;
/** A percentage (0-1) that controls the mix between the constrained and unconstrained translation Y. */ /** A percentage (0-1) that controls the mix between the constrained and unconstrained translation Y. */
public var mixY = 0.; public var mixY = 0.;
/** A percentage (0-1) that controls the mix between the constrained and unconstrained scale X. */ /** A percentage (0-1) that controls the mix between the constrained and unconstrained scale X. */
public var mixScaleX = 0.; public var mixScaleX = 0.;
/** A percentage (0-1) that controls the mix between the constrained and unconstrained scale Y. */ /** A percentage (0-1) that controls the mix between the constrained and unconstrained scale Y. */
public var mixScaleY = 0.; public var mixScaleY = 0.;
/** A percentage (0-1) that controls the mix between the constrained and unconstrained shear Y. */
/** A percentage (0-1) that controls the mix between the constrained and unconstrained shear Y. */
public var mixShearY = 0.; public var mixShearY = 0.;
public function new () { public function new() {}
}
public function set(pose:TransformConstraintPose) { public function set(pose:TransformConstraintPose) {
mixRotate = pose.mixRotate; mixRotate = pose.mixRotate;
@ -61,5 +59,4 @@ class TransformConstraintPose implements Pose<TransformConstraintPose> {
mixScaleY = pose.mixScaleY; mixScaleY = pose.mixScaleY;
mixShearY = pose.mixShearY; mixShearY = pose.mixShearY;
} }
} }

View File

@ -55,11 +55,11 @@ class AlphaTimeline extends CurveTimeline1 implements SlotTimeline {
return slotIndex; return slotIndex;
} }
public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend, direction:MixDirection,
blend:MixBlend, direction:MixDirection, appliedPose:Bool) { appliedPose:Bool) {
var slot = skeleton.slots[slotIndex]; var slot = skeleton.slots[slotIndex];
if (!slot.bone.active) return; if (!slot.bone.active)
return;
var color = (appliedPose ? slot.applied : slot.pose).color; var color = (appliedPose ? slot.applied : slot.pose).color;
if (time < frames[0]) { if (time < frames[0]) {

View File

@ -36,7 +36,6 @@ import spine.Skeleton;
/** Stores a list of timelines to animate a skeleton's pose over time. */ /** Stores a list of timelines to animate a skeleton's pose over time. */
class Animation { class Animation {
/** The animation's name, which is unique across all animations in the skeleton. */ /** The animation's name, which is unique across all animations in the skeleton. */
public final name:String; public final name:String;
@ -49,7 +48,8 @@ class Animation {
public final bones:Array<Int>; public final bones:Array<Int>;
public function new(name:String, timelines:Array<Timeline>, duration:Float) { public function new(name:String, timelines:Array<Timeline>, duration:Float) {
if (name == null) throw new SpineException("name cannot be null."); if (name == null)
throw new SpineException("name cannot be null.");
this.name = name; this.name = name;
this.duration = duration; this.duration = duration;
var n = timelines.length << 1; var n = timelines.length << 1;
@ -59,7 +59,8 @@ class Animation {
} }
public function setTimelines(timelines:Array<Timeline>) { public function setTimelines(timelines:Array<Timeline>) {
if (timelines == null) throw new SpineException("timelines cannot be null."); if (timelines == null)
throw new SpineException("timelines cannot be null.");
this.timelines = timelines; this.timelines = timelines;
timelineIds.clear(); timelineIds.clear();
@ -67,7 +68,8 @@ class Animation {
var boneSet = new IntMap<Bool>(); var boneSet = new IntMap<Bool>();
for (timeline in timelines) { for (timeline in timelines) {
var ids:Array<String> = timeline.propertyIds; var ids:Array<String> = timeline.propertyIds;
for (id in ids) timelineIds.set(id, true); for (id in ids)
timelineIds.set(id, true);
if (Std.isOfType(timeline, BoneTimeline)) { if (Std.isOfType(timeline, BoneTimeline)) {
var boneTimeline = cast(timeline, BoneTimeline); var boneTimeline = cast(timeline, BoneTimeline);
var boneIndex = boneTimeline.getBoneIndex(); var boneIndex = boneTimeline.getBoneIndex();
@ -108,13 +110,15 @@ class Animation {
* @param blend Controls how mixing is applied when alpha < 1. * @param blend Controls how mixing is applied when alpha < 1.
* @param direction Indicates whether the timelines are mixing in or out. Used by timelines which perform instant transitions, * @param direction Indicates whether the timelines are mixing in or out. Used by timelines which perform instant transitions,
* such as DrawOrderTimeline or AttachmentTimeline. */ * such as DrawOrderTimeline or AttachmentTimeline. */
public function apply(skeleton:Skeleton, lastTime:Float, time:Float, loop:Bool, events:Array<Event>, alpha:Float, blend:MixBlend, public function apply(skeleton:Skeleton, lastTime:Float, time:Float, loop:Bool, events:Array<Event>, alpha:Float, blend:MixBlend, direction:MixDirection,
direction:MixDirection, appliedPose:Bool):Void { appliedPose:Bool):Void {
if (skeleton == null) throw new SpineException("skeleton cannot be null."); if (skeleton == null)
throw new SpineException("skeleton cannot be null.");
if (loop && duration != 0) { if (loop && duration != 0) {
time %= duration; time %= duration;
if (lastTime > 0) lastTime %= duration; if (lastTime > 0)
lastTime %= duration;
} }
for (timeline in timelines) { for (timeline in timelines) {

View File

@ -47,12 +47,14 @@ class AnimationState {
* Result: Mix from the current pose to the timeline pose. * Result: Mix from the current pose to the timeline pose.
*/ */
public static inline var SUBSEQUENT:Int = 0; public static inline var SUBSEQUENT:Int = 0;
/** /**
* 1) This is the first timeline to set this property. * 1) This is the first timeline to set this property.
* 2) The next track entry applied after this one does not have a timeline to set this property. * 2) The next track entry applied after this one does not have a timeline to set this property.
* Result: Mix from the setup pose to the timeline pose. * Result: Mix from the setup pose to the timeline pose.
*/ */
public static inline var FIRST:Int = 1; public static inline var FIRST:Int = 1;
/** /**
* 1) A previously applied timeline has set this property. * 1) A previously applied timeline has set this property.
* 2) The next track entry to be applied does have a timeline to set this property. * 2) The next track entry to be applied does have a timeline to set this property.
@ -61,6 +63,7 @@ class AnimationState {
* animations that key the same property. A subsequent timeline will set this property using a mix. * animations that key the same property. A subsequent timeline will set this property using a mix.
*/ */
public static inline var HOLD_SUBSEQUENT:Int = 2; public static inline var HOLD_SUBSEQUENT:Int = 2;
/** /**
* 1) This is the first timeline to set this property. * 1) This is the first timeline to set this property.
* 2) The next track entry to be applied does have a timeline to set this property. * 2) The next track entry to be applied does have a timeline to set this property.
@ -69,6 +72,7 @@ class AnimationState {
* that key the same property. A subsequent timeline will set this property using a mix. * that key the same property. A subsequent timeline will set this property using a mix.
*/ */
public static inline var HOLD_FIRST:Int = 3; public static inline var HOLD_FIRST:Int = 3;
/** /**
* 1) This is the first timeline to set this property. * 1) This is the first timeline to set this property.
* 2) The next track entry to be applied does have a timeline to set this property. * 2) The next track entry to be applied does have a timeline to set this property.
@ -82,6 +86,7 @@ class AnimationState {
* out position. * out position.
*/ */
public static inline var HOLD_MIX:Int = 4; public static inline var HOLD_MIX:Int = 4;
public static inline var SETUP:Int = 1; public static inline var SETUP:Int = 1;
public static inline var CURRENT:Int = 2; public static inline var CURRENT:Int = 2;
@ -203,7 +208,8 @@ class AnimationState {
// Mixing is complete for all entries before the from entry or the mix is instantaneous. // Mixing is complete for all entries before the from entry or the mix is instantaneous.
if (from.totalAlpha == 0 || to.mixDuration == 0) { if (from.totalAlpha == 0 || to.mixDuration == 0) {
to.mixingFrom = from.mixingFrom; to.mixingFrom = from.mixingFrom;
if (from.mixingFrom != null) from.mixingFrom.mixingTo = to; if (from.mixingFrom != null)
from.mixingFrom.mixingTo = to;
to.interruptAlpha = from.interruptAlpha; to.interruptAlpha = from.interruptAlpha;
queue.end(from); queue.end(from);
} }
@ -256,7 +262,8 @@ class AnimationState {
var timelineCount:Int = timelines.length; var timelineCount:Int = timelines.length;
var timeline:Timeline; var timeline:Timeline;
if ((i == 0 && alpha == 1) || blend == MixBlend.add) { if ((i == 0 && alpha == 1) || blend == MixBlend.add) {
if (i == 0) attachments = true; if (i == 0)
attachments = true;
for (timeline in timelines) { for (timeline in timelines) {
if (Std.isOfType(timeline, AttachmentTimeline)) { if (Std.isOfType(timeline, AttachmentTimeline)) {
applyAttachmentTimeline(cast(timeline, AttachmentTimeline), skeleton, applyTime, blend, attachments); applyAttachmentTimeline(cast(timeline, AttachmentTimeline), skeleton, applyTime, blend, attachments);
@ -276,8 +283,8 @@ class AnimationState {
var timeline:Timeline = timelines[ii]; var timeline:Timeline = timelines[ii];
var timelineBlend:MixBlend = timelineMode[ii] == SUBSEQUENT ? blend : MixBlend.setup; var timelineBlend:MixBlend = timelineMode[ii] == SUBSEQUENT ? blend : MixBlend.setup;
if (!shortestRotation && Std.isOfType(timeline, RotateTimeline)) { if (!shortestRotation && Std.isOfType(timeline, RotateTimeline)) {
this.applyRotateTimeline(cast(timeline, RotateTimeline), skeleton, applyTime, alpha, timelineBlend, current.timelinesRotation, ii << 1, this.applyRotateTimeline(cast(timeline, RotateTimeline), skeleton, applyTime, alpha, timelineBlend, current.timelinesRotation,
firstFrame); ii << 1, firstFrame);
} else if (Std.isOfType(timeline, AttachmentTimeline)) { } else if (Std.isOfType(timeline, AttachmentTimeline)) {
this.applyAttachmentTimeline(cast(timeline, AttachmentTimeline), skeleton, applyTime, blend, attachments); this.applyAttachmentTimeline(cast(timeline, AttachmentTimeline), skeleton, applyTime, blend, attachments);
} else { } else {
@ -387,7 +394,8 @@ class AnimationState {
if (!shortestRotation && Std.isOfType(timeline, RotateTimeline)) { if (!shortestRotation && Std.isOfType(timeline, RotateTimeline)) {
applyRotateTimeline(cast(timeline, RotateTimeline), skeleton, applyTime, alpha, timelineBlend, from.timelinesRotation, i << 1, firstFrame); applyRotateTimeline(cast(timeline, RotateTimeline), skeleton, applyTime, alpha, timelineBlend, from.timelinesRotation, i << 1, firstFrame);
} else if (Std.isOfType(timeline, AttachmentTimeline)) { } else if (Std.isOfType(timeline, AttachmentTimeline)) {
applyAttachmentTimeline(cast(timeline, AttachmentTimeline), skeleton, applyTime, timelineBlend, attachments && alpha >= from.alphaAttachmentThreshold); applyAttachmentTimeline(cast(timeline, AttachmentTimeline), skeleton, applyTime,
timelineBlend, attachments && alpha >= from.alphaAttachmentThreshold);
} else { } else {
if (drawOrder && Std.isOfType(timeline, DrawOrderTimeline) && timelineBlend == MixBlend.setup) if (drawOrder && Std.isOfType(timeline, DrawOrderTimeline) && timelineBlend == MixBlend.setup)
direction = MixDirection.mixIn; direction = MixDirection.mixIn;
@ -534,7 +542,8 @@ class AnimationState {
} }
} else } else
complete = animationTime >= animationEnd && entry.animationLast < animationEnd; complete = animationTime >= animationEnd && entry.animationLast < animationEnd;
if (complete) queue.complete(entry); if (complete)
queue.complete(entry);
// Queue events after complete. // Queue events after complete.
while (i < n) { while (i < n) {
@ -699,11 +708,13 @@ class AnimationState {
if (last == null) { if (last == null) {
setCurrent(trackIndex, entry, true); setCurrent(trackIndex, entry, true);
queue.drain(); queue.drain();
if (delay < 0) delay = 0; if (delay < 0)
delay = 0;
} else { } else {
last.next = entry; last.next = entry;
entry.previous = last; entry.previous = last;
if (delay <= 0) delay = Math.max(delay + last.getTrackComplete() - entry.mixDuration, 0); if (delay <= 0)
delay = Math.max(delay + last.getTrackComplete() - entry.mixDuration, 0);
} }
entry.delay = delay; entry.delay = delay;
@ -753,7 +764,8 @@ class AnimationState {
*/ */
public function addEmptyAnimation(trackIndex:Int, mixDuration:Float, delay:Float):TrackEntry { public function addEmptyAnimation(trackIndex:Int, mixDuration:Float, delay:Float):TrackEntry {
var entry:TrackEntry = addAnimation(trackIndex, emptyAnimation, false, delay); var entry:TrackEntry = addAnimation(trackIndex, emptyAnimation, false, delay);
if (delay <= 0) entry.delay = Math.max(entry.delay + entry.mixDuration - mixDuration, 0); if (delay <= 0)
entry.delay = Math.max(entry.delay + entry.mixDuration - mixDuration, 0);
entry.mixDuration = mixDuration; entry.mixDuration = mixDuration;
entry.trackEnd = mixDuration; entry.trackEnd = mixDuration;
return entry; return entry;

View File

@ -63,17 +63,19 @@ class AttachmentTimeline extends Timeline implements SlotTimeline {
attachmentNames[frame] = attachmentName; attachmentNames[frame] = attachmentName;
} }
public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend, direction:MixDirection,
blend:MixBlend, direction:MixDirection, appliedPose:Bool) { appliedPose:Bool) {
var slot = skeleton.slots[slotIndex]; var slot = skeleton.slots[slotIndex];
if (!slot.bone.active) return; if (!slot.bone.active)
return;
var pose = appliedPose ? slot.applied : slot.pose; var pose = appliedPose ? slot.applied : slot.pose;
if (direction == MixDirection.mixOut) { if (direction == MixDirection.mixOut) {
if (blend == MixBlend.setup) setAttachment(skeleton, pose, slot.data.attachmentName); if (blend == MixBlend.setup)
setAttachment(skeleton, pose, slot.data.attachmentName);
} else if (time < frames[0]) { } else if (time < frames[0]) {
if (blend == MixBlend.setup || blend == MixBlend.first) setAttachment(skeleton, pose, slot.data.attachmentName); if (blend == MixBlend.setup || blend == MixBlend.first)
setAttachment(skeleton, pose, slot.data.attachmentName);
} else } else
setAttachment(skeleton, pose, attachmentNames[Timeline.search1(frames, time)]); setAttachment(skeleton, pose, attachmentNames[Timeline.search1(frames, time)]);
} }

View File

@ -41,11 +41,11 @@
return boneIndex; return boneIndex;
} }
public function apply (skeleton: Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend, public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend, direction:MixDirection,
direction:MixDirection, appliedPose:Bool) { appliedPose:Bool) {
var bone = skeleton.bones[boneIndex]; var bone = skeleton.bones[boneIndex];
if (bone.active) apply1(appliedPose ? bone.applied : bone.pose, bone.data.setup, time, alpha, blend, direction); if (bone.active)
apply1(appliedPose ? bone.applied : bone.pose, bone.data.setup, time, alpha, blend, direction);
} }
abstract function apply1(pose:BoneLocal, setup:BoneLocal, time:Float, alpha:Float, blend:MixBlend, direction:MixDirection):Void; abstract function apply1(pose:BoneLocal, setup:BoneLocal, time:Float, alpha:Float, blend:MixBlend, direction:MixDirection):Void;

View File

@ -61,11 +61,11 @@ abstract class BoneTimeline2 extends CurveTimeline implements BoneTimeline {
return boneIndex; return boneIndex;
} }
public function apply (skeleton: Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend, public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend, direction:MixDirection,
direction:MixDirection, appliedPose:Bool) { appliedPose:Bool) {
var bone = skeleton.bones[boneIndex]; var bone = skeleton.bones[boneIndex];
if (bone.active) apply1(appliedPose ? bone.applied : bone.pose, bone.data.setup, time, alpha, blend, direction); if (bone.active)
apply1(appliedPose ? bone.applied : bone.pose, bone.data.setup, time, alpha, blend, direction);
} }
abstract function apply1(pose:BoneLocal, setup:BoneLocal, time:Float, alpha:Float, blend:MixBlend, direction:MixDirection):Void; abstract function apply1(pose:BoneLocal, setup:BoneLocal, time:Float, alpha:Float, blend:MixBlend, direction:MixDirection):Void;

View File

@ -81,47 +81,65 @@ abstract class CurveTimeline1 extends CurveTimeline {
public function getRelativeValue(time:Float, alpha:Float, blend:MixBlend, current:Float, setup:Float):Float { public function getRelativeValue(time:Float, alpha:Float, blend:MixBlend, current:Float, setup:Float):Float {
if (time < frames[0]) { if (time < frames[0]) {
switch (blend) { switch (blend) {
case MixBlend.setup: return setup; case MixBlend.setup:
case MixBlend.first: return current + (setup - current) * alpha; return setup;
default: return current; case MixBlend.first:
return current + (setup - current) * alpha;
default:
return current;
} }
} }
var value:Float = getCurveValue(time); var value:Float = getCurveValue(time);
switch (blend) { switch (blend) {
case MixBlend.setup: return setup + value * alpha; case MixBlend.setup:
case MixBlend.first, MixBlend.replace: return current + (value + setup - current) * alpha; return setup + value * alpha;
default: return current + value * alpha; // MixBlend.add case MixBlend.first, MixBlend.replace:
return current + (value + setup - current) * alpha;
default:
return current + value * alpha; // MixBlend.add
} }
} }
public function getAbsoluteValue(time:Float, alpha:Float, blend:MixBlend, current:Float, setup:Float):Float { public function getAbsoluteValue(time:Float, alpha:Float, blend:MixBlend, current:Float, setup:Float):Float {
if (time < frames[0]) { if (time < frames[0]) {
switch (blend) { switch (blend) {
case MixBlend.setup: return setup; case MixBlend.setup:
case MixBlend.first: return current + (setup - current) * alpha; return setup;
default: return current; case MixBlend.first:
return current + (setup - current) * alpha;
default:
return current;
} }
} }
var value:Float = getCurveValue(time); var value:Float = getCurveValue(time);
switch (blend) { switch (blend) {
case MixBlend.setup: return setup + (value - setup) * alpha; case MixBlend.setup:
case MixBlend.first, MixBlend.replace: return current + (value - current) * alpha; return setup + (value - setup) * alpha;
default: return current + value * alpha; // MixBlend.add case MixBlend.first, MixBlend.replace:
return current + (value - current) * alpha;
default:
return current + value * alpha; // MixBlend.add
} }
} }
public function getAbsoluteValue2(time:Float, alpha:Float, blend:MixBlend, current:Float, setup:Float, value:Float):Float { public function getAbsoluteValue2(time:Float, alpha:Float, blend:MixBlend, current:Float, setup:Float, value:Float):Float {
if (time < frames[0]) { if (time < frames[0]) {
switch (blend) { switch (blend) {
case MixBlend.setup: return setup; case MixBlend.setup:
case MixBlend.first: return current + (setup - current) * alpha; return setup;
default: current; case MixBlend.first:
return current + (setup - current) * alpha;
default:
current;
} }
} }
switch (blend) { switch (blend) {
case MixBlend.setup: return setup + (value - setup) * alpha; case MixBlend.setup:
case MixBlend.first, MixBlend.replace: return current + (value - current) * alpha; return setup + (value - setup) * alpha;
default: return current + value * alpha; // MixBlend.add case MixBlend.first, MixBlend.replace:
return current + (value - current) * alpha;
default:
return current + value * alpha; // MixBlend.add
} }
} }
@ -129,13 +147,17 @@ abstract class CurveTimeline1 extends CurveTimeline {
var frames:Array<Float> = frames; var frames:Array<Float> = frames;
if (time < frames[0]) { if (time < frames[0]) {
switch (blend) { switch (blend) {
case MixBlend.setup: return setup; case MixBlend.setup:
case MixBlend.first: return current + (setup - current) * alpha; return setup;
default: return current; case MixBlend.first:
return current + (setup - current) * alpha;
default:
return current;
} }
} }
var value:Float = getCurveValue(time) * setup; var value:Float = getCurveValue(time) * setup;
if (alpha == 1) return blend == MixBlend.add ? current + value - setup : value; if (alpha == 1)
return blend == MixBlend.add ? current + value - setup : value;
// Mixing out uses sign of setup or current pose, else use sign of key. // Mixing out uses sign of setup or current pose, else use sign of key.
if (direction == MixDirection.mixOut) { if (direction == MixDirection.mixOut) {
switch (blend) { switch (blend) {

View File

@ -140,18 +140,22 @@ class DeformTimeline extends SlotCurveTimeline {
} }
public function apply1(slot:Slot, pose:SlotPose, time:Float, alpha:Float, blend:MixBlend) { public function apply1(slot:Slot, pose:SlotPose, time:Float, alpha:Float, blend:MixBlend) {
if (!Std.isOfType(pose.attachment, VertexAttachment)) return; if (!Std.isOfType(pose.attachment, VertexAttachment))
return;
var vertexAttachment = cast(pose.attachment, VertexAttachment); var vertexAttachment = cast(pose.attachment, VertexAttachment);
if (vertexAttachment.timelineAttachment != attachment) return; if (vertexAttachment.timelineAttachment != attachment)
return;
var deform = pose.deform; var deform = pose.deform;
if (deform.length == 0) blend = MixBlend.setup; if (deform.length == 0)
blend = MixBlend.setup;
var vertexCount = vertices[0].length; var vertexCount = vertices[0].length;
if (time < frames[0]) { if (time < frames[0]) {
switch (blend) { switch (blend) {
case MixBlend.setup: deform.resize(0); case MixBlend.setup:
deform.resize(0);
case MixBlend.first: case MixBlend.first:
if (alpha == 1) { if (alpha == 1) {
deform.resize(0); deform.resize(0);
@ -253,7 +257,8 @@ class DeformTimeline extends SlotCurveTimeline {
if (vertexAttachment.bones == null) { // Unweighted vertex positions, with alpha. if (vertexAttachment.bones == null) { // Unweighted vertex positions, with alpha.
var setupVertices = vertexAttachment.vertices; var setupVertices = vertexAttachment.vertices;
for (i in 0...vertexCount) { for (i in 0...vertexCount) {
var prev = prevVertices[i], setup = setupVertices[i]; var prev = prevVertices[i],
setup = setupVertices[i];
deform[i] = setup + (prev + (nextVertices[i] - prev) * percent - setup) * alpha; deform[i] = setup + (prev + (nextVertices[i] - prev) * percent - setup) * alpha;
} }
} else { // Weighted deform offsets, with alpha. } else { // Weighted deform offsets, with alpha.

View File

@ -59,9 +59,8 @@ class DrawOrderTimeline extends Timeline {
drawOrders[frame] = drawOrder; drawOrders[frame] = drawOrder;
} }
public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend, direction:MixDirection,
blend:MixBlend, direction:MixDirection, appliedPose:Bool) { appliedPose:Bool) {
var drawOrder:Array<Slot> = skeleton.drawOrder; var drawOrder:Array<Slot> = skeleton.drawOrder;
var slots:Array<Slot> = skeleton.slots; var slots:Array<Slot> = skeleton.slots;
var i:Int = 0, n:Int = slots.length; var i:Int = 0, n:Int = slots.length;

View File

@ -79,7 +79,8 @@ class EventQueue {
} }
public function drain():Void { public function drain():Void {
if (drainDisabled) return; // Not reentrant. if (drainDisabled)
return; // Not reentrant.
drainDisabled = true; drainDisabled = true;
var i:Int = 0; var i:Int = 0;

View File

@ -56,9 +56,10 @@ class EventTimeline extends Timeline {
} }
/** Fires events for frames > lastTime and <= time. */ /** Fires events for frames > lastTime and <= time. */
public function apply(skeleton:Skeleton, lastTime:Float, time:Float, firedEvents:Array<Event>, alpha:Float, public function apply(skeleton:Skeleton, lastTime:Float, time:Float, firedEvents:Array<Event>, alpha:Float, blend:MixBlend, direction:MixDirection,
blend:MixBlend, direction:MixDirection, appliedPose:Bool) { appliedPose:Bool) {
if (firedEvents == null) return; if (firedEvents == null)
return;
var frameCount:Int = frames.length; var frameCount:Int = frames.length;
@ -67,7 +68,8 @@ class EventTimeline extends Timeline {
lastTime = -1; lastTime = -1;
} else if (lastTime >= frames[frameCount - 1]) // Last time is after last frame. } else if (lastTime >= frames[frameCount - 1]) // Last time is after last frame.
return; return;
if (time < frames[0]) return; if (time < frames[0])
return;
var frame:Int; var frame:Int;
var i:Int = 0; var i:Int = 0;

View File

@ -70,11 +70,11 @@ class IkConstraintTimeline extends CurveTimeline implements ConstraintTimeline {
frames[frame + STRETCH] = stretch ? 1 : 0; frames[frame + STRETCH] = stretch ? 1 : 0;
} }
public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend, direction:MixDirection,
blend:MixBlend, direction:MixDirection, appliedPose:Bool) { appliedPose:Bool) {
var constraint = cast(skeleton.constraints[constraintIndex], IkConstraint); var constraint = cast(skeleton.constraints[constraintIndex], IkConstraint);
if (!constraint.active) return; if (!constraint.active)
return;
var pose = appliedPose ? constraint.applied : constraint.pose; var pose = appliedPose ? constraint.applied : constraint.pose;
if (time < frames[0]) { if (time < frames[0]) {
@ -129,12 +129,13 @@ class IkConstraintTimeline extends CurveTimeline implements ConstraintTimeline {
case MixBlend.first, MixBlend.replace: case MixBlend.first, MixBlend.replace:
pose.mix += (mix - pose.mix) * alpha; pose.mix += (mix - pose.mix) * alpha;
pose.softness += (softness - pose.softness) * alpha; pose.softness += (softness - pose.softness) * alpha;
if (direction == MixDirection.mixOut) return; if (direction == MixDirection.mixOut)
return;
case MixBlend.add: case MixBlend.add:
pose.mix += mix * alpha; pose.mix += mix * alpha;
pose.softness += softness * alpha; pose.softness += softness * alpha;
if (direction == MixDirection.mixOut) return; if (direction == MixDirection.mixOut)
return;
} }
pose.bendDirection = Std.int(frames[i + BEND_DIRECTION]); pose.bendDirection = Std.int(frames[i + BEND_DIRECTION]);
pose.compress = frames[i + COMPRESS] != 0; pose.compress = frames[i + COMPRESS] != 0;

View File

@ -62,21 +62,23 @@ class InheritTimeline extends Timeline implements BoneTimeline {
frames[frame + INHERIT] = inherit.ordinal; frames[frame + INHERIT] = inherit.ordinal;
} }
public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend, direction:MixDirection,
blend:MixBlend, direction:MixDirection, appliedPose:Bool):Void { appliedPose:Bool):Void {
var bone:Bone = skeleton.bones[boneIndex]; var bone:Bone = skeleton.bones[boneIndex];
if (!bone.active) return; if (!bone.active)
return;
var pose = appliedPose ? bone.applied : bone.pose; var pose = appliedPose ? bone.applied : bone.pose;
if (direction == MixDirection.mixOut) { if (direction == MixDirection.mixOut) {
if (blend == MixBlend.setup) pose.inherit = bone.data.setup.inherit; if (blend == MixBlend.setup)
pose.inherit = bone.data.setup.inherit;
return; return;
} }
var frames:Array<Float> = frames; var frames:Array<Float> = frames;
if (time < frames[0]) { if (time < frames[0]) {
if (blend == MixBlend.setup || blend == MixBlend.first) pose.inherit = bone.data.setup.inherit; if (blend == MixBlend.setup || blend == MixBlend.first)
pose.inherit = bone.data.setup.inherit;
} else } else
pose.inherit = Inherit.values[Std.int(frames[Timeline.search(frames, time, ENTRIES) + INHERIT])]; pose.inherit = Inherit.values[Std.int(frames[Timeline.search(frames, time, ENTRIES) + INHERIT])];
} }

View File

@ -69,11 +69,11 @@ class PathConstraintMixTimeline extends CurveTimeline implements ConstraintTimel
frames[frame + Y] = mixY; frames[frame + Y] = mixY;
} }
public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend, direction:MixDirection,
blend:MixBlend, direction:MixDirection, appliedPose:Bool) { appliedPose:Bool) {
var constraint = cast(skeleton.constraints[constraintIndex], PathConstraint); var constraint = cast(skeleton.constraints[constraintIndex], PathConstraint);
if (!constraint.active) return; if (!constraint.active)
return;
var pose = appliedPose ? constraint.applied : constraint.pose; var pose = appliedPose ? constraint.applied : constraint.pose;
if (time < frames[0]) { if (time < frames[0]) {

View File

@ -35,14 +35,12 @@ class PathConstraintPositionTimeline extends ConstraintTimeline1 {
super(frameCount, bezierCount, constraintIndex, Property.pathConstraintPosition); super(frameCount, bezierCount, constraintIndex, Property.pathConstraintPosition);
} }
public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend, direction:MixDirection,
blend:MixBlend, direction:MixDirection, appliedPose:Bool) { appliedPose:Bool) {
var constraint = cast(skeleton.constraints[constraintIndex], PathConstraint); var constraint = cast(skeleton.constraints[constraintIndex], PathConstraint);
if (constraint.active) { if (constraint.active) {
var pose = appliedPose ? constraint.applied : constraint.pose; var pose = appliedPose ? constraint.applied : constraint.pose;
pose.position = getAbsoluteValue(time, alpha, blend, pose.position, constraint.data.setup.position); pose.position = getAbsoluteValue(time, alpha, blend, pose.position, constraint.data.setup.position);
} }
} }
} }

View File

@ -39,9 +39,8 @@ class PathConstraintSpacingTimeline extends ConstraintTimeline1 {
super(frameCount, bezierCount, constraintIndex, Property.pathConstraintSpacing); super(frameCount, bezierCount, constraintIndex, Property.pathConstraintSpacing);
} }
public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend, direction:MixDirection,
blend:MixBlend, direction:MixDirection, appliedPose:Bool) { appliedPose:Bool) {
var constraint = cast(skeleton.constraints[constraintIndex], PathConstraint); var constraint = cast(skeleton.constraints[constraintIndex], PathConstraint);
if (constraint.active) { if (constraint.active) {
var pose = appliedPose ? constraint.applied : constraint.pose; var pose = appliedPose ? constraint.applied : constraint.pose;

View File

@ -46,5 +46,4 @@ class PhysicsConstraintDampingTimeline extends PhysicsConstraintTimeline {
public function global(constraint:PhysicsConstraintData):Bool { public function global(constraint:PhysicsConstraintData):Bool {
return constraint.dampingGlobal; return constraint.dampingGlobal;
} }
} }

View File

@ -46,5 +46,4 @@ class PhysicsConstraintGravityTimeline extends PhysicsConstraintTimeline {
public function global(constraint:PhysicsConstraintData):Bool { public function global(constraint:PhysicsConstraintData):Bool {
return constraint.gravityGlobal; return constraint.gravityGlobal;
} }
} }

View File

@ -46,5 +46,4 @@ class PhysicsConstraintInertiaTimeline extends PhysicsConstraintTimeline {
public function global(constraint:PhysicsConstraintData):Bool { public function global(constraint:PhysicsConstraintData):Bool {
return constraint.inertiaGlobal; return constraint.inertiaGlobal;
} }
} }

View File

@ -46,5 +46,4 @@ class PhysicsConstraintMassTimeline extends PhysicsConstraintTimeline {
public function global(constraint:PhysicsConstraintData):Bool { public function global(constraint:PhysicsConstraintData):Bool {
return constraint.massGlobal; return constraint.massGlobal;
} }
} }

View File

@ -46,5 +46,4 @@ class PhysicsConstraintMixTimeline extends PhysicsConstraintTimeline {
public function global(constraint:PhysicsConstraintData):Bool { public function global(constraint:PhysicsConstraintData):Bool {
return constraint.mixGlobal; return constraint.mixGlobal;
} }
} }

View File

@ -58,13 +58,13 @@ class PhysicsConstraintResetTimeline extends Timeline implements ConstraintTimel
} }
/** Resets the physics constraint when frames > lastTime and <= time. */ /** Resets the physics constraint when frames > lastTime and <= time. */
public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend, direction:MixDirection,
blend:MixBlend, direction:MixDirection, appliedPose:Bool) { appliedPose:Bool) {
var constraint:PhysicsConstraint = null; var constraint:PhysicsConstraint = null;
if (constraintIndex != -1) { if (constraintIndex != -1) {
constraint = cast(skeleton.constraints[constraintIndex], PhysicsConstraint); constraint = cast(skeleton.constraints[constraintIndex], PhysicsConstraint);
if (!constraint.active) return; if (!constraint.active)
return;
} }
var frames:Array<Float> = this.frames; var frames:Array<Float> = this.frames;
@ -74,14 +74,16 @@ class PhysicsConstraintResetTimeline extends Timeline implements ConstraintTimel
lastTime = -1; lastTime = -1;
} else if (lastTime >= frames[frames.length - 1]) // Last time is after last frame. } else if (lastTime >= frames[frames.length - 1]) // Last time is after last frame.
return; return;
if (time < frames[0]) return; if (time < frames[0])
return;
if (lastTime < frames[0] || time >= frames[Timeline.search1(frames, lastTime) + 1]) { if (lastTime < frames[0] || time >= frames[Timeline.search1(frames, lastTime) + 1]) {
if (constraint != null) if (constraint != null)
constraint.reset(skeleton); constraint.reset(skeleton);
else { else {
for (constraint in skeleton.physics) { for (constraint in skeleton.physics) {
if (constraint.active) constraint.reset(skeleton); if (constraint.active)
constraint.reset(skeleton);
} }
} }
} }

View File

@ -46,5 +46,4 @@ class PhysicsConstraintStrengthTimeline extends PhysicsConstraintTimeline {
public function global(constraint:PhysicsConstraintData):Bool { public function global(constraint:PhysicsConstraintData):Bool {
return constraint.strengthGlobal; return constraint.strengthGlobal;
} }
} }

View File

@ -42,9 +42,8 @@ abstract class PhysicsConstraintTimeline extends ConstraintTimeline1 {
super(frameCount, bezierCount, constraintIndex, property); super(frameCount, bezierCount, constraintIndex, property);
} }
public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend, direction:MixDirection,
blend:MixBlend, direction:MixDirection, appliedPose:Bool) { appliedPose:Bool) {
if (constraintIndex == -1) { if (constraintIndex == -1) {
var value:Float = time >= frames[0] ? getCurveValue(time) : 0; var value:Float = time >= frames[0] ? getCurveValue(time) : 0;
for (constraint in skeleton.physics) { for (constraint in skeleton.physics) {

View File

@ -46,5 +46,4 @@ class PhysicsConstraintWindTimeline extends PhysicsConstraintTimeline {
public function global(constraint:PhysicsConstraintData):Bool { public function global(constraint:PhysicsConstraintData):Bool {
return constraint.windGlobal; return constraint.windGlobal;
} }
} }

View File

@ -40,9 +40,7 @@ class RGB2Timeline extends SlotCurveTimeline {
private static inline var B2:Int = 6; private static inline var B2:Int = 6;
public function new(frameCount:Int, bezierCount:Int, slotIndex:Int) { public function new(frameCount:Int, bezierCount:Int, slotIndex:Int) {
super(frameCount, bezierCount, slotIndex, super(frameCount, bezierCount, slotIndex, Property.rgb + "|" + slotIndex, Property.rgb2 + "|" + slotIndex);
Property.rgb + "|" + slotIndex,
Property.rgb2 + "|" + slotIndex);
} }
public override function getFrameEntries():Int { public override function getFrameEntries():Int {

View File

@ -41,11 +41,13 @@ class RGBA2Timeline extends SlotCurveTimeline {
private static inline var B2:Int = 7; private static inline var B2:Int = 7;
public function new(frameCount:Int, bezierCount:Int, slotIndex:Int) { public function new(frameCount:Int, bezierCount:Int, slotIndex:Int) {
super(frameCount, bezierCount, slotIndex, super(frameCount, bezierCount, slotIndex, Property.rgb
Property.rgb + "|" + slotIndex, + "|"
Property.alpha + "|" + slotIndex, + slotIndex, Property.alpha
Property.rgb2 + "|" + slotIndex + "|"
); + slotIndex, Property.rgb2
+ "|"
+ slotIndex);
} }
public override function getFrameEntries():Int { public override function getFrameEntries():Int {

View File

@ -38,9 +38,7 @@ class RGBATimeline extends SlotCurveTimeline {
private static inline var A:Int = 4; private static inline var A:Int = 4;
public function new(frameCount:Int, bezierCount:Int, slotIndex:Int) { public function new(frameCount:Int, bezierCount:Int, slotIndex:Int) {
super(frameCount, bezierCount, slotIndex, super(frameCount, bezierCount, slotIndex, Property.rgb + "|" + slotIndex, Property.alpha + "|" + slotIndex);
Property.rgb + "|" + slotIndex,
Property.alpha + "|" + slotIndex);
} }
public override function getFrameEntries():Int { public override function getFrameEntries():Int {

View File

@ -42,8 +42,7 @@ class SequenceTimeline extends Timeline implements SlotTimeline {
var attachment:HasTextureRegion; var attachment:HasTextureRegion;
public function new(frameCount:Int, slotIndex:Int, attachment:HasTextureRegion) { public function new(frameCount:Int, slotIndex:Int, attachment:HasTextureRegion) {
super(frameCount, super(frameCount, Std.string(Property.sequence) + "|" + Std.string(slotIndex) + "|" + Std.string(attachment.sequence.id));
Std.string(Property.sequence) + "|" + Std.string(slotIndex) + "|" + Std.string(attachment.sequence.id));
this.slotIndex = slotIndex; this.slotIndex = slotIndex;
this.attachment = attachment; this.attachment = attachment;
} }
@ -70,11 +69,11 @@ class SequenceTimeline extends Timeline implements SlotTimeline {
frames[frame + SequenceTimeline.DELAY] = delay; frames[frame + SequenceTimeline.DELAY] = delay;
} }
public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend, direction:MixDirection,
blend:MixBlend, direction:MixDirection, appliedPose:Bool) { appliedPose:Bool) {
var slot = skeleton.slots[this.slotIndex]; var slot = skeleton.slots[this.slotIndex];
if (!slot.bone.active) return; if (!slot.bone.active)
return;
var pose = appliedPose ? slot.applied : slot.pose; var pose = appliedPose ? slot.applied : slot.pose;
var slotAttachment = pose.attachment; var slotAttachment = pose.attachment;
@ -85,12 +84,14 @@ class SequenceTimeline extends Timeline implements SlotTimeline {
} }
if (direction == MixDirection.mixOut) { if (direction == MixDirection.mixOut) {
if (blend == MixBlend.setup) pose.sequenceIndex = -1; if (blend == MixBlend.setup)
pose.sequenceIndex = -1;
return; return;
} }
if (time < frames[0]) { if (time < frames[0]) {
if (blend == MixBlend.setup || blend == MixBlend.first) pose.sequenceIndex = -1; if (blend == MixBlend.setup || blend == MixBlend.first)
pose.sequenceIndex = -1;
return; return;
} }

View File

@ -37,9 +37,8 @@ class SliderMixTimeline extends ConstraintTimeline1 {
super(frameCount, bezierCount, constraintIndex, Property.sliderMix); super(frameCount, bezierCount, constraintIndex, Property.sliderMix);
} }
public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend, direction:MixDirection,
blend:MixBlend, direction:MixDirection, appliedPose:Bool) { appliedPose:Bool) {
var constraint = cast(skeleton.constraints[constraintIndex], Slider); var constraint = cast(skeleton.constraints[constraintIndex], Slider);
if (constraint.active) { if (constraint.active) {
var pose = appliedPose ? constraint.applied : constraint.pose; var pose = appliedPose ? constraint.applied : constraint.pose;

View File

@ -35,9 +35,8 @@ class SliderTimeline extends ConstraintTimeline1 {
super(frameCount, bezierCount, constraintIndex, Property.sliderTime); super(frameCount, bezierCount, constraintIndex, Property.sliderTime);
} }
public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend, direction:MixDirection,
blend:MixBlend, direction:MixDirection, appliedPose:Bool) { appliedPose:Bool) {
var constraint = cast(skeleton.constraints[constraintIndex], Slider); var constraint = cast(skeleton.constraints[constraintIndex], Slider);
if (constraint.active) { if (constraint.active) {
var pose = appliedPose ? constraint.applied : constraint.pose; var pose = appliedPose ? constraint.applied : constraint.pose;

View File

@ -41,11 +41,11 @@ abstract class SlotCurveTimeline extends CurveTimeline implements SlotTimeline {
return slotIndex; return slotIndex;
} }
public function apply (skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend, public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend, direction:MixDirection,
direction:MixDirection, appliedPose:Bool) { appliedPose:Bool) {
var slot = skeleton.slots[slotIndex]; var slot = skeleton.slots[slotIndex];
if (slot.bone.active) apply1(slot, appliedPose ? slot.applied : slot.pose, time, alpha, blend); if (slot.bone.active)
apply1(slot, appliedPose ? slot.applied : slot.pose, time, alpha, blend);
} }
abstract function apply1(slot:Slot, pose:SlotPose, time:Float, alpha:Float, blend:MixBlend):Void; abstract function apply1(slot:Slot, pose:SlotPose, time:Float, alpha:Float, blend:MixBlend):Void;

View File

@ -36,6 +36,7 @@ import spine.Skeleton;
abstract class Timeline { abstract class Timeline {
/** Uniquely encodes both the type of this timeline and the skeleton properties that it affects. */ /** Uniquely encodes both the type of this timeline and the skeleton properties that it affects. */
public var propertyIds:Array<String>; public var propertyIds:Array<String>;
/** The time in seconds and any other values for each frame. */ /** The time in seconds and any other values for each frame. */
public var frames:Array<Float>; public var frames:Array<Float>;
@ -83,8 +84,8 @@ abstract class Timeline {
* @param direction Indicates whether the timeline is mixing in or out. Used by timelines which perform instant transitions, * @param direction Indicates whether the timeline is mixing in or out. Used by timelines which perform instant transitions,
* such as spine.animation.DrawOrderTimeline or spine.animation.AttachmentTimeline, and others such as spine.animation.ScaleTimeline. * such as spine.animation.DrawOrderTimeline or spine.animation.AttachmentTimeline, and others such as spine.animation.ScaleTimeline.
* @param appliedPose True to to modify the applied pose. */ * @param appliedPose True to to modify the applied pose. */
abstract public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, abstract public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend, direction:MixDirection,
blend:MixBlend, direction:MixDirection, appliedPose:Bool):Void; appliedPose:Bool):Void;
/** Linear search using a stride of 1. /** Linear search using a stride of 1.
* @param time Must be >= the first value in frames. * @param time Must be >= the first value in frames.

View File

@ -38,34 +38,43 @@ import spine.Poolable;
class TrackEntry implements Poolable { class TrackEntry implements Poolable {
/** The animation to apply for this track entry. */ /** The animation to apply for this track entry. */
public var animation:Animation; public var animation:Animation;
/** The animation queued to start after this animation, or null if there is none. next makes up a doubly linked /** The animation queued to start after this animation, or null if there is none. next makes up a doubly linked
* list. * list.
* *
* See spine.animation.AnimationState.clearNext(TrackEntry) to truncate the list. */ * See spine.animation.AnimationState.clearNext(TrackEntry) to truncate the list. */
public var next:TrackEntry; public var next:TrackEntry;
/** The animation queued to play before this animation, or null. previous makes up a doubly linked list. */ /** The animation queued to play before this animation, or null. previous makes up a doubly linked list. */
public var previous:TrackEntry; public var previous:TrackEntry;
/** The track entry for the previous animation when mixing from the previous animation to this animation, or null if no /** The track entry for the previous animation when mixing from the previous animation to this animation, or null if no
* mixing is currently occurring. When mixing from multiple animations, mixingFrom makes up a linked list. */ * mixing is currently occurring. When mixing from multiple animations, mixingFrom makes up a linked list. */
public var mixingFrom:TrackEntry; public var mixingFrom:TrackEntry;
/** The track entry for the next animation when mixing from this animation to the next animation, or null if no mixing is /** The track entry for the next animation when mixing from this animation to the next animation, or null if no mixing is
* currently occurring. When mixing to multiple animations, mixingTo makes up a linked list. */ * currently occurring. When mixing to multiple animations, mixingTo makes up a linked list. */
public var mixingTo:TrackEntry; public var mixingTo:TrackEntry;
public var onStart:Listeners = new Listeners(); public var onStart:Listeners = new Listeners();
public var onInterrupt:Listeners = new Listeners(); public var onInterrupt:Listeners = new Listeners();
public var onEnd:Listeners = new Listeners(); public var onEnd:Listeners = new Listeners();
public var onDispose:Listeners = new Listeners(); public var onDispose:Listeners = new Listeners();
public var onComplete:Listeners = new Listeners(); public var onComplete:Listeners = new Listeners();
public var onEvent:EventListeners = new EventListeners(); public var onEvent:EventListeners = new EventListeners();
/** The index of the track where this track entry is either current or queued. /** The index of the track where this track entry is either current or queued.
* *
* See spine.animation.AnimationState.getCurrent(int). */ * See spine.animation.AnimationState.getCurrent(int). */
public var trackIndex:Int = 0; public var trackIndex:Int = 0;
/** If true, the animation will repeat. If false it will not, instead its last frame is applied if played beyond its /** If true, the animation will repeat. If false it will not, instead its last frame is applied if played beyond its
* duration. */ * duration. */
public var loop:Bool = false; public var loop:Bool = false;
/** If true, the animation will be applied in reverse. Events are not fired when an animation is applied in reverse. */ /** If true, the animation will be applied in reverse. Events are not fired when an animation is applied in reverse. */
public var reverse:Bool = false; public var reverse:Bool = false;
/** If true, when mixing from the previous animation to this animation, the previous animation is applied as normal instead /** If true, when mixing from the previous animation to this animation, the previous animation is applied as normal instead
* of being mixed out. * of being mixed out.
* *
@ -78,34 +87,42 @@ class TrackEntry implements Poolable {
* Snapping will occur if holdPrevious is true and this animation does not key all the same properties as the * Snapping will occur if holdPrevious is true and this animation does not key all the same properties as the
* previous animation. */ * previous animation. */
public var holdPrevious:Bool = false; public var holdPrevious:Bool = false;
/** When the mix percentage (TrackEntry.getMixTime() / TrackEntry.getMixDuration()) is less than the /** When the mix percentage (TrackEntry.getMixTime() / TrackEntry.getMixDuration()) is less than the
* eventThreshold, event timelines are applied while this animation is being mixed out. Defaults to 0, so event * eventThreshold, event timelines are applied while this animation is being mixed out. Defaults to 0, so event
* timelines are not applied while this animation is being mixed out. */ * timelines are not applied while this animation is being mixed out. */
public var eventThreshold:Float = 0; public var eventThreshold:Float = 0;
/** When the mix percentage (TrackEntry.getMixTime() / TrackEntry.getMixDuration()) is less than the /** When the mix percentage (TrackEntry.getMixTime() / TrackEntry.getMixDuration()) is less than the
* mixAttachmentThreshold, attachment timelines are applied while this animation is being mixed out. Defaults * mixAttachmentThreshold, attachment timelines are applied while this animation is being mixed out. Defaults
* to 0, so attachment timelines are not applied while this animation is being mixed out. */ * to 0, so attachment timelines are not applied while this animation is being mixed out. */
public var mixAttachmentThreshold:Float = 0; public var mixAttachmentThreshold:Float = 0;
/** When TrackEntry.getAlpha() is greater than alphaAttachmentThreshold, attachment timelines are applied. /** When TrackEntry.getAlpha() is greater than alphaAttachmentThreshold, attachment timelines are applied.
* Defaults to 0, so attachment timelines are always applied. */ * Defaults to 0, so attachment timelines are always applied. */
public var alphaAttachmentThreshold:Float = 0; public var alphaAttachmentThreshold:Float = 0;
/** When the mix percentage (TrackEntry.getMixTime() / TrackEntry.getMixDuration()) is less than the /** When the mix percentage (TrackEntry.getMixTime() / TrackEntry.getMixDuration()) is less than the
* mixDrawOrderThreshold, draw order timelines are applied while this animation is being mixed out. Defaults to * mixDrawOrderThreshold, draw order timelines are applied while this animation is being mixed out. Defaults to
* 0, so draw order timelines are not applied while this animation is being mixed out. */ * 0, so draw order timelines are not applied while this animation is being mixed out. */
public var mixDrawOrderThreshold:Float = 0; public var mixDrawOrderThreshold:Float = 0;
/** Seconds when this animation starts, both initially and after looping. Defaults to 0. /** Seconds when this animation starts, both initially and after looping. Defaults to 0.
* *
* When changing the animationStart time, it often makes sense to set TrackEntry.getAnimationLast() to the same * When changing the animationStart time, it often makes sense to set TrackEntry.getAnimationLast() to the same
* value to prevent timeline keys before the start time from triggering. */ * value to prevent timeline keys before the start time from triggering. */
public var animationStart:Float = 0; public var animationStart:Float = 0;
/** Seconds for the last frame of this animation. Non-looping animations won't play past this time. Looping animations will /** Seconds for the last frame of this animation. Non-looping animations won't play past this time. Looping animations will
* loop back to TrackEntry.getAnimationStart() at this time. Defaults to the animation spine.animation.Animation.duration. */ * loop back to TrackEntry.getAnimationStart() at this time. Defaults to the animation spine.animation.Animation.duration. */
public var animationEnd:Float = 0; public var animationEnd:Float = 0;
/** The time in seconds this animation was last applied. Some timelines use this for one-time triggers. Eg, when this /** The time in seconds this animation was last applied. Some timelines use this for one-time triggers. Eg, when this
* animation is applied, event timelines will fire all events between the animationLast time (exclusive) and * animation is applied, event timelines will fire all events between the animationLast time (exclusive) and
* animationTime (inclusive). Defaults to -1 to ensure triggers on frame 0 happen the first time this animation * animationTime (inclusive). Defaults to -1 to ensure triggers on frame 0 happen the first time this animation
* is applied. */ * is applied. */
public var animationLast:Float = 0; public var animationLast:Float = 0;
public var nextAnimationLast:Float = 0; public var nextAnimationLast:Float = 0;
/** Seconds to postpone playing the animation. Must be >= 0. When this track entry is the current track entry, /** Seconds to postpone playing the animation. Must be >= 0. When this track entry is the current track entry,
@ -125,8 +142,10 @@ class TrackEntry implements Poolable {
* TrackEntry.getAnimationTime(). The track time can be set to start the animation at a time other than 0, without affecting * TrackEntry.getAnimationTime(). The track time can be set to start the animation at a time other than 0, without affecting
* looping. */ * looping. */
public var trackTime:Float = 0; public var trackTime:Float = 0;
public var trackLast:Float = 0; public var trackLast:Float = 0;
public var nextTrackLast:Float = 0; public var nextTrackLast:Float = 0;
/** The track time in seconds when this animation will be removed from the track. Defaults to the highest possible float /** The track time in seconds when this animation will be removed from the track. Defaults to the highest possible float
* value, meaning the animation will be applied until a new animation is set or the track is cleared. If the track end time * value, meaning the animation will be applied until a new animation is set or the track is cleared. If the track end time
* is reached, no other animations are queued for playback, and mixing from any previous animations is complete, then the * is reached, no other animations are queued for playback, and mixing from any previous animations is complete, then the
@ -135,6 +154,7 @@ class TrackEntry implements Poolable {
* It may be desired to use spine.animation.AnimationState.addEmptyAnimation(int, float, float) rather than have the animation * It may be desired to use spine.animation.AnimationState.addEmptyAnimation(int, float, float) rather than have the animation
* abruptly cease being applied. */ * abruptly cease being applied. */
public var trackEnd:Float = 0; public var trackEnd:Float = 0;
/** Multiplier for the delta time when this track entry is updated, causing time for this animation to pass slower or /** Multiplier for the delta time when this track entry is updated, causing time for this animation to pass slower or
* faster. Defaults to 1. * faster. Defaults to 1.
* *
@ -149,15 +169,18 @@ class TrackEntry implements Poolable {
* *
* See AnimationState spine.animation.AnimationState.getTimeScale() for affecting all animations. */ * See AnimationState spine.animation.AnimationState.getTimeScale() for affecting all animations. */
public var timeScale:Float = 0; public var timeScale:Float = 0;
/** Values < 1 mix this animation with the skeleton's current pose (usually the pose resulting from lower tracks). Defaults /** Values < 1 mix this animation with the skeleton's current pose (usually the pose resulting from lower tracks). Defaults
* to 1, which overwrites the skeleton's current pose with this animation. * to 1, which overwrites the skeleton's current pose with this animation.
* *
* Typically track 0 is used to completely pose the skeleton, then alpha is used on higher tracks. It doesn't make sense to * Typically track 0 is used to completely pose the skeleton, then alpha is used on higher tracks. It doesn't make sense to
* use alpha on track 0 if the skeleton pose is from the last frame render. */ * use alpha on track 0 if the skeleton pose is from the last frame render. */
public var alpha:Float = 0; public var alpha:Float = 0;
/** Seconds from 0 to the TrackEntry.getMixDuration() when mixing from the previous animation to this animation. May be /** Seconds from 0 to the TrackEntry.getMixDuration() when mixing from the previous animation to this animation. May be
* slightly more than mixDuration when the mix is complete. */ * slightly more than mixDuration when the mix is complete. */
public var mixTime:Float = 0; public var mixTime:Float = 0;
/** Seconds for mixing from the previous animation to this animation. Defaults to the value provided by AnimationStateData /** Seconds for mixing from the previous animation to this animation. Defaults to the value provided by AnimationStateData
* spine.animation.AnimationStateData.getMix(Animation, Animation) based on the animation before this animation (if any). * spine.animation.AnimationStateData.getMix(Animation, Animation) based on the animation before this animation (if any).
* *
@ -176,8 +199,10 @@ class TrackEntry implements Poolable {
* Alternatively, TrackEntry.setMixDuration(float, float) can be used to recompute the delay: * Alternatively, TrackEntry.setMixDuration(float, float) can be used to recompute the delay:
* entry.setMixDuration(0.25f, 0); */ * entry.setMixDuration(0.25f, 0); */
public var mixDuration:Float = 0; public var mixDuration:Float = 0;
public var interruptAlpha:Float = 0; public var interruptAlpha:Float = 0;
public var totalAlpha:Float = 0; public var totalAlpha:Float = 0;
/** Controls how properties keyed in the animation are mixed with lower tracks. Defaults to spine.animation.MixBlend.replace. /** Controls how properties keyed in the animation are mixed with lower tracks. Defaults to spine.animation.MixBlend.replace.
* *
* Track entries on track 0 ignore this setting and always use spine.animation.MixBlend.first. * Track entries on track 0 ignore this setting and always use spine.animation.MixBlend.first.
@ -185,9 +210,11 @@ class TrackEntry implements Poolable {
* The mixBlend can be set for a new track entry only before spine.animation.AnimationState.apply(Skeleton) is first * The mixBlend can be set for a new track entry only before spine.animation.AnimationState.apply(Skeleton) is first
* called. */ * called. */
public var mixBlend:MixBlend = MixBlend.replace; public var mixBlend:MixBlend = MixBlend.replace;
public var timelineMode:Array<Int> = new Array<Int>(); public var timelineMode:Array<Int> = new Array<Int>();
public var timelineHoldMix:Array<TrackEntry> = new Array<TrackEntry>(); public var timelineHoldMix:Array<TrackEntry> = new Array<TrackEntry>();
public var timelinesRotation:Array<Float> = new Array<Float>(); public var timelinesRotation:Array<Float> = new Array<Float>();
/** If true, mixing rotation between tracks always uses the shortest rotation direction. If the rotation is animated, the /** If true, mixing rotation between tracks always uses the shortest rotation direction. If the rotation is animated, the
* shortest rotation direction may change during the mix. * shortest rotation direction may change during the mix.
* *
@ -196,7 +223,8 @@ class TrackEntry implements Poolable {
public var shortestRotation = false; public var shortestRotation = false;
function set_delay(delay:Float):Float { function set_delay(delay:Float):Float {
if (delay < 0) throw new SpineException("delay must be >= 0."); if (delay < 0)
throw new SpineException("delay must be >= 0.");
return this.delay = delay; return this.delay = delay;
} }

View File

@ -72,11 +72,11 @@ class TransformConstraintTimeline extends CurveTimeline implements ConstraintTim
frames[frame + SHEARY] = mixShearY; frames[frame + SHEARY] = mixShearY;
} }
public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, public function apply(skeleton:Skeleton, lastTime:Float, time:Float, events:Array<Event>, alpha:Float, blend:MixBlend, direction:MixDirection,
blend:MixBlend, direction:MixDirection, appliedPose:Bool) { appliedPose:Bool) {
var constraint = cast(skeleton.constraints[constraintIndex], TransformConstraint); var constraint = cast(skeleton.constraints[constraintIndex], TransformConstraint);
if (!constraint.active) return; if (!constraint.active)
return;
var pose = appliedPose ? constraint.applied : constraint.pose; var pose = appliedPose ? constraint.applied : constraint.pose;
if (time < frames[0]) { if (time < frames[0]) {

View File

@ -37,6 +37,7 @@ class ClippingAttachment extends VertexAttachment {
/** Clipping is performed between the clipping attachment's slot and the end slot. If null clipping is done until the end of /** Clipping is performed between the clipping attachment's slot and the end slot. If null clipping is done until the end of
* the skeleton's rendering. */ * the skeleton's rendering. */
public var endSlot:SlotData; public var endSlot:SlotData;
/** The color of the clipping attachment as it was in Spine, or a default color if nonessential data was not exported. Clipping /** The color of the clipping attachment as it was in Spine, or a default color if nonessential data was not exported. Clipping
* attachments are not usually rendered at runtime. */ * attachments are not usually rendered at runtime. */
public var color:Color = new Color(0.2275, 0.2275, 0.2275, 1); public var color:Color = new Color(0.2275, 0.2275, 0.2275, 1);

View File

@ -40,23 +40,32 @@ import spine.atlas.TextureAtlasPage;
class MeshAttachment extends VertexAttachment implements HasTextureRegion { class MeshAttachment extends VertexAttachment implements HasTextureRegion {
public var region:TextureRegion; public var region:TextureRegion;
public var path:String; public var path:String;
/** The UV pair for each vertex, normalized within the texture region. */ /** The UV pair for each vertex, normalized within the texture region. */
public var regionUVs = new Array<Float>(); public var regionUVs = new Array<Float>();
/** The UV pair for each vertex, normalized within the entire texture. /** The UV pair for each vertex, normalized within the entire texture.
* See #updateRegion(). */ * See #updateRegion(). */
public var uvs = new Array<Float>(); public var uvs = new Array<Float>();
/** Triplets of vertex indices which describe the mesh's triangulation. */ /** Triplets of vertex indices which describe the mesh's triangulation. */
public var triangles = new Array<Int>(); public var triangles = new Array<Int>();
public var color:Color = new Color(1, 1, 1, 1); public var color:Color = new Color(1, 1, 1, 1);
/** The width of the mesh's image, or zero if nonessential data was not exported. */ /** The width of the mesh's image, or zero if nonessential data was not exported. */
public var width:Float = 0; public var width:Float = 0;
/** The height of the mesh's image, or zero if nonessential data was not exported. */ /** The height of the mesh's image, or zero if nonessential data was not exported. */
public var height:Float = 0; public var height:Float = 0;
/** The number of entries at the beginning of #vertices that make up the mesh hull. */ /** The number of entries at the beginning of #vertices that make up the mesh hull. */
public var hullLength:Int = 0; public var hullLength:Int = 0;
/** Vertex index pairs describing edges for controlling triangulation, or null if nonessential data was not exported. Mesh /** Vertex index pairs describing edges for controlling triangulation, or null if nonessential data was not exported. Mesh
* triangles will never cross edges. Triangulation is not performed at runtime. */ * triangles will never cross edges. Triangulation is not performed at runtime. */
public var edges = new Array<Int>(); public var edges = new Array<Int>();
public var rendererObject:Dynamic; public var rendererObject:Dynamic;
public var sequence:Sequence; public var sequence:Sequence;
@ -86,7 +95,8 @@ class MeshAttachment extends VertexAttachment implements HasTextureRegion {
var n = uvs.length; var n = uvs.length;
var u = region.u, v = region.v, width:Float = 0, height:Float = 0; var u = region.u, v = region.v, width:Float = 0, height:Float = 0;
if (Std.isOfType(region, TextureAtlasRegion)) { if (Std.isOfType(region, TextureAtlasRegion)) {
var atlasRegion:TextureAtlasRegion = cast(region, TextureAtlasRegion), page:TextureAtlasPage = atlasRegion.page; var atlasRegion:TextureAtlasRegion = cast(region, TextureAtlasRegion),
page:TextureAtlasPage = atlasRegion.page;
var textureWidth = page.width, textureHeight = page.height; var textureWidth = page.width, textureHeight = page.height;
switch (atlasRegion.degrees) { switch (atlasRegion.degrees) {
case 90: case 90:

View File

@ -39,11 +39,14 @@ import spine.Color;
class PathAttachment extends VertexAttachment { class PathAttachment extends VertexAttachment {
/** The lengths along the path in the setup pose from the start of the path to the end of each Bezier curve. */ /** The lengths along the path in the setup pose from the start of the path to the end of each Bezier curve. */
public var lengths:Array<Float>; public var lengths:Array<Float>;
/** If true, the start and end knots are connected. */ /** If true, the start and end knots are connected. */
public var closed:Bool = false; public var closed:Bool = false;
/** If true, additional calculations are performed to make computing positions along the path more accurate and movement along /** If true, additional calculations are performed to make computing positions along the path more accurate and movement along
* the path have a constant speed. */ * the path have a constant speed. */
public var constantSpeed:Bool = false; public var constantSpeed:Bool = false;
/** The color of the path as it was in Spine, or a default color if nonessential data was not exported. Paths are not usually /** The color of the path as it was in Spine, or a default color if nonessential data was not exported. Paths are not usually
* rendered at runtime. */ * rendered at runtime. */
public var color:Color = new Color(0, 0, 0, 0); public var color:Color = new Color(0, 0, 0, 0);

Some files were not shown because too many files have changed in this diff Show More