mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 22:49:01 +08:00
Merge remote-tracking branch 'origin/3.6-beta' into 3.6-beta
This commit is contained in:
commit
896585f92e
17
.gitignore
vendored
17
.gitignore
vendored
@ -33,6 +33,7 @@ spine-cocos2dx/example/cocos2dx.zip
|
||||
spine-cocos2dx/example/__MACOSX
|
||||
spine-cocos2dx/example/cocos2d
|
||||
spine-cocos2dx/example/proj.win32/spine-cocos2d-x.VC.opendb
|
||||
spine-cocos2dx/example/proj.win32/spine-cocos2d-x.VC.db
|
||||
xcuserdata/
|
||||
|
||||
spine-cocos2d-objc/cocos2d/*
|
||||
@ -44,20 +45,8 @@ spine-csharp/src/*.meta
|
||||
spine-csharp/src/*.cs.meta
|
||||
spine-csharp/src/Attachments/*.cs.meta
|
||||
|
||||
spine-monogame/xamarinstudio-ios/src/bin
|
||||
spine-monogame/xamarinstudio-ios/src/obj
|
||||
spine-monogame/xamarinstudio-ios/src/packages
|
||||
|
||||
spine-monogame/xamarinstudio-ios/example/bin
|
||||
spine-monogame/xamarinstudio-ios/example/obj
|
||||
spine-monogame/xamarinstudio-ios/example/packages
|
||||
|
||||
spine-monogame/windows8-store/src/bin
|
||||
spine-monogame/windows8-store/src/obj
|
||||
|
||||
spine-monogame/windows8-store/example/spine-monogame-example_TemporaryKey.pfx
|
||||
spine-monogame/windows8-store/example/obj/*
|
||||
spine-monogame/windows8-store/example/bin/*
|
||||
spine-monogame/example/bin
|
||||
spine-monogame/example/obj
|
||||
|
||||
spine-xna/bin
|
||||
spine-xna/obj
|
||||
|
||||
124
CHANGELOG.md
124
CHANGELOG.md
@ -1,3 +1,121 @@
|
||||
# 3.6.x
|
||||
* [c] Modified kvec.h used by SkeletonBinary.c to use Spine's MALLOC/FREE macros. That way there's only one place
|
||||
to inject custom allocators ([extension.h](https://github.com/EsotericSoftware/spine-runtimes/blob/master/spine-c/spine-c/include/spine/extension.h)) [commit](https://github.com/EsotericSoftware/spine-runtimes/commit/c2cfbc6cb8709daa082726222d558188d75a004f)
|
||||
# 3.6
|
||||
|
||||
## AS3
|
||||
* **Breaking changes**
|
||||
* Removed `Bone.worldToLocalRotationX` and `Bone.worldToLocalRotationY`. Replaced by `Bone.worldToLocalRotation` (rotation given relative to x-axis, counter-clockwise, in degrees).
|
||||
* Made `Bone` fields `_a`, `_b`, `_c`, `_d`, `_worldX` and `_worldY` public, removed underscore prefix.
|
||||
* Removed `VertexAttachment.computeWorldVertices` overload, changed `VertexAttachment.computeWorldVertices2` to `VertexAttachment.computeWorldVertices`, added `stride` parameter.
|
||||
* Removed `RegionAttachment.vertices` field. The vertices array is provided to `RegionAttachment.computeWorldVertices` by the API user now.
|
||||
* Removed `RegionAttachment.updateWorldVertices`, added `RegionAttachment.computeWorldVertices`. The new method now computes the x/y positions of the 4 vertices of the corner and places them in the provided `worldVertices` array, starting at `offset`, then moving by `stride` array elements when advancing to the next vertex. This allows to directly compose the vertex buffer and avoids a copy. The computation of the full vertices, including vertex colors and texture coordinates, is now done by the backend's respective renderer.
|
||||
* Replaced `r`, `g`, `b`, `a` fields with instances of new `Color` class in `RegionAttachment`, `MeshAttachment`, `Skeleton`, `SkeletonData`, `Slot` and `SlotData`.
|
||||
* **Additions**
|
||||
* Added `Skeleton.getBounds` from reference implementation.
|
||||
* Added support for local and relative transform constraint calculation, including additional fields in `TransformConstraintData`
|
||||
* Added `Bone.localToWorldRotation`(rotation given relative to x-axis, counter-clockwise, in degrees).
|
||||
* Added two color tinting support, including `TwoColorTimeline` and additional fields on `Slot` and `SlotData`.
|
||||
* Added `PointAttachment`, additional method `newPointAttachment` in `AttachmentLoader` interface.
|
||||
|
||||
### Starling
|
||||
* Fixed renderer to work with 3.6 changes.
|
||||
* Added support for two color tinting.
|
||||
|
||||
## C
|
||||
* **Breaking changes**
|
||||
* `spVertexAttachment_computeWorldVertices` and `spRegionAttachment_computeWorldVerticeS` now take new parameters to make it possible to directly output the calculated vertex positions to a vertex buffer. Removes the need for additional copies in the backends' respective renderers.
|
||||
* Removed `spBoundingBoxAttachment_computeWorldVertices`, superseded by `spVertexAttachment_computeWorldVertices`.
|
||||
* Removed `spPathAttachment_computeWorldVertices` and `spPathAttachment_computeWorldVertices1`, superseded by `spVertexAttachment_computeWorldVertices`.
|
||||
* Removed `sp_MeshAttachment_computeWorldVertices`, superseded by `spVertexAttachment_computeWorldVertices`.
|
||||
* Removed `spBone_worldToLocalRotationX` and `spBone_worldToLocalRotationY`. Replaced by `spBone_worldToLocalRotation` (rotation given relative to x-axis, counter-clockwise, in degrees).
|
||||
* Replaced `r`, `g`, `b`, `a` fields with instances of new `spColor` struct in `spRegionAttachment`, `spMeshAttachment`, `spSkeleton`, `spSkeletonData`, `spSlot` and `spSlotData`.
|
||||
* **Additions**
|
||||
* Added support for local and relative transform constraint calculation, including additional fields in `spTransformConstraintData`.
|
||||
* Added `spPointAttachment`, additional method `spAtlasAttachmentLoadeR_newPointAttachment`.
|
||||
* Added support for local and relative transform constraint calculation, including additional fields in `TransformConstraintData`
|
||||
* Added `spBone_localToWorldRotation`(rotation given relative to x-axis, counter-clockwise, in degrees).
|
||||
* Added two color tinting support, including `spTwoColorTimeline` and additional fields on `spSlot` and `spSlotData`.
|
||||
* Added `userData` field to `spTrackEntry`, so users can expose data in `spAnimationState` callbacks.
|
||||
* Modified kvec.h used by SkeletonBinary.c to use Spine's MALLOC/FREE macros. That way there's only one place to inject custom allocators ([extension.h](https://github.com/EsotericSoftware/spine-runtimes/blob/master/spine-c/spine-c/include/spine/extension.h)) [commit](https://github.com/EsotericSoftware/spine-runtimes/commit/c2cfbc6cb8709daa082726222d558188d75a004f)
|
||||
|
||||
### Cocos2d-X
|
||||
* Fixed renderer to work with 3.6 changes
|
||||
* Optimized rendering by removing all per-frame allocation in `SkeletonRenderer`, resulting in 15% performance increase for large numbers of skeletons being rendered per frame.
|
||||
* Added support for two color tinting. Tinting is enabled/disabled per `SkeletonRenderer`/`SkeletonAnimation` instance. Use `SkeletonRenderer::setTwoColorTint()`. Note that two color tinting requires the use of a non-standard shader and vertex format. This means that skeletons rendered with two color tinting will break batching. However, skeletons with two color tinting enabled and rendered after each other will be batched.
|
||||
* Updated example to use Cocos2d-x 3.14.1.
|
||||
|
||||
### Cocos2d-Objc
|
||||
* Fixed renderer to work with 3.6 changes
|
||||
* Added support for two color tinting. Tinting is enabled/disabled per `SkeletonRenderer/SkeletonAnimation.twoColorTint = true`. Note that two color tinted skeletons do not batch with other nodes.
|
||||
|
||||
### SFML
|
||||
* Fixed renderer to work with 3.6 changes. Sadly, two color tinting does not work, as the vertex format in SFML is fixed.
|
||||
|
||||
### Unreal Engine 4
|
||||
* Fixed renderer to work with 3.6 changes
|
||||
* Added new UPROPERTY to SpineSkeletonRendererComponent called `Color`. This allows to set the tint color of the skeleton in the editor, C++ and Blueprints. Under the hood, the `spSkeleton->color` will be set on every tick of the renderer component.
|
||||
|
||||
## C#
|
||||
* **Breaking changes**
|
||||
* `MeshAttachment.parentMesh` is now a private field to enforce using the `.ParentMesh` setter property in external code. The `MeshAttachment.ParentMesh` property is an appropriate replacement wherever `.parentMesh` was used.
|
||||
|
||||
### Unity
|
||||
* Fixed renderer to work with 3.6 changes.
|
||||
* Two color tinting is currently supported via extra UV2 and UV3 mesh vertex streams. To use Two color tinting, you need to:
|
||||
* switch on "Tint Black" under "Advanced...",
|
||||
* use the new `Spine/Skeleton Tint Black` shader, or your own shader that treats the UV2 and UV3 streams similarly.
|
||||
* `SkeletonAnimator` now has autoreset set to true by default. Old prefabs and scene values will have been serialized to whatever value it was previously. This change only applies to new instances of SkeletonAnimator.
|
||||
* Old triangle-winding code has been removed from `SkeletonRenderer`. Please use shaders that have backface culling off.
|
||||
* The code in the example scripts have been switched over to using properties instead of fields. This is in anticipation of both users who want to move the Spine folders to the Unity Plugins folder (compiled as a different assembly), and of Unity 2017's ability to manually define different assemblies.
|
||||
* Warnings and conditionals checking for specific Unity 5.2-and-below incompatibility have been removed.
|
||||
* `AtasRegionAttacher` and `SpriteAttacher` are now part of `Example Modules`, to reflect that they are meant to be used as sample code rather than production.
|
||||
* In the unitypackage, the "spine-csharp" and "spine-unity" folders are now inside a "Spine" folder. This change will only affect fresh imports. Importing the unitypackage to update Spine-Unity in your project will update the appropriate files wherever you have moved them.
|
||||
|
||||
## Lua
|
||||
* **Breaking changes**
|
||||
* Removed `Bone:worldToLocalRotationX` and `Bone:worldToLocalRotationY`. Replaced by `Bone:worldToLocalRotation` (rotation given relative to x-axis, counter-clockwise, in degrees).
|
||||
* `VertexAttachment:computeWorldVertices` now takes offsets and stride to allow compositing vertices directly in a vertex buffer to be send to the GPU. The compositing is now performed in the backends' respective renderers. This also affects the subclasses `MeshAttachment`, `BoundingBoxAttachment` and `PathAttachment`.
|
||||
* Removed `RegionAttachment:updateWorldVertices`, added `RegionAttachment:computeWorldVertices`, which takes offsets and stride to allow compositing vertices directly in a vertex buffer to be send to the GPU. The compositing is now performed in the backends' respective renderers.
|
||||
* Removed `MeshAttachment.worldVertices` field. Computation is now performed in each backends' respective renderer. The `uv` coordinates are now stored in `MeshAttachment.uvs`.
|
||||
* Removed `RegionAttachment.vertices` field. Computation is now performed in each backends respective renderer. The `uv` coordinates for each vertex are now stored in the `RegionAttachment.uvs` field.
|
||||
* **Additions**
|
||||
* Added `Bone:localToWorldRotation`(rotation given relative to x-axis, counter-clockwise, in degrees).
|
||||
* Added two color tinting support, including `TwoColorTimeline` and additional fields on `Slot` and `SlotData`.
|
||||
* Added `PointAttachment`, additional method `newPointAttachment` in `AttachmentLoader` interface.
|
||||
* Added support for local and relative transform constraint calculation, including additional fields in `TransformConstraintData`
|
||||
|
||||
### Love2D
|
||||
* Fixed renderer to work with 3.6 changes
|
||||
* Added support for two color tinting. Enable it via `SkeletonRenderer.new(true)`.
|
||||
|
||||
### Corona
|
||||
* Fixed renderer to work with 3.6 changes. Sadly, two color tinting is not supported, as Corona doesn't let us change the vertex format needed and its doesn't allow to modify shaders in the way needed for two color tinting
|
||||
|
||||
## Typescript/Javascript
|
||||
* **Breaking changes**
|
||||
* `Skeleton.getBounds` takes a scratch array as input so it doesn't have to allocate a new array on each invocation itself. Reduces GC activity.
|
||||
* Removed `Bone.worldToLocalRotationX` and `Bone.worldToLocalRotationY`. Replaced by `Bone.worldToLocalRotation` (rotation given relative to x-axis, counter-clockwise, in degrees).
|
||||
* Removed `VertexAttachment.computeWorldVertices` overload, changed `VertexAttachment.computeWorldVerticesWith` to `VertexAttachment.computeWorldVertices`, added `stride` parameter.
|
||||
* Removed `RegionAttachment.vertices` field. The vertices array is provided to `RegionAttachment.computeWorldVertices` by the API user now.
|
||||
* Removed `RegionAttachment.updateWorldVertices`, added `RegionAttachment.computeWorldVertices`. The new method now computes the x/y positions of the 4 vertices of the corner and places them in the provided `worldVertices` array, starting at `offset`, then moving by `stride` array elements when advancing to the next vertex. This allows to directly compose the vertex buffer and avoids a copy. The computation of the full vertices, including vertex colors and texture coordinates, is now done by the backend's respective renderer.
|
||||
* **Additions**
|
||||
* Added support for local and relative transform constraint calculation, including additional fields in `TransformConstraintData`
|
||||
* Added `Bone.localToWorldRotation`(rotation given relative to x-axis, counter-clockwise, in degrees).
|
||||
* Added two color tinting support, including `TwoColorTimeline` and additional fields on `Slot` and `SlotData`.
|
||||
* Added `PointAttachment`, additional method `newPointAttachment` in `AttachmentLoader` interface.
|
||||
|
||||
### WebGL backend
|
||||
* Fixed renderer to work with 3.6 changes.
|
||||
* Added support for two color tinting.
|
||||
* Improved performance by using `DYNAMIC_DRAW` for vertex buffer objects and fixing bug that copied to much data to the GPU each frame in `PolygonBatcher`/`Mesh`.
|
||||
* Added two color tinting support, enabled by default. You can disable it via the constructors of `SceneRenderer`, `SkeletonRenderer`and `PolygonBatcher`. Note that you will need to use a shader created via `Shader.newTwoColoredTexturedShader` shader with `SkeletonRenderer` and `PolygonBatcher` if two color tinting is enabled.
|
||||
|
||||
### Canvas backend
|
||||
* Fixed renderer to work for 3.6 changes. Sadly, we can't support two color tinting via the Canvas API.
|
||||
* Added support for shearing and non-uniform scaling inherited from parent bones.
|
||||
* Added support for alpha tinting.
|
||||
|
||||
### Three.js backend
|
||||
* Fixed renderer to work with 3.6 changes. Two color tinting is not supported.
|
||||
|
||||
### Widget backend
|
||||
* Fixed renderer to work for 3.6 changes. Supports two color tinting (see webgl backend changes for details).
|
||||
* Added fields `atlasContent` and `jsonContent` to `WidgetConfiguration` allowing you to directly pass the contents of the `.atlas` and `.json` file without having to do a request. See `README.md` and the example for details.
|
||||
|
||||
Binary file not shown.
@ -29,68 +29,71 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.examples {
|
||||
import spine.animation.TrackEntry;
|
||||
import flash.display.Sprite;
|
||||
|
||||
import flash.display.Sprite;
|
||||
import spine.*;
|
||||
import spine.animation.AnimationStateData;
|
||||
import spine.atlas.Atlas;
|
||||
import spine.attachments.AtlasAttachmentLoader;
|
||||
import spine.flash.FlashTextureLoader;
|
||||
import spine.flash.SkeletonAnimation;
|
||||
|
||||
import spine.*;
|
||||
import spine.animation.AnimationStateData;
|
||||
import spine.atlas.Atlas;
|
||||
import spine.attachments.AtlasAttachmentLoader;
|
||||
import spine.flash.FlashTextureLoader;
|
||||
import spine.flash.SkeletonAnimation;
|
||||
[SWF(width = "800", height = "600", frameRate = "60", backgroundColor = "#dddddd")]
|
||||
public class Main extends Sprite {
|
||||
[Embed(source = "/spineboy.atlas", mimeType = "application/octet-stream")]
|
||||
static public const SpineboyAtlas : Class;
|
||||
|
||||
[SWF(width = "800", height = "600", frameRate = "60", backgroundColor = "#dddddd")]
|
||||
public class Main extends Sprite {
|
||||
[Embed(source = "/spineboy.atlas", mimeType = "application/octet-stream")]
|
||||
static public const SpineboyAtlas:Class;
|
||||
[Embed(source = "/spineboy.png")]
|
||||
static public const SpineboyAtlasTexture : Class;
|
||||
|
||||
[Embed(source = "/spineboy.png")]
|
||||
static public const SpineboyAtlasTexture:Class;
|
||||
[Embed(source = "/spineboy.json", mimeType = "application/octet-stream")]
|
||||
static public const SpineboyJson : Class;
|
||||
private var skeleton : SkeletonAnimation;
|
||||
|
||||
[Embed(source = "/spineboy.json", mimeType = "application/octet-stream")]
|
||||
static public const SpineboyJson:Class;
|
||||
public function Main() {
|
||||
var atlas : Atlas = new Atlas(new SpineboyAtlas(), new FlashTextureLoader(new SpineboyAtlasTexture()));
|
||||
var json : SkeletonJson = new SkeletonJson(new AtlasAttachmentLoader(atlas));
|
||||
json.scale = 0.6;
|
||||
var skeletonData : SkeletonData = json.readSkeletonData(new SpineboyJson());
|
||||
|
||||
private var skeleton:SkeletonAnimation;
|
||||
var stateData : AnimationStateData = new AnimationStateData(skeletonData);
|
||||
stateData.setMixByName("walk", "jump", 0.2);
|
||||
stateData.setMixByName("jump", "run", 0.4);
|
||||
stateData.setMixByName("jump", "jump", 0.2);
|
||||
|
||||
public function Main () {
|
||||
var atlas:Atlas = new Atlas(new SpineboyAtlas(), new FlashTextureLoader(new SpineboyAtlasTexture()));
|
||||
var json:SkeletonJson = new SkeletonJson(new AtlasAttachmentLoader(atlas));
|
||||
json.scale = 0.6;
|
||||
var skeletonData:SkeletonData = json.readSkeletonData(new SpineboyJson());
|
||||
skeleton = new SkeletonAnimation(skeletonData, stateData);
|
||||
skeleton.x = 400;
|
||||
skeleton.y = 560;
|
||||
|
||||
var stateData:AnimationStateData = new AnimationStateData(skeletonData);
|
||||
stateData.setMixByName("walk", "jump", 0.2);
|
||||
stateData.setMixByName("jump", "run", 0.4);
|
||||
stateData.setMixByName("jump", "jump", 0.2);
|
||||
skeleton.state.onStart.add(function(entry : TrackEntry) : void {
|
||||
trace(entry.trackIndex + " start: " + entry.animation.name);
|
||||
});
|
||||
skeleton.state.onInterrupt.add(function(entry : TrackEntry) : void {
|
||||
trace(entry.trackIndex + " interrupt: " + entry.animation.name);
|
||||
});
|
||||
skeleton.state.onEnd.add(function(entry : TrackEntry) : void {
|
||||
trace(entry.trackIndex + " end: " + entry.animation.name);
|
||||
});
|
||||
skeleton.state.onComplete.add(function(entry : TrackEntry) : void {
|
||||
trace(entry.trackIndex + " complete: " + entry.animation.name);
|
||||
});
|
||||
skeleton.state.onDispose.add(function(entry : TrackEntry) : void {
|
||||
trace(entry.trackIndex + " dispose: " + entry.animation.name);
|
||||
});
|
||||
skeleton.state.onEvent.add(function(entry : TrackEntry, event : Event) : void {
|
||||
trace(entry.trackIndex + " event: " + entry.animation.name + ", " + event.data.name + ": " + event.intValue + ", " + event.floatValue + ", " + event.stringValue);
|
||||
});
|
||||
|
||||
skeleton = new SkeletonAnimation(skeletonData, stateData);
|
||||
skeleton.x = 400;
|
||||
skeleton.y = 560;
|
||||
|
||||
skeleton.state.onStart.add(function (trackIndex:int) : void {
|
||||
trace(trackIndex + " fuu start: " + skeleton.state.getCurrent(trackIndex));
|
||||
});
|
||||
skeleton.state.onEnd.add(function (trackIndex:int) : void {
|
||||
trace(trackIndex + " end: " + skeleton.state.getCurrent(trackIndex));
|
||||
});
|
||||
skeleton.state.onComplete.add(function (trackIndex:int, count:int) : void {
|
||||
trace(trackIndex + " complete: " + skeleton.state.getCurrent(trackIndex) + ", " + count);
|
||||
});
|
||||
skeleton.state.onEvent.add(function (trackIndex:int, event:Event) : void {
|
||||
trace(trackIndex + " event: " + skeleton.state.getCurrent(trackIndex) + ", "
|
||||
+ event.data.name + ": " + event.intValue + ", " + event.floatValue + ", " + event.stringValue);
|
||||
});
|
||||
|
||||
if (false) {
|
||||
skeleton.state.setAnimationByName(0, "test", true);
|
||||
} else {
|
||||
skeleton.state.setAnimationByName(0, "walk", true);
|
||||
skeleton.state.addAnimationByName(0, "jump", false, 3);
|
||||
skeleton.state.addAnimationByName(0, "run", true, 0);
|
||||
if (false) {
|
||||
skeleton.state.setAnimationByName(0, "test", true);
|
||||
} else {
|
||||
skeleton.state.setAnimationByName(0, "walk", true);
|
||||
skeleton.state.addAnimationByName(0, "jump", false, 3);
|
||||
skeleton.state.addAnimationByName(0, "run", true, 0);
|
||||
}
|
||||
|
||||
addChild(skeleton);
|
||||
}
|
||||
|
||||
addChild(skeleton);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
eclipse.preferences.version=1
|
||||
encoding//src/spine/SkeletonJson.as=UTF-8
|
||||
encoding//src/spine/animation/TwoColorTimeline.as=UTF-8
|
||||
encoding//src/spine/attachments/PointAttachment.as=UTF-8
|
||||
encoding/<project>=UTF-8
|
||||
|
||||
@ -29,18 +29,15 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
public class BlendMode {
|
||||
public static const normal : BlendMode = new BlendMode(0);
|
||||
public static const additive : BlendMode = new BlendMode(1);
|
||||
public static const multiply : BlendMode = new BlendMode(2);
|
||||
public static const screen : BlendMode = new BlendMode(3);
|
||||
public var ordinal : int;
|
||||
|
||||
public class BlendMode {
|
||||
public static const normal:BlendMode = new BlendMode(0);
|
||||
public static const additive:BlendMode = new BlendMode(1);
|
||||
public static const multiply:BlendMode = new BlendMode(2);
|
||||
public static const screen:BlendMode = new BlendMode(3);
|
||||
|
||||
public var ordinal:int;
|
||||
|
||||
public function BlendMode (ordinal:int) {
|
||||
this.ordinal = ordinal;
|
||||
public function BlendMode(ordinal : int) {
|
||||
this.ordinal = ordinal;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,314 +29,310 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
public class Bone implements Updatable {
|
||||
static public var yDown : Boolean;
|
||||
internal var _data : BoneData;
|
||||
internal var _skeleton : Skeleton;
|
||||
internal var _parent : Bone;
|
||||
internal var _children : Vector.<Bone> = new Vector.<Bone>();
|
||||
public var x : Number;
|
||||
public var y : Number;
|
||||
public var rotation : Number;
|
||||
public var scaleX : Number;
|
||||
public var scaleY : Number;
|
||||
public var shearX : Number;
|
||||
public var shearY : Number;
|
||||
public var ax : Number;
|
||||
public var ay : Number;
|
||||
public var arotation : Number;
|
||||
public var ascaleX : Number;
|
||||
public var ascaleY : Number;
|
||||
public var ashearX : Number;
|
||||
public var ashearY : Number;
|
||||
public var appliedValid : Boolean;
|
||||
public var a : Number;
|
||||
public var b : Number;
|
||||
public var c : Number;
|
||||
public var d : Number;
|
||||
public var worldX : Number;
|
||||
public var worldY : Number;
|
||||
internal var _sorted : Boolean;
|
||||
|
||||
public class Bone implements Updatable {
|
||||
static public var yDown:Boolean;
|
||||
/** @param parent May be null. */
|
||||
public function Bone(data : BoneData, skeleton : Skeleton, parent : Bone) {
|
||||
if (data == null) throw new ArgumentError("data cannot be null.");
|
||||
if (skeleton == null) throw new ArgumentError("skeleton cannot be null.");
|
||||
_data = data;
|
||||
_skeleton = skeleton;
|
||||
_parent = parent;
|
||||
setToSetupPose();
|
||||
}
|
||||
|
||||
internal var _data:BoneData;
|
||||
internal var _skeleton:Skeleton;
|
||||
internal var _parent:Bone;
|
||||
internal var _children:Vector.<Bone> = new Vector.<Bone>();
|
||||
public var x:Number;
|
||||
public var y:Number;
|
||||
public var rotation:Number;
|
||||
public var scaleX:Number;
|
||||
public var scaleY:Number;
|
||||
public var shearX:Number;
|
||||
public var shearY:Number;
|
||||
public var ax:Number;
|
||||
public var ay:Number;
|
||||
public var arotation:Number;
|
||||
public var ascaleX:Number;
|
||||
public var ascaleY:Number;
|
||||
public var ashearX:Number;
|
||||
public var ashearY:Number;
|
||||
public var appliedValid:Boolean;
|
||||
/** Same as updateWorldTransform(). This method exists for Bone to implement Updatable. */
|
||||
public function update() : void {
|
||||
updateWorldTransformWith(x, y, rotation, scaleX, scaleY, shearX, shearY);
|
||||
}
|
||||
|
||||
public var a:Number;
|
||||
public var b:Number;
|
||||
public var c:Number;
|
||||
public var d:Number;
|
||||
public var worldX:Number;
|
||||
public var worldY:Number;
|
||||
|
||||
internal var _sorted:Boolean;
|
||||
/** Computes the world SRT using the parent bone and this bone's local SRT. */
|
||||
public function updateWorldTransform() : void {
|
||||
updateWorldTransformWith(x, y, rotation, scaleX, scaleY, shearX, shearY);
|
||||
}
|
||||
|
||||
/** @param parent May be null. */
|
||||
public function Bone (data:BoneData, skeleton:Skeleton, parent:Bone) {
|
||||
if (data == null) throw new ArgumentError("data cannot be null.");
|
||||
if (skeleton == null) throw new ArgumentError("skeleton cannot be null.");
|
||||
_data = data;
|
||||
_skeleton = skeleton;
|
||||
_parent = parent;
|
||||
setToSetupPose();
|
||||
}
|
||||
|
||||
/** Same as updateWorldTransform(). This method exists for Bone to implement Updatable. */
|
||||
public function update () : void {
|
||||
updateWorldTransformWith(x, y, rotation, scaleX, scaleY, shearX, shearY);
|
||||
}
|
||||
/** Computes the world SRT using the parent bone and the specified local SRT. */
|
||||
public function updateWorldTransformWith(x : Number, y : Number, rotation : Number, scaleX : Number, scaleY : Number, shearX : Number, shearY : Number) : void {
|
||||
ax = x;
|
||||
ay = y;
|
||||
arotation = rotation;
|
||||
ascaleX = scaleX;
|
||||
ascaleY = scaleY;
|
||||
ashearX = shearX;
|
||||
ashearY = shearY;
|
||||
appliedValid = true;
|
||||
|
||||
/** Computes the world SRT using the parent bone and this bone's local SRT. */
|
||||
public function updateWorldTransform () : void {
|
||||
updateWorldTransformWith(x, y, rotation, scaleX, scaleY, shearX, shearY);
|
||||
}
|
||||
var rotationY : Number = 0, la : Number = 0, lb : Number = 0, lc : Number = 0, ld : Number = 0;
|
||||
var sin : Number = 0, cos : Number = 0;
|
||||
var s : Number = 0;
|
||||
|
||||
/** Computes the world SRT using the parent bone and the specified local SRT. */
|
||||
public function updateWorldTransformWith (x:Number, y:Number, rotation:Number, scaleX:Number, scaleY:Number, shearX:Number, shearY:Number) : void {
|
||||
ax = x;
|
||||
ay = y;
|
||||
arotation = rotation;
|
||||
ascaleX = scaleX;
|
||||
ascaleY = scaleY;
|
||||
ashearX = shearX;
|
||||
ashearY = shearY;
|
||||
appliedValid = true;
|
||||
|
||||
var rotationY:Number = 0, la:Number = 0, lb:Number = 0, lc:Number = 0, ld:Number = 0;
|
||||
var sin:Number = 0, cos:Number = 0;
|
||||
var s:Number = 0;
|
||||
|
||||
var parent:Bone = _parent;
|
||||
if (!parent) { // Root bone.
|
||||
rotationY = rotation + 90 + shearY;
|
||||
la = MathUtils.cosDeg(rotation + shearX) * scaleX;
|
||||
lb = MathUtils.cosDeg(rotationY) * scaleY;
|
||||
lc = MathUtils.sinDeg(rotation + shearX) * scaleX;
|
||||
ld = MathUtils.sinDeg(rotationY) * scaleY;
|
||||
var skeleton:Skeleton = _skeleton;
|
||||
if (skeleton.flipX) {
|
||||
x = -x;
|
||||
la = -la;
|
||||
lb = -lb;
|
||||
var parent : Bone = _parent;
|
||||
if (!parent) { // Root bone.
|
||||
rotationY = rotation + 90 + shearY;
|
||||
la = MathUtils.cosDeg(rotation + shearX) * scaleX;
|
||||
lb = MathUtils.cosDeg(rotationY) * scaleY;
|
||||
lc = MathUtils.sinDeg(rotation + shearX) * scaleX;
|
||||
ld = MathUtils.sinDeg(rotationY) * scaleY;
|
||||
var skeleton : Skeleton = _skeleton;
|
||||
if (skeleton.flipX) {
|
||||
x = -x;
|
||||
la = -la;
|
||||
lb = -lb;
|
||||
}
|
||||
if (skeleton.flipY != yDown) {
|
||||
y = -y;
|
||||
lc = -lc;
|
||||
ld = -ld;
|
||||
}
|
||||
this.a = la;
|
||||
this.b = lb;
|
||||
this.c = lc;
|
||||
this.d = ld;
|
||||
worldX = x + skeleton.x;
|
||||
worldY = y + skeleton.y;
|
||||
return;
|
||||
}
|
||||
if (skeleton.flipY != yDown) {
|
||||
y = -y;
|
||||
lc = -lc;
|
||||
ld = -ld;
|
||||
}
|
||||
this.a = la;
|
||||
this.b = lb;
|
||||
this.c = lc;
|
||||
this.d = ld;
|
||||
worldX = x + skeleton.x;
|
||||
worldY = y + skeleton.y;
|
||||
return;
|
||||
}
|
||||
|
||||
var pa:Number = parent.a, pb:Number = parent.b, pc:Number = parent.c, pd:Number = parent.d;
|
||||
worldX = pa * x + pb * y + parent.worldX;
|
||||
worldY = pc * x + pd * y + parent.worldY;
|
||||
var pa : Number = parent.a, pb : Number = parent.b, pc : Number = parent.c, pd : Number = parent.d;
|
||||
worldX = pa * x + pb * y + parent.worldX;
|
||||
worldY = pc * x + pd * y + parent.worldY;
|
||||
|
||||
switch (this.data.transformMode) {
|
||||
case TransformMode.normal: {
|
||||
rotationY = rotation + 90 + shearY;
|
||||
la = MathUtils.cosDeg(rotation + shearX) * scaleX;
|
||||
lb = MathUtils.cosDeg(rotationY) * scaleY;
|
||||
lc = MathUtils.sinDeg(rotation + shearX) * scaleX;
|
||||
ld = MathUtils.sinDeg(rotationY) * scaleY;
|
||||
this.a = pa * la + pb * lc;
|
||||
this.b = pa * lb + pb * ld;
|
||||
this.c = pc * la + pd * lc;
|
||||
this.d = pc * lb + pd * ld;
|
||||
return;
|
||||
}
|
||||
case TransformMode.onlyTranslation: {
|
||||
rotationY = rotation + 90 + shearY;
|
||||
this.a = MathUtils.cosDeg(rotation + shearX) * scaleX;
|
||||
this.b = MathUtils.cosDeg(rotationY) * scaleY;
|
||||
this.c = MathUtils.sinDeg(rotation + shearX) * scaleX;
|
||||
this.d = MathUtils.sinDeg(rotationY) * scaleY;
|
||||
break;
|
||||
}
|
||||
case TransformMode.noRotationOrReflection: {
|
||||
s = pa * pa + pc * pc;
|
||||
var prx:Number = 0;
|
||||
if (s > 0.0001) {
|
||||
s = Math.abs(pa * pd - pb * pc) / s;
|
||||
pb = pc * s;
|
||||
pd = pa * s;
|
||||
prx = Math.atan2(pc, pa) * MathUtils.radDeg;
|
||||
} else {
|
||||
pa = 0;
|
||||
pc = 0;
|
||||
prx = 90 - Math.atan2(pd, pb) * MathUtils.radDeg;
|
||||
switch (this.data.transformMode) {
|
||||
case TransformMode.normal: {
|
||||
rotationY = rotation + 90 + shearY;
|
||||
la = MathUtils.cosDeg(rotation + shearX) * scaleX;
|
||||
lb = MathUtils.cosDeg(rotationY) * scaleY;
|
||||
lc = MathUtils.sinDeg(rotation + shearX) * scaleX;
|
||||
ld = MathUtils.sinDeg(rotationY) * scaleY;
|
||||
this.a = pa * la + pb * lc;
|
||||
this.b = pa * lb + pb * ld;
|
||||
this.c = pc * la + pd * lc;
|
||||
this.d = pc * lb + pd * ld;
|
||||
return;
|
||||
}
|
||||
case TransformMode.onlyTranslation: {
|
||||
rotationY = rotation + 90 + shearY;
|
||||
this.a = MathUtils.cosDeg(rotation + shearX) * scaleX;
|
||||
this.b = MathUtils.cosDeg(rotationY) * scaleY;
|
||||
this.c = MathUtils.sinDeg(rotation + shearX) * scaleX;
|
||||
this.d = MathUtils.sinDeg(rotationY) * scaleY;
|
||||
break;
|
||||
}
|
||||
case TransformMode.noRotationOrReflection: {
|
||||
s = pa * pa + pc * pc;
|
||||
var prx : Number = 0;
|
||||
if (s > 0.0001) {
|
||||
s = Math.abs(pa * pd - pb * pc) / s;
|
||||
pb = pc * s;
|
||||
pd = pa * s;
|
||||
prx = Math.atan2(pc, pa) * MathUtils.radDeg;
|
||||
} else {
|
||||
pa = 0;
|
||||
pc = 0;
|
||||
prx = 90 - Math.atan2(pd, pb) * MathUtils.radDeg;
|
||||
}
|
||||
var rx : Number = rotation + shearX - prx;
|
||||
var ry : Number = rotation + shearY - prx + 90;
|
||||
la = MathUtils.cosDeg(rx) * scaleX;
|
||||
lb = MathUtils.cosDeg(ry) * scaleY;
|
||||
lc = MathUtils.sinDeg(rx) * scaleX;
|
||||
ld = MathUtils.sinDeg(ry) * scaleY;
|
||||
this.a = pa * la - pb * lc;
|
||||
this.b = pa * lb - pb * ld;
|
||||
this.c = pc * la + pd * lc;
|
||||
this.d = pc * lb + pd * ld;
|
||||
break;
|
||||
}
|
||||
case TransformMode.noScale:
|
||||
case TransformMode.noScaleOrReflection: {
|
||||
cos = MathUtils.cosDeg(rotation);
|
||||
sin = MathUtils.sinDeg(rotation);
|
||||
var za : Number = pa * cos + pb * sin;
|
||||
var zc : Number = pc * cos + pd * sin;
|
||||
s = Math.sqrt(za * za + zc * zc);
|
||||
if (s > 0.00001) s = 1 / s;
|
||||
za *= s;
|
||||
zc *= s;
|
||||
s = Math.sqrt(za * za + zc * zc);
|
||||
var r : Number = Math.PI / 2 + Math.atan2(zc, za);
|
||||
var zb : Number = Math.cos(r) * s;
|
||||
var zd : Number = Math.sin(r) * s;
|
||||
la = MathUtils.cosDeg(shearX) * scaleX;
|
||||
lb = MathUtils.cosDeg(90 + shearY) * scaleY;
|
||||
lc = MathUtils.sinDeg(shearX) * scaleX;
|
||||
ld = MathUtils.sinDeg(90 + shearY) * scaleY;
|
||||
this.a = za * la + zb * lc;
|
||||
this.b = za * lb + zb * ld;
|
||||
this.c = zc * la + zd * lc;
|
||||
this.d = zc * lb + zd * ld;
|
||||
if (this.data.transformMode != TransformMode.noScaleOrReflection ? pa * pd - pb * pc < 0 : skeleton.flipX != skeleton.flipY) {
|
||||
this.b = -this.b;
|
||||
this.d = -this.d;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
var rx:Number = rotation + shearX - prx;
|
||||
var ry:Number = rotation + shearY - prx + 90;
|
||||
la = MathUtils.cosDeg(rx) * scaleX;
|
||||
lb = MathUtils.cosDeg(ry) * scaleY;
|
||||
lc = MathUtils.sinDeg(rx) * scaleX;
|
||||
ld = MathUtils.sinDeg(ry) * scaleY;
|
||||
this.a = pa * la - pb * lc;
|
||||
this.b = pa * lb - pb * ld;
|
||||
this.c = pc * la + pd * lc;
|
||||
this.d = pc * lb + pd * ld;
|
||||
break;
|
||||
}
|
||||
case TransformMode.noScale:
|
||||
case TransformMode.noScaleOrReflection: {
|
||||
cos = MathUtils.cosDeg(rotation);
|
||||
sin = MathUtils.sinDeg(rotation);
|
||||
var za:Number = pa * cos + pb * sin;
|
||||
var zc:Number = pc * cos + pd * sin;
|
||||
s = Math.sqrt(za * za + zc * zc);
|
||||
if (s > 0.00001) s = 1 / s;
|
||||
za *= s;
|
||||
zc *= s;
|
||||
s = Math.sqrt(za * za + zc * zc);
|
||||
var r:Number = Math.PI / 2 + Math.atan2(zc, za);
|
||||
var zb:Number = Math.cos(r) * s;
|
||||
var zd:Number = Math.sin(r) * s;
|
||||
la = MathUtils.cosDeg(shearX) * scaleX;
|
||||
lb = MathUtils.cosDeg(90 + shearY) * scaleY;
|
||||
lc = MathUtils.sinDeg(shearX) * scaleX;
|
||||
ld = MathUtils.sinDeg(90 + shearY) * scaleY;
|
||||
this.a = za * la + zb * lc;
|
||||
this.b = za * lb + zb * ld;
|
||||
this.c = zc * la + zd * lc;
|
||||
this.d = zc * lb + zd * ld;
|
||||
if (this.data.transformMode != TransformMode.noScaleOrReflection ? pa * pd - pb * pc < 0 : skeleton.flipX != skeleton.flipY) {
|
||||
if (_skeleton.flipX) {
|
||||
this.a = -this.a;
|
||||
this.b = -this.b;
|
||||
}
|
||||
if (_skeleton.flipY != yDown) {
|
||||
this.c = -this.c;
|
||||
this.d = -this.d;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
public function setToSetupPose() : void {
|
||||
x = this.data.x;
|
||||
y = this.data.y;
|
||||
rotation = this.data.rotation;
|
||||
scaleX = this.data.scaleX;
|
||||
scaleY = this.data.scaleY;
|
||||
shearX = this.data.shearX;
|
||||
shearY = this.data.shearY;
|
||||
}
|
||||
if (_skeleton.flipX) {
|
||||
this.a = -this.a;
|
||||
this.b = -this.b;
|
||||
|
||||
public function get data() : BoneData {
|
||||
return _data;
|
||||
}
|
||||
if (_skeleton.flipY != yDown) {
|
||||
this.c = -this.c;
|
||||
this.d = -this.d;
|
||||
|
||||
public function get skeleton() : Skeleton {
|
||||
return _skeleton;
|
||||
}
|
||||
}
|
||||
|
||||
public function setToSetupPose () : void {
|
||||
x = this.data.x;
|
||||
y = this.data.y;
|
||||
rotation = this.data.rotation;
|
||||
scaleX = this.data.scaleX;
|
||||
scaleY = this.data.scaleY;
|
||||
shearX = this.data.shearX;
|
||||
shearY = this.data.shearY;
|
||||
}
|
||||
public function get parent() : Bone {
|
||||
return _parent;
|
||||
}
|
||||
|
||||
public function get data () : BoneData {
|
||||
return _data;
|
||||
}
|
||||
|
||||
public function get skeleton () : Skeleton {
|
||||
return _skeleton;
|
||||
}
|
||||
|
||||
public function get parent () : Bone {
|
||||
return _parent;
|
||||
}
|
||||
|
||||
public function get children () : Vector.<Bone> {;
|
||||
return _children;
|
||||
}
|
||||
public function get children() : Vector.<Bone> {
|
||||
;
|
||||
return _children;
|
||||
}
|
||||
|
||||
public function get worldRotationX () : Number {
|
||||
return Math.atan2(this.c, this.a) * MathUtils.radDeg;
|
||||
}
|
||||
public function get worldRotationX() : Number {
|
||||
return Math.atan2(this.c, this.a) * MathUtils.radDeg;
|
||||
}
|
||||
|
||||
public function get worldRotationY () : Number {
|
||||
return Math.atan2(this.d, this.b) * MathUtils.radDeg;
|
||||
}
|
||||
public function get worldRotationY() : Number {
|
||||
return Math.atan2(this.d, this.b) * MathUtils.radDeg;
|
||||
}
|
||||
|
||||
public function get worldScaleX () : Number {
|
||||
return Math.sqrt(this.a * this.a + this.c * this.c);
|
||||
}
|
||||
public function get worldScaleX() : Number {
|
||||
return Math.sqrt(this.a * this.a + this.c * this.c);
|
||||
}
|
||||
|
||||
public function get worldScaleY () : Number {
|
||||
return Math.sqrt(this.b * this.b + this.d * this.d);
|
||||
}
|
||||
public function get worldScaleY() : Number {
|
||||
return Math.sqrt(this.b * this.b + this.d * this.d);
|
||||
}
|
||||
|
||||
/** Computes the individual applied transform values from the world transform. This can be useful to perform processing using
|
||||
* the applied transform after the world transform has been modified directly (eg, by a constraint).
|
||||
* <p>
|
||||
* Some information is ambiguous in the world transform, such as -1,-1 scale versus 180 rotation. */
|
||||
internal function updateAppliedTransform () : void {
|
||||
appliedValid = true;
|
||||
var parent:Bone = this.parent;
|
||||
if (parent == null) {
|
||||
ax = worldX;
|
||||
ay = worldY;
|
||||
arotation = Math.atan2(c, a) * MathUtils.radDeg;
|
||||
ascaleX = Math.sqrt(a * a + c * c);
|
||||
ascaleY = Math.sqrt(b * b + d * d);
|
||||
/** Computes the individual applied transform values from the world transform. This can be useful to perform processing using
|
||||
* the applied transform after the world transform has been modified directly (eg, by a constraint).
|
||||
* <p>
|
||||
* Some information is ambiguous in the world transform, such as -1,-1 scale versus 180 rotation. */
|
||||
internal function updateAppliedTransform() : void {
|
||||
appliedValid = true;
|
||||
var parent : Bone = this.parent;
|
||||
if (parent == null) {
|
||||
ax = worldX;
|
||||
ay = worldY;
|
||||
arotation = Math.atan2(c, a) * MathUtils.radDeg;
|
||||
ascaleX = Math.sqrt(a * a + c * c);
|
||||
ascaleY = Math.sqrt(b * b + d * d);
|
||||
ashearX = 0;
|
||||
ashearY = Math.atan2(a * b + c * d, a * d - b * c) * MathUtils.radDeg;
|
||||
return;
|
||||
}
|
||||
var pa : Number = parent.a, pb : Number = parent.b, pc : Number = parent.c, pd : Number = parent.d;
|
||||
var pid : Number = 1 / (pa * pd - pb * pc);
|
||||
var dx : Number = worldX - parent.worldX, dy : Number = worldY - parent.worldY;
|
||||
ax = (dx * pd * pid - dy * pb * pid);
|
||||
ay = (dy * pa * pid - dx * pc * pid);
|
||||
var ia : Number = pid * pd;
|
||||
var id : Number = pid * pa;
|
||||
var ib : Number = pid * pb;
|
||||
var ic : Number = pid * pc;
|
||||
var ra : Number = ia * a - ib * c;
|
||||
var rb : Number = ia * b - ib * d;
|
||||
var rc : Number = id * c - ic * a;
|
||||
var rd : Number = id * d - ic * b;
|
||||
ashearX = 0;
|
||||
ashearY = Math.atan2(a * b + c * d, a * d - b * c) * MathUtils.radDeg;
|
||||
return;
|
||||
ascaleX = Math.sqrt(ra * ra + rc * rc);
|
||||
if (scaleX > 0.0001) {
|
||||
var det : Number = ra * rd - rb * rc;
|
||||
ascaleY = det / ascaleX;
|
||||
ashearY = Math.atan2(ra * rb + rc * rd, det) * MathUtils.radDeg;
|
||||
arotation = Math.atan2(rc, ra) * MathUtils.radDeg;
|
||||
} else {
|
||||
ascaleX = 0;
|
||||
ascaleY = Math.sqrt(rb * rb + rd * rd);
|
||||
ashearY = 0;
|
||||
arotation = 90 - Math.atan2(rd, rb) * MathUtils.radDeg;
|
||||
}
|
||||
}
|
||||
var pa:Number = parent.a, pb:Number = parent.b, pc:Number = parent.c, pd:Number = parent.d;
|
||||
var pid:Number = 1 / (pa * pd - pb * pc);
|
||||
var dx:Number = worldX - parent.worldX, dy:Number = worldY - parent.worldY;
|
||||
ax = (dx * pd * pid - dy * pb * pid);
|
||||
ay = (dy * pa * pid - dx * pc * pid);
|
||||
var ia:Number = pid * pd;
|
||||
var id:Number = pid * pa;
|
||||
var ib:Number = pid * pb;
|
||||
var ic:Number = pid * pc;
|
||||
var ra:Number = ia * a - ib * c;
|
||||
var rb:Number = ia * b - ib * d;
|
||||
var rc:Number = id * c - ic * a;
|
||||
var rd:Number = id * d - ic * b;
|
||||
ashearX = 0;
|
||||
ascaleX = Math.sqrt(ra * ra + rc * rc);
|
||||
if (scaleX > 0.0001) {
|
||||
var det:Number = ra * rd - rb * rc;
|
||||
ascaleY = det /ascaleX;
|
||||
ashearY = Math.atan2(ra * rb + rc * rd, det) * MathUtils.radDeg;
|
||||
arotation = Math.atan2(rc, ra) * MathUtils.radDeg;
|
||||
} else {
|
||||
ascaleX = 0;
|
||||
ascaleY = Math.sqrt(rb * rb + rd * rd);
|
||||
ashearY = 0;
|
||||
arotation = 90 - Math.atan2(rd, rb) * MathUtils.radDeg;
|
||||
}
|
||||
}
|
||||
|
||||
public function worldToLocal (world:Vector.<Number>) : void {
|
||||
var a:Number = this.a, b:Number = this.b, c:Number = this.c, d:Number = this.d;
|
||||
var invDet:Number = 1 / (a * d - b * c);
|
||||
var x:Number = world[0] - this.worldX, y:Number = world[1] - this.worldY;
|
||||
world[0] = (x * d * invDet - y * b * invDet);
|
||||
world[1] = (y * a * invDet - x * c * invDet);
|
||||
}
|
||||
public function worldToLocal(world : Vector.<Number>) : void {
|
||||
var a : Number = this.a, b : Number = this.b, c : Number = this.c, d : Number = this.d;
|
||||
var invDet : Number = 1 / (a * d - b * c);
|
||||
var x : Number = world[0] - this.worldX, y : Number = world[1] - this.worldY;
|
||||
world[0] = (x * d * invDet - y * b * invDet);
|
||||
world[1] = (y * a * invDet - x * c * invDet);
|
||||
}
|
||||
|
||||
public function localToWorld (local:Vector.<Number>) : void {
|
||||
var localX:Number = local[0], localY:Number = local[1];
|
||||
local[0] = localX * this.a + localY * this.b + this.worldX;
|
||||
local[1] = localX * this.c + localY * this.d + this.worldY;
|
||||
}
|
||||
|
||||
public function worldToLocalRotation (worldRotation:Number) : Number {
|
||||
var sin:Number = MathUtils.sinDeg(worldRotation), cos:Number = MathUtils.cosDeg(worldRotation);
|
||||
return Math.atan2(this.a * sin - this.c * cos, this.d * cos - this.b * sin) * MathUtils.radDeg;
|
||||
}
|
||||
public function localToWorld(local : Vector.<Number>) : void {
|
||||
var localX : Number = local[0], localY : Number = local[1];
|
||||
local[0] = localX * this.a + localY * this.b + this.worldX;
|
||||
local[1] = localX * this.c + localY * this.d + this.worldY;
|
||||
}
|
||||
|
||||
public function localToWorldRotation (localRotation:Number) : Number {
|
||||
var sin:Number = MathUtils.sinDeg(localRotation), cos:Number = MathUtils.cosDeg(localRotation);
|
||||
return Math.atan2(cos * this.c + sin * this.d, cos * this.a + sin * this.b) * MathUtils.radDeg;
|
||||
}
|
||||
public function worldToLocalRotation(worldRotation : Number) : Number {
|
||||
var sin : Number = MathUtils.sinDeg(worldRotation), cos : Number = MathUtils.cosDeg(worldRotation);
|
||||
return Math.atan2(this.a * sin - this.c * cos, this.d * cos - this.b * sin) * MathUtils.radDeg;
|
||||
}
|
||||
|
||||
public function rotateWorld (degrees:Number) : void {
|
||||
var a:Number = this.a, b:Number = this.b, c:Number = this.c, d:Number = this.d;
|
||||
var cos:Number = MathUtils.cosDeg(degrees), sin:Number = MathUtils.sinDeg(degrees);
|
||||
this.a = cos * a - sin * c;
|
||||
this.b = cos * b - sin * d;
|
||||
this.c = sin * a + cos * c;
|
||||
this.d = sin * b + cos * d;
|
||||
this.appliedValid = false;
|
||||
}
|
||||
public function localToWorldRotation(localRotation : Number) : Number {
|
||||
var sin : Number = MathUtils.sinDeg(localRotation), cos : Number = MathUtils.cosDeg(localRotation);
|
||||
return Math.atan2(cos * this.c + sin * this.d, cos * this.a + sin * this.b) * MathUtils.radDeg;
|
||||
}
|
||||
|
||||
public function toString () : String {
|
||||
return this.data._name;
|
||||
}
|
||||
}
|
||||
public function rotateWorld(degrees : Number) : void {
|
||||
var a : Number = this.a, b : Number = this.b, c : Number = this.c, d : Number = this.d;
|
||||
var cos : Number = MathUtils.cosDeg(degrees), sin : Number = MathUtils.sinDeg(degrees);
|
||||
this.a = cos * a - sin * c;
|
||||
this.b = cos * b - sin * d;
|
||||
this.c = sin * a + cos * c;
|
||||
this.d = sin * b + cos * d;
|
||||
this.appliedValid = false;
|
||||
}
|
||||
|
||||
}
|
||||
public function toString() : String {
|
||||
return this.data._name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -29,46 +29,44 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
public class BoneData {
|
||||
internal var _index : int;
|
||||
internal var _name : String;
|
||||
internal var _parent : BoneData;
|
||||
public var length : Number;
|
||||
public var x : Number;
|
||||
public var y : Number;
|
||||
public var rotation : Number;
|
||||
public var scaleX : Number = 1;
|
||||
public var scaleY : Number = 1;
|
||||
public var shearX : Number;
|
||||
public var shearY : Number;
|
||||
public var transformMode : TransformMode = TransformMode.normal;
|
||||
|
||||
public class BoneData {
|
||||
internal var _index:int;
|
||||
internal var _name:String;
|
||||
internal var _parent:BoneData;
|
||||
public var length:Number;
|
||||
public var x:Number;
|
||||
public var y:Number;
|
||||
public var rotation:Number;
|
||||
public var scaleX:Number = 1;
|
||||
public var scaleY:Number = 1;
|
||||
public var shearX:Number;
|
||||
public var shearY:Number;
|
||||
public var transformMode:TransformMode = TransformMode.normal;
|
||||
/** @param parent May be null. */
|
||||
public function BoneData(index : int, name : String, parent : BoneData) {
|
||||
if (index < 0) throw new ArgumentError("index must be >= 0");
|
||||
if (name == null) throw new ArgumentError("name cannot be null.");
|
||||
_index = index;
|
||||
_name = name;
|
||||
_parent = parent;
|
||||
}
|
||||
|
||||
/** @param parent May be null. */
|
||||
public function BoneData (index:int, name:String, parent:BoneData) {
|
||||
if (index < 0) throw new ArgumentError("index must be >= 0");
|
||||
if (name == null) throw new ArgumentError("name cannot be null.");
|
||||
_index = index;
|
||||
_name = name;
|
||||
_parent = parent;
|
||||
public function get index() : int {
|
||||
return _index;
|
||||
}
|
||||
|
||||
public function get name() : String {
|
||||
return _name;
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
public function get parent() : BoneData {
|
||||
return _parent;
|
||||
}
|
||||
|
||||
public function toString() : String {
|
||||
return _name;
|
||||
}
|
||||
}
|
||||
|
||||
public function get index () : int {
|
||||
return _index;
|
||||
}
|
||||
|
||||
public function get name () : String {
|
||||
return _name;
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
public function get parent () : BoneData {
|
||||
return _parent;
|
||||
}
|
||||
|
||||
public function toString () : String {
|
||||
return _name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -30,25 +30,24 @@
|
||||
|
||||
package spine {
|
||||
public class Color {
|
||||
public static var WHITE:Color = new Color(1, 1, 1, 1);
|
||||
public static var RED:Color = new Color(1, 0, 0, 1);
|
||||
public static var GREEN:Color = new Color(0, 1, 0, 1);
|
||||
public static var BLUE:Color = new Color(0, 0, 1, 1);
|
||||
public static var MAGENTA:Color = new Color(1, 0, 1, 1);
|
||||
public static var WHITE : Color = new Color(1, 1, 1, 1);
|
||||
public static var RED : Color = new Color(1, 0, 0, 1);
|
||||
public static var GREEN : Color = new Color(0, 1, 0, 1);
|
||||
public static var BLUE : Color = new Color(0, 0, 1, 1);
|
||||
public static var MAGENTA : Color = new Color(1, 0, 1, 1);
|
||||
public var r : Number = 0;
|
||||
public var g : Number = 0;
|
||||
public var b : Number = 0;
|
||||
public var a : Number = 0;
|
||||
|
||||
public var r:Number = 0;
|
||||
public var g:Number = 0;
|
||||
public var b:Number = 0;
|
||||
public var a:Number = 0;
|
||||
|
||||
public function Color (r:Number, g:Number, b:Number, a:Number = 0) {
|
||||
public function Color(r : Number, g : Number, b : Number, a : Number = 0) {
|
||||
this.r = r;
|
||||
this.g = g;
|
||||
this.b = b;
|
||||
this.a = a;
|
||||
}
|
||||
|
||||
public function setFrom (r:Number, g:Number, b:Number, a:Number): Color {
|
||||
public function setFrom(r : Number, g : Number, b : Number, a : Number) : Color {
|
||||
this.r = r;
|
||||
this.g = g;
|
||||
this.b = b;
|
||||
@ -57,7 +56,7 @@ package spine {
|
||||
return this;
|
||||
}
|
||||
|
||||
public function setFromColor (c:Color): Color{
|
||||
public function setFromColor(c : Color) : Color {
|
||||
this.r = c.r;
|
||||
this.g = c.g;
|
||||
this.b = c.b;
|
||||
@ -65,7 +64,7 @@ package spine {
|
||||
return this;
|
||||
}
|
||||
|
||||
public function setFromString (hex:String): Color {
|
||||
public function setFromString(hex : String) : Color {
|
||||
hex = hex.charAt(0) == '#' ? hex.substr(1) : hex;
|
||||
this.r = parseInt(hex.substr(0, 2), 16) / 255.0;
|
||||
this.g = parseInt(hex.substr(2, 2), 16) / 255.0;
|
||||
@ -74,7 +73,7 @@ package spine {
|
||||
return this;
|
||||
}
|
||||
|
||||
public function add (r:Number, g:Number, b:Number, a:Number): Color {
|
||||
public function add(r : Number, g : Number, b : Number, a : Number) : Color {
|
||||
this.r += r;
|
||||
this.g += g;
|
||||
this.b += b;
|
||||
@ -83,7 +82,7 @@ package spine {
|
||||
return this;
|
||||
}
|
||||
|
||||
public function clamp (): Color {
|
||||
public function clamp() : Color {
|
||||
if (this.r < 0) this.r = 0;
|
||||
else if (this.r > 1) this.r = 1;
|
||||
|
||||
|
||||
@ -29,9 +29,7 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
|
||||
public interface Constraint extends Updatable {
|
||||
function getOrder () : Number;
|
||||
}
|
||||
|
||||
}
|
||||
public interface Constraint extends Updatable {
|
||||
function getOrder() : Number;
|
||||
}
|
||||
}
|
||||
@ -29,27 +29,25 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
public class Event {
|
||||
internal var _data : EventData;
|
||||
public var time : Number;
|
||||
public var intValue : int;
|
||||
public var floatValue : Number;
|
||||
public var stringValue : String;
|
||||
|
||||
public class Event {
|
||||
internal var _data:EventData;
|
||||
public var time:Number;
|
||||
public var intValue:int;
|
||||
public var floatValue:Number;
|
||||
public var stringValue:String;
|
||||
public function Event(time : Number, data : EventData) {
|
||||
if (data == null) throw new ArgumentError("data cannot be null.");
|
||||
this.time = time;
|
||||
_data = data;
|
||||
}
|
||||
|
||||
public function Event (time:Number, data:EventData) {
|
||||
if (data == null) throw new ArgumentError("data cannot be null.");
|
||||
this.time = time;
|
||||
_data = data;
|
||||
public function get data() : EventData {
|
||||
return _data;
|
||||
}
|
||||
|
||||
public function toString() : String {
|
||||
return _data._name;
|
||||
}
|
||||
}
|
||||
|
||||
public function get data () : EventData {
|
||||
return _data;
|
||||
}
|
||||
|
||||
public function toString () : String {
|
||||
return _data._name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,25 +29,24 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
public class EventData {
|
||||
internal var _name : String;
|
||||
public var intValue : int;
|
||||
;
|
||||
public var floatValue : Number;
|
||||
public var stringValue : String;
|
||||
|
||||
public class EventData {
|
||||
internal var _name:String;
|
||||
public var intValue:int;;
|
||||
public var floatValue:Number;
|
||||
public var stringValue:String;
|
||||
|
||||
public function EventData (name:String) {
|
||||
if (name == null) throw new ArgumentError("name cannot be null.");
|
||||
_name = name;
|
||||
public function EventData(name : String) {
|
||||
if (name == null) throw new ArgumentError("name cannot be null.");
|
||||
_name = name;
|
||||
}
|
||||
|
||||
public function get name() : String {
|
||||
return _name;
|
||||
}
|
||||
|
||||
public function toString() : String {
|
||||
return _name;
|
||||
}
|
||||
}
|
||||
|
||||
public function get name () : String {
|
||||
return _name;
|
||||
}
|
||||
|
||||
public function toString () : String {
|
||||
return _name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,207 +29,204 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
public class IkConstraint implements Constraint {
|
||||
internal var _data : IkConstraintData;
|
||||
public var bones : Vector.<Bone>;
|
||||
public var target : Bone;
|
||||
public var mix : Number;
|
||||
public var bendDirection : int;
|
||||
|
||||
public class IkConstraint implements Constraint {
|
||||
internal var _data:IkConstraintData;
|
||||
public var bones:Vector.<Bone>;
|
||||
public var target:Bone;
|
||||
public var mix:Number;
|
||||
public var bendDirection:int;
|
||||
public function IkConstraint(data : IkConstraintData, skeleton : Skeleton) {
|
||||
if (data == null) throw new ArgumentError("data cannot be null.");
|
||||
if (skeleton == null) throw new ArgumentError("skeleton cannot be null.");
|
||||
_data = data;
|
||||
mix = data.mix;
|
||||
bendDirection = data.bendDirection;
|
||||
|
||||
public function IkConstraint (data:IkConstraintData, skeleton:Skeleton) {
|
||||
if (data == null) throw new ArgumentError("data cannot be null.");
|
||||
if (skeleton == null) throw new ArgumentError("skeleton cannot be null.");
|
||||
_data = data;
|
||||
mix = data.mix;
|
||||
bendDirection = data.bendDirection;
|
||||
|
||||
bones = new Vector.<Bone>();
|
||||
for each (var boneData:BoneData in data.bones)
|
||||
bones[bones.length] = skeleton.findBone(boneData.name);
|
||||
target = skeleton.findBone(data.target._name);
|
||||
}
|
||||
|
||||
public function apply () : void {
|
||||
update();
|
||||
}
|
||||
|
||||
public function update () : void {
|
||||
switch (bones.length) {
|
||||
case 1:
|
||||
apply1(bones[0], target.worldX, target.worldY, mix);
|
||||
break;
|
||||
case 2:
|
||||
apply2(bones[0], bones[1], target.worldX, target.worldY, bendDirection, mix);
|
||||
break;
|
||||
bones = new Vector.<Bone>();
|
||||
for each (var boneData : BoneData in data.bones)
|
||||
bones[bones.length] = skeleton.findBone(boneData.name);
|
||||
target = skeleton.findBone(data.target._name);
|
||||
}
|
||||
}
|
||||
|
||||
public function getOrder() : Number {
|
||||
return _data.order;
|
||||
}
|
||||
|
||||
public function get data () : IkConstraintData {
|
||||
return _data;
|
||||
}
|
||||
public function apply() : void {
|
||||
update();
|
||||
}
|
||||
|
||||
public function toString () : String {
|
||||
return _data._name;
|
||||
}
|
||||
|
||||
/** Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified in the world
|
||||
* coordinate system. */
|
||||
static public function apply1 (bone:Bone, targetX:Number, targetY:Number, alpha:Number) : void {
|
||||
if (!bone.appliedValid) bone.updateAppliedTransform();
|
||||
var p:Bone = bone.parent;
|
||||
var id:Number = 1 / (p.a * p.d - p.b * p.c);
|
||||
var x:Number = targetX - p.worldX, y:Number = targetY - p.worldY;
|
||||
var tx:Number = (x * p.d - y * p.b) * id - bone.ax, ty:Number = (y * p.a - x * p.c) * id - bone.ay;
|
||||
var rotationIK:Number = Math.atan2(ty, tx) * MathUtils.radDeg - bone.ashearX - bone.arotation;
|
||||
if (bone.ascaleX < 0) rotationIK += 180;
|
||||
if (rotationIK > 180)
|
||||
rotationIK -= 360;
|
||||
else if (rotationIK < -180) rotationIK += 360;
|
||||
bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, bone.ascaleX, bone.ascaleY, bone.ashearX,
|
||||
bone.ashearY);
|
||||
}
|
||||
public function update() : void {
|
||||
switch (bones.length) {
|
||||
case 1:
|
||||
apply1(bones[0], target.worldX, target.worldY, mix);
|
||||
break;
|
||||
case 2:
|
||||
apply2(bones[0], bones[1], target.worldX, target.worldY, bendDirection, mix);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/** Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as possible. The
|
||||
* target is specified in the world coordinate system.
|
||||
* @param child Any descendant bone of the parent. */
|
||||
static public function apply2 (parent:Bone, child:Bone, targetX:Number, targetY:Number, bendDir:int, alpha:Number) : void {
|
||||
if (alpha == 0) {
|
||||
child.updateWorldTransform();
|
||||
return;
|
||||
public function getOrder() : Number {
|
||||
return _data.order;
|
||||
}
|
||||
if (!parent.appliedValid) parent.updateAppliedTransform();
|
||||
if (!child.appliedValid) child.updateAppliedTransform();
|
||||
var px:Number = parent.ax, py:Number = parent.ay, psx:Number = parent.ascaleX, psy:Number = parent.ascaleY, csx:Number = child.ascaleX;
|
||||
var os1:int, os2:int, s2:int;
|
||||
if (psx < 0) {
|
||||
psx = -psx;
|
||||
os1 = 180;
|
||||
s2 = -1;
|
||||
} else {
|
||||
os1 = 0;
|
||||
s2 = 1;
|
||||
|
||||
public function get data() : IkConstraintData {
|
||||
return _data;
|
||||
}
|
||||
if (psy < 0) {
|
||||
psy = -psy;
|
||||
s2 = -s2;
|
||||
|
||||
public function toString() : String {
|
||||
return _data._name;
|
||||
}
|
||||
if (csx < 0) {
|
||||
csx = -csx;
|
||||
os2 = 180;
|
||||
} else
|
||||
os2 = 0;
|
||||
var cx:Number = child.ax, cy:Number, cwx:Number, cwy:Number, a:Number = parent.a, b:Number = parent.b, c:Number = parent.c, d:Number = parent.d;
|
||||
var u:Boolean = Math.abs(psx - psy) <= 0.0001;
|
||||
if (!u) {
|
||||
cy = 0;
|
||||
cwx = a * cx + parent.worldX;
|
||||
cwy = c * cx + parent.worldY;
|
||||
} else {
|
||||
cy = child.ay;
|
||||
cwx = a * cx + b * cy + parent.worldX;
|
||||
cwy = c * cx + d * cy + parent.worldY;
|
||||
|
||||
/** Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified in the world
|
||||
* coordinate system. */
|
||||
static public function apply1(bone : Bone, targetX : Number, targetY : Number, alpha : Number) : void {
|
||||
if (!bone.appliedValid) bone.updateAppliedTransform();
|
||||
var p : Bone = bone.parent;
|
||||
var id : Number = 1 / (p.a * p.d - p.b * p.c);
|
||||
var x : Number = targetX - p.worldX, y : Number = targetY - p.worldY;
|
||||
var tx : Number = (x * p.d - y * p.b) * id - bone.ax, ty : Number = (y * p.a - x * p.c) * id - bone.ay;
|
||||
var rotationIK : Number = Math.atan2(ty, tx) * MathUtils.radDeg - bone.ashearX - bone.arotation;
|
||||
if (bone.ascaleX < 0) rotationIK += 180;
|
||||
if (rotationIK > 180)
|
||||
rotationIK -= 360;
|
||||
else if (rotationIK < -180) rotationIK += 360;
|
||||
bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, bone.ascaleX, bone.ascaleY, bone.ashearX, bone.ashearY);
|
||||
}
|
||||
var pp:Bone = parent.parent;
|
||||
a = pp.a;
|
||||
b = pp.b;
|
||||
c = pp.c;
|
||||
d = pp.d;
|
||||
var id:Number = 1 / (a * d - b * c), x:Number = targetX - pp.worldX, y:Number = targetY - pp.worldY;
|
||||
var tx:Number = (x * d - y * b) * id - px, ty:Number = (y * a - x * c) * id - py;
|
||||
x = cwx - pp.worldX;
|
||||
y = cwy - pp.worldY;
|
||||
var dx:Number = (x * d - y * b) * id - px, dy:Number = (y * a - x * c) * id - py;
|
||||
var l1:Number = Math.sqrt(dx * dx + dy * dy), l2:Number = child.data.length * csx, a1:Number, a2:Number;
|
||||
outer:
|
||||
if (u) {
|
||||
l2 *= psx;
|
||||
var cos:Number = (tx * tx + ty * ty - l1 * l1 - l2 * l2) / (2 * l1 * l2);
|
||||
if (cos < -1)
|
||||
cos = -1;
|
||||
else if (cos > 1) cos = 1;
|
||||
a2 = Math.acos(cos) * bendDir;
|
||||
a = l1 + l2 * cos;
|
||||
b = l2 * Math.sin(a2);
|
||||
a1 = Math.atan2(ty * a - tx * b, tx * a + ty * b);
|
||||
} else {
|
||||
a = psx * l2;
|
||||
b = psy * l2;
|
||||
var aa:Number = a * a, bb:Number = b * b, dd:Number = tx * tx + ty * ty, ta:Number = Math.atan2(ty, tx);
|
||||
c = bb * l1 * l1 + aa * dd - aa * bb;
|
||||
var c1:Number = -2 * bb * l1, c2:Number = bb - aa;
|
||||
d = c1 * c1 - 4 * c2 * c;
|
||||
if (d >= 0) {
|
||||
var q:Number = Math.sqrt(d);
|
||||
if (c1 < 0) q = -q;
|
||||
q = -(c1 + q) / 2;
|
||||
var r0:Number = q / c2, r1:Number = c / q;
|
||||
var r:Number = Math.abs(r0) < Math.abs(r1) ? r0 : r1;
|
||||
if (r * r <= dd) {
|
||||
y = Math.sqrt(dd - r * r) * bendDir;
|
||||
a1 = ta - Math.atan2(y, r);
|
||||
a2 = Math.atan2(y / psy, (r - l1) / psx);
|
||||
break outer;
|
||||
|
||||
/** Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as possible. The
|
||||
* target is specified in the world coordinate system.
|
||||
* @param child Any descendant bone of the parent. */
|
||||
static public function apply2(parent : Bone, child : Bone, targetX : Number, targetY : Number, bendDir : int, alpha : Number) : void {
|
||||
if (alpha == 0) {
|
||||
child.updateWorldTransform();
|
||||
return;
|
||||
}
|
||||
if (!parent.appliedValid) parent.updateAppliedTransform();
|
||||
if (!child.appliedValid) child.updateAppliedTransform();
|
||||
var px : Number = parent.ax, py : Number = parent.ay, psx : Number = parent.ascaleX, psy : Number = parent.ascaleY, csx : Number = child.ascaleX;
|
||||
var os1 : int, os2 : int, s2 : int;
|
||||
if (psx < 0) {
|
||||
psx = -psx;
|
||||
os1 = 180;
|
||||
s2 = -1;
|
||||
} else {
|
||||
os1 = 0;
|
||||
s2 = 1;
|
||||
}
|
||||
if (psy < 0) {
|
||||
psy = -psy;
|
||||
s2 = -s2;
|
||||
}
|
||||
if (csx < 0) {
|
||||
csx = -csx;
|
||||
os2 = 180;
|
||||
} else
|
||||
os2 = 0;
|
||||
var cx : Number = child.ax, cy : Number, cwx : Number, cwy : Number, a : Number = parent.a, b : Number = parent.b, c : Number = parent.c, d : Number = parent.d;
|
||||
var u : Boolean = Math.abs(psx - psy) <= 0.0001;
|
||||
if (!u) {
|
||||
cy = 0;
|
||||
cwx = a * cx + parent.worldX;
|
||||
cwy = c * cx + parent.worldY;
|
||||
} else {
|
||||
cy = child.ay;
|
||||
cwx = a * cx + b * cy + parent.worldX;
|
||||
cwy = c * cx + d * cy + parent.worldY;
|
||||
}
|
||||
var pp : Bone = parent.parent;
|
||||
a = pp.a;
|
||||
b = pp.b;
|
||||
c = pp.c;
|
||||
d = pp.d;
|
||||
var id : Number = 1 / (a * d - b * c), x : Number = targetX - pp.worldX, y : Number = targetY - pp.worldY;
|
||||
var tx : Number = (x * d - y * b) * id - px, ty : Number = (y * a - x * c) * id - py;
|
||||
x = cwx - pp.worldX;
|
||||
y = cwy - pp.worldY;
|
||||
var dx : Number = (x * d - y * b) * id - px, dy : Number = (y * a - x * c) * id - py;
|
||||
var l1 : Number = Math.sqrt(dx * dx + dy * dy), l2 : Number = child.data.length * csx, a1 : Number, a2 : Number;
|
||||
outer:
|
||||
if (u) {
|
||||
l2 *= psx;
|
||||
var cos : Number = (tx * tx + ty * ty - l1 * l1 - l2 * l2) / (2 * l1 * l2);
|
||||
if (cos < -1)
|
||||
cos = -1;
|
||||
else if (cos > 1) cos = 1;
|
||||
a2 = Math.acos(cos) * bendDir;
|
||||
a = l1 + l2 * cos;
|
||||
b = l2 * Math.sin(a2);
|
||||
a1 = Math.atan2(ty * a - tx * b, tx * a + ty * b);
|
||||
} else {
|
||||
a = psx * l2;
|
||||
b = psy * l2;
|
||||
var aa : Number = a * a, bb : Number = b * b, dd : Number = tx * tx + ty * ty, ta : Number = Math.atan2(ty, tx);
|
||||
c = bb * l1 * l1 + aa * dd - aa * bb;
|
||||
var c1 : Number = -2 * bb * l1, c2 : Number = bb - aa;
|
||||
d = c1 * c1 - 4 * c2 * c;
|
||||
if (d >= 0) {
|
||||
var q : Number = Math.sqrt(d);
|
||||
if (c1 < 0) q = -q;
|
||||
q = -(c1 + q) / 2;
|
||||
var r0 : Number = q / c2, r1 : Number = c / q;
|
||||
var r : Number = Math.abs(r0) < Math.abs(r1) ? r0 : r1;
|
||||
if (r * r <= dd) {
|
||||
y = Math.sqrt(dd - r * r) * bendDir;
|
||||
a1 = ta - Math.atan2(y, r);
|
||||
a2 = Math.atan2(y / psy, (r - l1) / psx);
|
||||
break outer;
|
||||
}
|
||||
}
|
||||
var minAngle : Number = 0, minDist : Number = Number.MAX_VALUE, minX : Number = 0, minY : Number = 0;
|
||||
var maxAngle : Number = 0, maxDist : Number = 0, maxX : Number = 0, maxY : Number = 0;
|
||||
x = l1 + a;
|
||||
d = x * x;
|
||||
if (d > maxDist) {
|
||||
maxAngle = 0;
|
||||
maxDist = d;
|
||||
maxX = x;
|
||||
}
|
||||
x = l1 - a;
|
||||
d = x * x;
|
||||
if (d < minDist) {
|
||||
minAngle = Math.PI;
|
||||
minDist = d;
|
||||
minX = x;
|
||||
}
|
||||
var angle : Number = Math.acos(-a * l1 / (aa - bb));
|
||||
x = a * Math.cos(angle) + l1;
|
||||
y = b * Math.sin(angle);
|
||||
d = x * x + y * y;
|
||||
if (d < minDist) {
|
||||
minAngle = angle;
|
||||
minDist = d;
|
||||
minX = x;
|
||||
minY = y;
|
||||
}
|
||||
if (d > maxDist) {
|
||||
maxAngle = angle;
|
||||
maxDist = d;
|
||||
maxX = x;
|
||||
maxY = y;
|
||||
}
|
||||
if (dd <= (minDist + maxDist) / 2) {
|
||||
a1 = ta - Math.atan2(minY * bendDir, minX);
|
||||
a2 = minAngle * bendDir;
|
||||
} else {
|
||||
a1 = ta - Math.atan2(maxY * bendDir, maxX);
|
||||
a2 = maxAngle * bendDir;
|
||||
}
|
||||
}
|
||||
var minAngle:Number = 0, minDist:Number = Number.MAX_VALUE, minX:Number = 0, minY:Number = 0;
|
||||
var maxAngle:Number = 0, maxDist:Number = 0, maxX:Number = 0, maxY:Number = 0;
|
||||
x = l1 + a;
|
||||
d = x * x;
|
||||
if (d > maxDist) {
|
||||
maxAngle = 0;
|
||||
maxDist = d;
|
||||
maxX = x;
|
||||
}
|
||||
x = l1 - a;
|
||||
d = x * x;
|
||||
if (d < minDist) {
|
||||
minAngle = Math.PI;
|
||||
minDist = d;
|
||||
minX = x;
|
||||
}
|
||||
var angle:Number = Math.acos(-a * l1 / (aa - bb));
|
||||
x = a * Math.cos(angle) + l1;
|
||||
y = b * Math.sin(angle);
|
||||
d = x * x + y * y;
|
||||
if (d < minDist) {
|
||||
minAngle = angle;
|
||||
minDist = d;
|
||||
minX = x;
|
||||
minY = y;
|
||||
}
|
||||
if (d > maxDist) {
|
||||
maxAngle = angle;
|
||||
maxDist = d;
|
||||
maxX = x;
|
||||
maxY = y;
|
||||
}
|
||||
if (dd <= (minDist + maxDist) / 2) {
|
||||
a1 = ta - Math.atan2(minY * bendDir, minX);
|
||||
a2 = minAngle * bendDir;
|
||||
} else {
|
||||
a1 = ta - Math.atan2(maxY * bendDir, maxX);
|
||||
a2 = maxAngle * bendDir;
|
||||
}
|
||||
var os : Number = Math.atan2(cy, cx) * s2;
|
||||
var rotation : Number = parent.arotation;
|
||||
a1 = (a1 - os) * MathUtils.radDeg + os1 - rotation;
|
||||
if (a1 > 180)
|
||||
a1 -= 360;
|
||||
else if (a1 < -180) a1 += 360;
|
||||
parent.updateWorldTransformWith(px, py, rotation + a1 * alpha, parent.ascaleX, parent.ascaleY, 0, 0);
|
||||
rotation = child.arotation;
|
||||
a2 = ((a2 + os) * MathUtils.radDeg - child.ashearX) * s2 + os2 - rotation;
|
||||
if (a2 > 180)
|
||||
a2 -= 360;
|
||||
else if (a2 < -180) a2 += 360;
|
||||
child.updateWorldTransformWith(cx, cy, rotation + a2 * alpha, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY);
|
||||
}
|
||||
var os:Number = Math.atan2(cy, cx) * s2;
|
||||
var rotation:Number = parent.arotation;
|
||||
a1 = (a1 - os) * MathUtils.radDeg + os1 - rotation;
|
||||
if (a1 > 180)
|
||||
a1 -= 360;
|
||||
else if (a1 < -180) a1 += 360;
|
||||
parent.updateWorldTransformWith(px, py, rotation + a1 * alpha, parent.ascaleX, parent.ascaleY, 0, 0);
|
||||
rotation = child.arotation;
|
||||
a2 = ((a2 + os) * MathUtils.radDeg - child.ashearX) * s2 + os2 - rotation;
|
||||
if (a2 > 180)
|
||||
a2 -= 360;
|
||||
else if (a2 < -180) a2 += 360;
|
||||
child.updateWorldTransformWith(cx, cy, rotation + a2 * alpha, child.ascaleX, child.ascaleY, child.ashearX, child.ashearY);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,27 +29,25 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
public class IkConstraintData {
|
||||
internal var _name : String;
|
||||
public var order : Number;
|
||||
public var bones : Vector.<BoneData> = new Vector.<BoneData>();
|
||||
public var target : BoneData;
|
||||
public var bendDirection : int = 1;
|
||||
public var mix : Number = 1;
|
||||
|
||||
public class IkConstraintData {
|
||||
internal var _name:String;
|
||||
public var order:Number;
|
||||
public var bones:Vector.<BoneData> = new Vector.<BoneData>();
|
||||
public var target:BoneData;
|
||||
public var bendDirection:int = 1;
|
||||
public var mix:Number = 1;
|
||||
public function IkConstraintData(name : String) {
|
||||
if (name == null) throw new ArgumentError("name cannot be null.");
|
||||
_name = name;
|
||||
}
|
||||
|
||||
public function IkConstraintData (name:String) {
|
||||
if (name == null) throw new ArgumentError("name cannot be null.");
|
||||
_name = name;
|
||||
public function get name() : String {
|
||||
return _name;
|
||||
}
|
||||
|
||||
public function toString() : String {
|
||||
return _name;
|
||||
}
|
||||
}
|
||||
|
||||
public function get name () : String {
|
||||
return _name;
|
||||
}
|
||||
|
||||
public function toString () : String {
|
||||
return _name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,30 +29,28 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
public class MathUtils {
|
||||
static public var PI : Number = Math.PI;
|
||||
static public var PI2 : Number = Math.PI * 2;
|
||||
static public var radDeg : Number = 180 / Math.PI;
|
||||
static public var degRad : Number = Math.PI / 180;
|
||||
|
||||
public class MathUtils {
|
||||
static public var PI:Number = Math.PI;
|
||||
static public var PI2:Number = Math.PI * 2;
|
||||
static public var radDeg:Number = 180 / Math.PI;
|
||||
static public var degRad:Number = Math.PI / 180;
|
||||
|
||||
static public function cosDeg(degrees:Number): Number {
|
||||
return Math.cos(degrees * degRad);
|
||||
}
|
||||
|
||||
static public function sinDeg(degrees:Number): Number {
|
||||
return Math.sin(degrees * degRad);
|
||||
}
|
||||
|
||||
static public function clamp (value:Number, min:Number, max:Number) : Number {
|
||||
if (value < min) return min;
|
||||
if (value > max) return max;
|
||||
return value;
|
||||
}
|
||||
|
||||
static public function signum (value: Number):Number {
|
||||
return value > 0 ? 1 : value < 0 ? -1 : 0;
|
||||
}
|
||||
}
|
||||
static public function cosDeg(degrees : Number) : Number {
|
||||
return Math.cos(degrees * degRad);
|
||||
}
|
||||
|
||||
}
|
||||
static public function sinDeg(degrees : Number) : Number {
|
||||
return Math.sin(degrees * degRad);
|
||||
}
|
||||
|
||||
static public function clamp(value : Number, min : Number, max : Number) : Number {
|
||||
if (value < min) return min;
|
||||
if (value > max) return max;
|
||||
return value;
|
||||
}
|
||||
|
||||
static public function signum(value : Number) : Number {
|
||||
return value > 0 ? 1 : value < 0 ? -1 : 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -29,403 +29,398 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
import spine.attachments.PathAttachment;
|
||||
import spine.attachments.PathAttachment;
|
||||
|
||||
public class PathConstraint implements Constraint {
|
||||
private static const NONE:int = -1, BEFORE:int = -2, AFTER:int = -3;
|
||||
public class PathConstraint implements Constraint {
|
||||
private static const NONE : int = -1, BEFORE : int = -2, AFTER : int = -3;
|
||||
internal var _data : PathConstraintData;
|
||||
internal var _bones : Vector.<Bone>;
|
||||
public var target : Slot;
|
||||
public var position : Number, spacing : Number, rotateMix : Number, translateMix : Number;
|
||||
internal const _spaces : Vector.<Number> = new Vector.<Number>();
|
||||
internal const _positions : Vector.<Number> = new Vector.<Number>();
|
||||
internal const _world : Vector.<Number> = new Vector.<Number>();
|
||||
internal const _curves : Vector.<Number> = new Vector.<Number>();
|
||||
internal const _lengths : Vector.<Number> = new Vector.<Number>();
|
||||
internal const _segments : Vector.<Number> = new Vector.<Number>(10);
|
||||
|
||||
internal var _data:PathConstraintData;
|
||||
internal var _bones:Vector.<Bone>;
|
||||
public var target:Slot;
|
||||
public var position:Number, spacing:Number, rotateMix:Number, translateMix:Number;
|
||||
|
||||
internal const _spaces:Vector.<Number> = new Vector.<Number>();
|
||||
internal const _positions:Vector.<Number> = new Vector.<Number>();
|
||||
internal const _world:Vector.<Number> = new Vector.<Number>();
|
||||
internal const _curves:Vector.<Number> = new Vector.<Number>();
|
||||
internal const _lengths:Vector.<Number> = new Vector.<Number>();
|
||||
internal const _segments:Vector.<Number> = new Vector.<Number>(10);
|
||||
|
||||
public function PathConstraint (data:PathConstraintData, skeleton:Skeleton) {
|
||||
if (data == null) throw new ArgumentError("data cannot be null.");
|
||||
if (skeleton == null) throw new ArgumentError("skeleton cannot be null.");
|
||||
_data = data;
|
||||
_bones = new Vector.<Bone>();
|
||||
for each (var boneData:BoneData in data.bones)
|
||||
_bones.push(skeleton.findBone(boneData.name));
|
||||
target = skeleton.findSlot(data.target.name);
|
||||
position = data.position;
|
||||
spacing = data.spacing;
|
||||
rotateMix = data.rotateMix;
|
||||
translateMix = data.translateMix;
|
||||
}
|
||||
|
||||
public function apply () : void {
|
||||
update();
|
||||
}
|
||||
|
||||
public function update () : void {
|
||||
var attachment:PathAttachment = target.attachment as PathAttachment;
|
||||
if (attachment == null) return;
|
||||
|
||||
var rotateMix:Number = this.rotateMix, translateMix:Number = this.translateMix;
|
||||
var translate:Boolean = translateMix > 0, rotate:Boolean = rotateMix > 0;
|
||||
if (!translate && !rotate) return;
|
||||
|
||||
var data:PathConstraintData = this._data;
|
||||
var spacingMode:SpacingMode = data.spacingMode;
|
||||
var lengthSpacing:Boolean = spacingMode == SpacingMode.length;
|
||||
var rotateMode:RotateMode = data.rotateMode;
|
||||
var tangents:Boolean = rotateMode == RotateMode.tangent, scale:Boolean = rotateMode == RotateMode.chainScale;
|
||||
var boneCount:int = this._bones.length, spacesCount:int = tangents ? boneCount : boneCount + 1;
|
||||
var bones:Vector.<Bone> = this._bones;
|
||||
this._spaces.length = spacesCount;
|
||||
var spaces:Vector.<Number> = this._spaces, lengths:Vector.<Number> = null;
|
||||
var spacing:Number = this.spacing;
|
||||
if (scale || lengthSpacing) {
|
||||
if (scale) {
|
||||
this._lengths.length = boneCount;
|
||||
lengths = this._lengths;
|
||||
}
|
||||
for (var i:int = 0, n:int = spacesCount - 1; i < n;) {
|
||||
var bone:Bone = bones[i];
|
||||
var setupLength:Number = bone.data.length, x:Number = setupLength * bone.a, y:Number = setupLength * bone.c;
|
||||
var length:Number = Math.sqrt(x * x + y * y);
|
||||
if (scale) lengths[i] = length;
|
||||
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength;
|
||||
}
|
||||
} else {
|
||||
for (i = 1; i < spacesCount; i++)
|
||||
spaces[i] = spacing;
|
||||
public function PathConstraint(data : PathConstraintData, skeleton : Skeleton) {
|
||||
if (data == null) throw new ArgumentError("data cannot be null.");
|
||||
if (skeleton == null) throw new ArgumentError("skeleton cannot be null.");
|
||||
_data = data;
|
||||
_bones = new Vector.<Bone>();
|
||||
for each (var boneData : BoneData in data.bones)
|
||||
_bones.push(skeleton.findBone(boneData.name));
|
||||
target = skeleton.findSlot(data.target.name);
|
||||
position = data.position;
|
||||
spacing = data.spacing;
|
||||
rotateMix = data.rotateMix;
|
||||
translateMix = data.translateMix;
|
||||
}
|
||||
|
||||
var positions:Vector.<Number> = computeWorldPositions(attachment, spacesCount, tangents,
|
||||
data.positionMode == PositionMode.percent, spacingMode == SpacingMode.percent);
|
||||
var boneX:Number = positions[0], boneY:Number = positions[1], offsetRotation:Number = data.offsetRotation;
|
||||
var tip:Boolean = false;
|
||||
if (offsetRotation == 0)
|
||||
tip = rotateMode == RotateMode.chain;
|
||||
else {
|
||||
tip = false;
|
||||
var pa:Bone = target.bone;
|
||||
offsetRotation *= pa.a * pa.d - pa.b * pa.c > 0 ? MathUtils.degRad : -MathUtils.degRad;
|
||||
public function apply() : void {
|
||||
update();
|
||||
}
|
||||
var p:Number;
|
||||
for (i = 0, p = 3; i < boneCount; i++, p += 3) {
|
||||
bone = bones[i];
|
||||
bone.worldX += (boneX - bone.worldX) * translateMix;
|
||||
bone.worldY += (boneY - bone.worldY) * translateMix;
|
||||
x = positions[p]; y = positions[p + 1]; var dx:Number = x - boneX, dy:Number = y - boneY;
|
||||
if (scale) {
|
||||
length = lengths[i];
|
||||
if (length != 0) {
|
||||
var s:Number = (Math.sqrt(dx * dx + dy * dy) / length - 1) * rotateMix + 1;
|
||||
bone.a *= s;
|
||||
bone.c *= s;
|
||||
|
||||
public function update() : void {
|
||||
var attachment : PathAttachment = target.attachment as PathAttachment;
|
||||
if (attachment == null) return;
|
||||
|
||||
var rotateMix : Number = this.rotateMix, translateMix : Number = this.translateMix;
|
||||
var translate : Boolean = translateMix > 0, rotate : Boolean = rotateMix > 0;
|
||||
if (!translate && !rotate) return;
|
||||
|
||||
var data : PathConstraintData = this._data;
|
||||
var spacingMode : SpacingMode = data.spacingMode;
|
||||
var lengthSpacing : Boolean = spacingMode == SpacingMode.length;
|
||||
var rotateMode : RotateMode = data.rotateMode;
|
||||
var tangents : Boolean = rotateMode == RotateMode.tangent, scale : Boolean = rotateMode == RotateMode.chainScale;
|
||||
var boneCount : int = this._bones.length, spacesCount : int = tangents ? boneCount : boneCount + 1;
|
||||
var bones : Vector.<Bone> = this._bones;
|
||||
this._spaces.length = spacesCount;
|
||||
var spaces : Vector.<Number> = this._spaces, lengths : Vector.<Number> = null;
|
||||
var spacing : Number = this.spacing;
|
||||
if (scale || lengthSpacing) {
|
||||
if (scale) {
|
||||
this._lengths.length = boneCount;
|
||||
lengths = this._lengths;
|
||||
}
|
||||
for (var i : int = 0, n : int = spacesCount - 1; i < n;) {
|
||||
var bone : Bone = bones[i];
|
||||
var setupLength : Number = bone.data.length, x : Number = setupLength * bone.a, y : Number = setupLength * bone.c;
|
||||
var length : Number = Math.sqrt(x * x + y * y);
|
||||
if (scale) lengths[i] = length;
|
||||
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength;
|
||||
}
|
||||
} else {
|
||||
for (i = 1; i < spacesCount; i++)
|
||||
spaces[i] = spacing;
|
||||
}
|
||||
boneX = x;
|
||||
boneY = y;
|
||||
if (rotate) {
|
||||
var a:Number = bone.a, b:Number = bone.b, c:Number = bone.c, d:Number = bone.d, r:Number, cos:Number, sin:Number;
|
||||
if (tangents)
|
||||
r = positions[p - 1];
|
||||
else if (spaces[i + 1] == 0)
|
||||
r = positions[p + 2];
|
||||
else
|
||||
r = Math.atan2(dy, dx);
|
||||
r -= Math.atan2(c, a);
|
||||
if (tip) {
|
||||
|
||||
var positions : Vector.<Number> = computeWorldPositions(attachment, spacesCount, tangents, data.positionMode == PositionMode.percent, spacingMode == SpacingMode.percent);
|
||||
var boneX : Number = positions[0], boneY : Number = positions[1], offsetRotation : Number = data.offsetRotation;
|
||||
var tip : Boolean = false;
|
||||
if (offsetRotation == 0)
|
||||
tip = rotateMode == RotateMode.chain;
|
||||
else {
|
||||
tip = false;
|
||||
var pa : Bone = target.bone;
|
||||
offsetRotation *= pa.a * pa.d - pa.b * pa.c > 0 ? MathUtils.degRad : -MathUtils.degRad;
|
||||
}
|
||||
var p : Number;
|
||||
for (i = 0, p = 3; i < boneCount; i++, p += 3) {
|
||||
bone = bones[i];
|
||||
bone.worldX += (boneX - bone.worldX) * translateMix;
|
||||
bone.worldY += (boneY - bone.worldY) * translateMix;
|
||||
x = positions[p];
|
||||
y = positions[p + 1];
|
||||
var dx : Number = x - boneX, dy : Number = y - boneY;
|
||||
if (scale) {
|
||||
length = lengths[i];
|
||||
if (length != 0) {
|
||||
var s : Number = (Math.sqrt(dx * dx + dy * dy) / length - 1) * rotateMix + 1;
|
||||
bone.a *= s;
|
||||
bone.c *= s;
|
||||
}
|
||||
}
|
||||
boneX = x;
|
||||
boneY = y;
|
||||
if (rotate) {
|
||||
var a : Number = bone.a, b : Number = bone.b, c : Number = bone.c, d : Number = bone.d, r : Number, cos : Number, sin : Number;
|
||||
if (tangents)
|
||||
r = positions[p - 1];
|
||||
else if (spaces[i + 1] == 0)
|
||||
r = positions[p + 2];
|
||||
else
|
||||
r = Math.atan2(dy, dx);
|
||||
r -= Math.atan2(c, a);
|
||||
if (tip) {
|
||||
cos = Math.cos(r);
|
||||
sin = Math.sin(r);
|
||||
length = bone.data.length;
|
||||
boneX += (length * (cos * a - sin * c) - dx) * rotateMix;
|
||||
boneY += (length * (sin * a + cos * c) - dy) * rotateMix;
|
||||
} else {
|
||||
r += offsetRotation;
|
||||
}
|
||||
if (r > Math.PI)
|
||||
r -= (Math.PI * 2);
|
||||
else if (r < -Math.PI) //
|
||||
r += (Math.PI * 2);
|
||||
r *= rotateMix;
|
||||
cos = Math.cos(r);
|
||||
sin = Math.sin(r);
|
||||
length = bone.data.length;
|
||||
boneX += (length * (cos * a - sin * c) - dx) * rotateMix;
|
||||
boneY += (length * (sin * a + cos * c) - dy) * rotateMix;
|
||||
} else {
|
||||
r += offsetRotation;
|
||||
bone.a = cos * a - sin * c;
|
||||
bone.b = cos * b - sin * d;
|
||||
bone.c = sin * a + cos * c;
|
||||
bone.d = sin * b + cos * d;
|
||||
}
|
||||
if (r > Math.PI)
|
||||
r -= (Math.PI * 2);
|
||||
else if (r < -Math.PI) //
|
||||
r += (Math.PI * 2);
|
||||
r *= rotateMix;
|
||||
cos = Math.cos(r);
|
||||
sin = Math.sin(r);
|
||||
bone.a = cos * a - sin * c;
|
||||
bone.b = cos * b - sin * d;
|
||||
bone.c = sin * a + cos * c;
|
||||
bone.d = sin * b + cos * d;
|
||||
bone.appliedValid = false;
|
||||
}
|
||||
bone.appliedValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected function computeWorldPositions (path:PathAttachment, spacesCount:int, tangents:Boolean, percentPosition:Boolean,
|
||||
percentSpacing:Boolean) : Vector.<Number> {
|
||||
var target:Slot = this.target;
|
||||
var position:Number = this.position;
|
||||
var spaces:Vector.<Number> = this._spaces;
|
||||
this._positions.length = spacesCount * 3 + 2;
|
||||
var out:Vector.<Number> = this._positions, world:Vector.<Number>;
|
||||
var closed:Boolean = path.closed;
|
||||
var verticesLength:int = path.worldVerticesLength, curveCount:int = verticesLength / 6, prevCurve:int = NONE;
|
||||
protected function computeWorldPositions(path : PathAttachment, spacesCount : int, tangents : Boolean, percentPosition : Boolean, percentSpacing : Boolean) : Vector.<Number> {
|
||||
var target : Slot = this.target;
|
||||
var position : Number = this.position;
|
||||
var spaces : Vector.<Number> = this._spaces;
|
||||
this._positions.length = spacesCount * 3 + 2;
|
||||
var out : Vector.<Number> = this._positions, world : Vector.<Number>;
|
||||
var closed : Boolean = path.closed;
|
||||
var verticesLength : int = path.worldVerticesLength, curveCount : int = verticesLength / 6, prevCurve : int = NONE;
|
||||
|
||||
if (!path.constantSpeed) {
|
||||
var lengths:Vector.<Number> = path.lengths;
|
||||
curveCount -= closed ? 1 : 2;
|
||||
var pathLength:Number = lengths[curveCount];
|
||||
if (!path.constantSpeed) {
|
||||
var lengths : Vector.<Number> = path.lengths;
|
||||
curveCount -= closed ? 1 : 2;
|
||||
var pathLength : Number = lengths[curveCount];
|
||||
if (percentPosition) position *= pathLength;
|
||||
if (percentSpacing) {
|
||||
for (var i : int = 0; i < spacesCount; i++)
|
||||
spaces[i] *= pathLength;
|
||||
}
|
||||
this._world.length = 8;
|
||||
world = this._world;
|
||||
var o : int, curve : int;
|
||||
for (i = 0, o = 0, curve = 0; i < spacesCount; i++, o += 3) {
|
||||
var space : Number = spaces[i];
|
||||
position += space;
|
||||
var p : Number = position;
|
||||
|
||||
if (closed) {
|
||||
p %= pathLength;
|
||||
if (p < 0) p += pathLength;
|
||||
curve = 0;
|
||||
} else if (p < 0) {
|
||||
if (prevCurve != BEFORE) {
|
||||
prevCurve = BEFORE;
|
||||
path.computeWorldVertices(target, 2, 4, world, 0, 2);
|
||||
}
|
||||
addBeforePosition(p, world, 0, out, o);
|
||||
continue;
|
||||
} else if (p > pathLength) {
|
||||
if (prevCurve != AFTER) {
|
||||
prevCurve = AFTER;
|
||||
path.computeWorldVertices(target, verticesLength - 6, 4, world, 0, 2);
|
||||
}
|
||||
addAfterPosition(p - pathLength, world, 0, out, o);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Determine curve containing position.
|
||||
for (;; curve++) {
|
||||
var length : Number = lengths[curve];
|
||||
if (p > length) continue;
|
||||
if (curve == 0)
|
||||
p /= length;
|
||||
else {
|
||||
var prev : Number = lengths[curve - 1];
|
||||
p = (p - prev) / (length - prev);
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (curve != prevCurve) {
|
||||
prevCurve = curve;
|
||||
if (closed && curve == curveCount) {
|
||||
path.computeWorldVertices(target, verticesLength - 4, 4, world, 0, 2);
|
||||
path.computeWorldVertices(target, 0, 4, world, 4, 2);
|
||||
} else
|
||||
path.computeWorldVertices(target, 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, tangents || (i > 0 && space == 0));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// World vertices.
|
||||
if (closed) {
|
||||
verticesLength += 2;
|
||||
this._world.length = verticesLength;
|
||||
world = this._world;
|
||||
path.computeWorldVertices(target, 2, verticesLength - 4, world, 0, 2);
|
||||
path.computeWorldVertices(target, 0, 2, world, verticesLength - 4, 2);
|
||||
world[verticesLength - 2] = world[0];
|
||||
world[verticesLength - 1] = world[1];
|
||||
} else {
|
||||
curveCount--;
|
||||
verticesLength -= 4;
|
||||
this._world.length = verticesLength;
|
||||
world = this._world;
|
||||
path.computeWorldVertices(target, 2, verticesLength, world, 0, 2);
|
||||
}
|
||||
|
||||
// Curve lengths.
|
||||
this._curves.length = curveCount;
|
||||
var curves : Vector.<Number> = this._curves;
|
||||
pathLength = 0;
|
||||
var x1 : Number = world[0], y1 : Number = world[1], cx1 : Number = 0, cy1 : Number = 0, cx2 : Number = 0, cy2 : Number = 0, x2 : Number = 0, y2 : Number = 0;
|
||||
var tmpx : Number, tmpy : Number, dddfx : Number, dddfy : Number, ddfx : Number, ddfy : Number, dfx : Number, dfy : Number;
|
||||
var w : int;
|
||||
for (i = 0, w = 2; i < curveCount; i++, w += 6) {
|
||||
cx1 = world[w];
|
||||
cy1 = world[w + 1];
|
||||
cx2 = world[w + 2];
|
||||
cy2 = world[w + 3];
|
||||
x2 = world[w + 4];
|
||||
y2 = world[w + 5];
|
||||
tmpx = (x1 - cx1 * 2 + cx2) * 0.1875;
|
||||
tmpy = (y1 - cy1 * 2 + cy2) * 0.1875;
|
||||
dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375;
|
||||
dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375;
|
||||
ddfx = tmpx * 2 + dddfx;
|
||||
ddfy = tmpy * 2 + dddfy;
|
||||
dfx = (cx1 - x1) * 0.75 + tmpx + dddfx * 0.16666667;
|
||||
dfy = (cy1 - y1) * 0.75 + tmpy + dddfy * 0.16666667;
|
||||
pathLength += Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
dfx += ddfx;
|
||||
dfy += ddfy;
|
||||
ddfx += dddfx;
|
||||
ddfy += dddfy;
|
||||
pathLength += Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
dfx += ddfx;
|
||||
dfy += ddfy;
|
||||
pathLength += Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
dfx += ddfx + dddfx;
|
||||
dfy += ddfy + dddfy;
|
||||
pathLength += Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
curves[i] = pathLength;
|
||||
x1 = x2;
|
||||
y1 = y2;
|
||||
}
|
||||
if (percentPosition) position *= pathLength;
|
||||
if (percentSpacing) {
|
||||
for (var i:int = 0; i < spacesCount; i++)
|
||||
for (i = 0; i < spacesCount; i++)
|
||||
spaces[i] *= pathLength;
|
||||
}
|
||||
this._world.length = 8;
|
||||
world = this._world;
|
||||
var o:int, curve:int;
|
||||
for (i = 0, o = 0, curve = 0; i < spacesCount; i++, o += 3) {
|
||||
var space:Number = spaces[i];
|
||||
|
||||
var segments : Vector.<Number> = this._segments;
|
||||
var curveLength : Number = 0;
|
||||
var segment : int;
|
||||
for (i = 0, o = 0, curve = 0, segment = 0; i < spacesCount; i++, o += 3) {
|
||||
space = spaces[i];
|
||||
position += space;
|
||||
var p:Number = position;
|
||||
p = position;
|
||||
|
||||
if (closed) {
|
||||
p %= pathLength;
|
||||
if (p < 0) p += pathLength;
|
||||
curve = 0;
|
||||
} else if (p < 0) {
|
||||
if (prevCurve != BEFORE) {
|
||||
prevCurve = BEFORE;
|
||||
path.computeWorldVertices(target, 2, 4, world, 0, 2);
|
||||
}
|
||||
addBeforePosition(p, world, 0, out, o);
|
||||
continue;
|
||||
} else if (p > pathLength) {
|
||||
if (prevCurve != AFTER) {
|
||||
prevCurve = AFTER;
|
||||
path.computeWorldVertices(target, verticesLength - 6, 4, world, 0, 2);
|
||||
}
|
||||
addAfterPosition(p - pathLength, world, 0, out, o);
|
||||
addAfterPosition(p - pathLength, world, verticesLength - 4, out, o);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Determine curve containing position.
|
||||
for (;; curve++) {
|
||||
var length:Number = lengths[curve];
|
||||
length = curves[curve];
|
||||
if (p > length) continue;
|
||||
if (curve == 0)
|
||||
p /= length;
|
||||
else {
|
||||
var prev:Number = lengths[curve - 1];
|
||||
prev = curves[curve - 1];
|
||||
p = (p - prev) / (length - prev);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Curve segment lengths.
|
||||
if (curve != prevCurve) {
|
||||
prevCurve = curve;
|
||||
if (closed && curve == curveCount) {
|
||||
path.computeWorldVertices(target, verticesLength - 4, 4, world, 0, 2);
|
||||
path.computeWorldVertices(target, 0, 4, world, 4, 2);
|
||||
} else
|
||||
path.computeWorldVertices(target, curve * 6 + 2, 8, world, 0, 2);
|
||||
var ii : int = curve * 6;
|
||||
x1 = world[ii];
|
||||
y1 = world[ii + 1];
|
||||
cx1 = world[ii + 2];
|
||||
cy1 = world[ii + 3];
|
||||
cx2 = world[ii + 4];
|
||||
cy2 = world[ii + 5];
|
||||
x2 = world[ii + 6];
|
||||
y2 = world[ii + 7];
|
||||
tmpx = (x1 - cx1 * 2 + cx2) * 0.03;
|
||||
tmpy = (y1 - cy1 * 2 + cy2) * 0.03;
|
||||
dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.006;
|
||||
dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.006;
|
||||
ddfx = tmpx * 2 + dddfx;
|
||||
ddfy = tmpy * 2 + dddfy;
|
||||
dfx = (cx1 - x1) * 0.3 + tmpx + dddfx * 0.16666667;
|
||||
dfy = (cy1 - y1) * 0.3 + tmpy + dddfy * 0.16666667;
|
||||
curveLength = Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
segments[0] = curveLength;
|
||||
for (ii = 1; ii < 8; ii++) {
|
||||
dfx += ddfx;
|
||||
dfy += ddfy;
|
||||
ddfx += dddfx;
|
||||
ddfy += dddfy;
|
||||
curveLength += Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
segments[ii] = curveLength;
|
||||
}
|
||||
dfx += ddfx;
|
||||
dfy += ddfy;
|
||||
curveLength += Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
segments[8] = curveLength;
|
||||
dfx += ddfx + dddfx;
|
||||
dfy += ddfy + dddfy;
|
||||
curveLength += Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
segments[9] = curveLength;
|
||||
segment = 0;
|
||||
}
|
||||
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));
|
||||
|
||||
// Weight by segment length.
|
||||
p *= curveLength;
|
||||
for (;; segment++) {
|
||||
length = segments[segment];
|
||||
if (p > length) continue;
|
||||
if (segment == 0)
|
||||
p /= length;
|
||||
else {
|
||||
prev = segments[segment - 1];
|
||||
p = segment + (p - prev) / (length - prev);
|
||||
}
|
||||
break;
|
||||
}
|
||||
addCurvePosition(p * 0.1, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents || (i > 0 && space == 0));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
// World vertices.
|
||||
if (closed) {
|
||||
verticesLength += 2;
|
||||
this._world.length = verticesLength;
|
||||
world = this._world;
|
||||
path.computeWorldVertices(target, 2, verticesLength - 4, world, 0, 2);
|
||||
path.computeWorldVertices(target, 0, 2, world, verticesLength - 4, 2);
|
||||
world[verticesLength - 2] = world[0];
|
||||
world[verticesLength - 1] = world[1];
|
||||
} else {
|
||||
curveCount--;
|
||||
verticesLength -= 4;
|
||||
this._world.length = verticesLength;
|
||||
world = this._world;
|
||||
path.computeWorldVertices(target, 2, verticesLength, world, 0, 2);
|
||||
private function addBeforePosition(p : Number, temp : Vector.<Number>, i : int, out : Vector.<Number>, o : int) : void {
|
||||
var x1 : Number = temp[i], y1 : Number = temp[i + 1], dx : Number = temp[i + 2] - x1, dy : Number = temp[i + 3] - y1, r : Number = Math.atan2(dy, dx);
|
||||
out[o] = x1 + p * Math.cos(r);
|
||||
out[o + 1] = y1 + p * Math.sin(r);
|
||||
out[o + 2] = r;
|
||||
}
|
||||
|
||||
// Curve lengths.
|
||||
this._curves.length = curveCount;
|
||||
var curves:Vector.<Number> = this._curves;
|
||||
pathLength = 0;
|
||||
var x1:Number = world[0], y1:Number = world[1], cx1:Number = 0, cy1:Number = 0, cx2:Number = 0, cy2:Number = 0, x2:Number = 0, y2:Number = 0;
|
||||
var tmpx:Number, tmpy:Number, dddfx:Number, dddfy:Number, ddfx:Number, ddfy:Number, dfx:Number, dfy:Number;
|
||||
var w:int;
|
||||
for (i = 0, w = 2; i < curveCount; i++, w += 6) {
|
||||
cx1 = world[w];
|
||||
cy1 = world[w + 1];
|
||||
cx2 = world[w + 2];
|
||||
cy2 = world[w + 3];
|
||||
x2 = world[w + 4];
|
||||
y2 = world[w + 5];
|
||||
tmpx = (x1 - cx1 * 2 + cx2) * 0.1875;
|
||||
tmpy = (y1 - cy1 * 2 + cy2) * 0.1875;
|
||||
dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375;
|
||||
dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375;
|
||||
ddfx = tmpx * 2 + dddfx;
|
||||
ddfy = tmpy * 2 + dddfy;
|
||||
dfx = (cx1 - x1) * 0.75 + tmpx + dddfx * 0.16666667;
|
||||
dfy = (cy1 - y1) * 0.75 + tmpy + dddfy * 0.16666667;
|
||||
pathLength += Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
dfx += ddfx;
|
||||
dfy += ddfy;
|
||||
ddfx += dddfx;
|
||||
ddfy += dddfy;
|
||||
pathLength += Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
dfx += ddfx;
|
||||
dfy += ddfy;
|
||||
pathLength += Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
dfx += ddfx + dddfx;
|
||||
dfy += ddfy + dddfy;
|
||||
pathLength += Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
curves[i] = pathLength;
|
||||
x1 = x2;
|
||||
y1 = y2;
|
||||
}
|
||||
if (percentPosition) position *= pathLength;
|
||||
if (percentSpacing) {
|
||||
for (i = 0; i < spacesCount; i++)
|
||||
spaces[i] *= pathLength;
|
||||
private function addAfterPosition(p : Number, temp : Vector.<Number>, i : int, out : Vector.<Number>, o : int) : void {
|
||||
var x1 : Number = temp[i + 2], y1 : Number = temp[i + 3], dx : Number = x1 - temp[i], dy : Number = y1 - temp[i + 1], r : Number = Math.atan2(dy, dx);
|
||||
out[o] = x1 + p * Math.cos(r);
|
||||
out[o + 1] = y1 + p * Math.sin(r);
|
||||
out[o + 2] = r;
|
||||
}
|
||||
|
||||
var segments:Vector.<Number> = this._segments;
|
||||
var curveLength:Number = 0;
|
||||
var segment:int;
|
||||
for (i = 0, o = 0, curve = 0, segment = 0; i < spacesCount; i++, o += 3) {
|
||||
space = spaces[i];
|
||||
position += space;
|
||||
p = position;
|
||||
|
||||
if (closed) {
|
||||
p %= pathLength;
|
||||
if (p < 0) p += pathLength;
|
||||
curve = 0;
|
||||
} else if (p < 0) {
|
||||
addBeforePosition(p, world, 0, out, o);
|
||||
continue;
|
||||
} else if (p > pathLength) {
|
||||
addAfterPosition(p - pathLength, world, verticesLength - 4, out, o);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Determine curve containing position.
|
||||
for (;; curve++) {
|
||||
length = curves[curve];
|
||||
if (p > length) continue;
|
||||
if (curve == 0)
|
||||
p /= length;
|
||||
else {
|
||||
prev = curves[curve - 1];
|
||||
p = (p - prev) / (length - prev);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Curve segment lengths.
|
||||
if (curve != prevCurve) {
|
||||
prevCurve = curve;
|
||||
var ii:int = curve * 6;
|
||||
x1 = world[ii];
|
||||
y1 = world[ii + 1];
|
||||
cx1 = world[ii + 2];
|
||||
cy1 = world[ii + 3];
|
||||
cx2 = world[ii + 4];
|
||||
cy2 = world[ii + 5];
|
||||
x2 = world[ii + 6];
|
||||
y2 = world[ii + 7];
|
||||
tmpx = (x1 - cx1 * 2 + cx2) * 0.03;
|
||||
tmpy = (y1 - cy1 * 2 + cy2) * 0.03;
|
||||
dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.006;
|
||||
dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.006;
|
||||
ddfx = tmpx * 2 + dddfx;
|
||||
ddfy = tmpy * 2 + dddfy;
|
||||
dfx = (cx1 - x1) * 0.3 + tmpx + dddfx * 0.16666667;
|
||||
dfy = (cy1 - y1) * 0.3 + tmpy + dddfy * 0.16666667;
|
||||
curveLength = Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
segments[0] = curveLength;
|
||||
for (ii = 1; ii < 8; ii++) {
|
||||
dfx += ddfx;
|
||||
dfy += ddfy;
|
||||
ddfx += dddfx;
|
||||
ddfy += dddfy;
|
||||
curveLength += Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
segments[ii] = curveLength;
|
||||
}
|
||||
dfx += ddfx;
|
||||
dfy += ddfy;
|
||||
curveLength += Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
segments[8] = curveLength;
|
||||
dfx += ddfx + dddfx;
|
||||
dfy += ddfy + dddfy;
|
||||
curveLength += Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
segments[9] = curveLength;
|
||||
segment = 0;
|
||||
}
|
||||
|
||||
// Weight by segment length.
|
||||
p *= curveLength;
|
||||
for (;; segment++) {
|
||||
length = segments[segment];
|
||||
if (p > length) continue;
|
||||
if (segment == 0)
|
||||
p /= length;
|
||||
else {
|
||||
prev = segments[segment - 1];
|
||||
p = segment + (p - prev) / (length - prev);
|
||||
}
|
||||
break;
|
||||
}
|
||||
addCurvePosition(p * 0.1, x1, y1, cx1, cy1, cx2, cy2, x2, y2, out, o, tangents || (i > 0 && space == 0));
|
||||
private function addCurvePosition(p : Number, x1 : Number, y1 : Number, cx1 : Number, cy1 : Number, cx2 : Number, cy2 : Number, x2 : Number, y2 : Number, out : Vector.<Number>, o : int, tangents : Boolean) : void {
|
||||
if (p == 0 || isNaN(p)) p = 0.0001;
|
||||
var tt : Number = p * p, ttt : Number = tt * p, u : Number = 1 - p, uu : Number = u * u, uuu : Number = uu * u;
|
||||
var ut : Number = u * p, ut3 : Number = ut * 3, uut3 : Number = u * ut3, utt3 : Number = ut3 * p;
|
||||
var x : Number = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y : Number = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt;
|
||||
out[o] = x;
|
||||
out[o + 1] = y;
|
||||
if (tangents) out[o + 2] = Math.atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt));
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
private function addBeforePosition (p:Number, temp:Vector.<Number>, i:int, out:Vector.<Number>, o:int) : void {
|
||||
var x1:Number = temp[i], y1:Number = temp[i + 1], dx:Number = temp[i + 2] - x1, dy:Number = temp[i + 3] - y1, r:Number = Math.atan2(dy, dx);
|
||||
out[o] = x1 + p * Math.cos(r);
|
||||
out[o + 1] = y1 + p * Math.sin(r);
|
||||
out[o + 2] = r;
|
||||
}
|
||||
public function get bones() : Vector.<Bone> {
|
||||
return _bones;
|
||||
}
|
||||
|
||||
private function addAfterPosition (p:Number, temp:Vector.<Number>, i:int, out:Vector.<Number>, o:int) : void {
|
||||
var x1:Number = temp[i + 2], y1:Number = temp[i + 3], dx:Number = x1 - temp[i], dy:Number = y1 - temp[i + 1], r:Number = Math.atan2(dy, dx);
|
||||
out[o] = x1 + p * Math.cos(r);
|
||||
out[o + 1] = y1 + p * Math.sin(r);
|
||||
out[o + 2] = r;
|
||||
}
|
||||
public function get data() : PathConstraintData {
|
||||
return _data;
|
||||
}
|
||||
|
||||
private function addCurvePosition (p:Number, x1:Number, y1:Number, cx1:Number, cy1:Number, cx2:Number, cy2:Number, x2:Number, y2:Number,
|
||||
out:Vector.<Number>, o:int, tangents:Boolean) : void {
|
||||
if (p == 0 || isNaN(p)) p = 0.0001;
|
||||
var tt:Number = p * p, ttt:Number = tt * p, u:Number = 1 - p, uu:Number = u * u, uuu:Number = uu * u;
|
||||
var ut:Number = u * p, ut3:Number = ut * 3, uut3:Number = u * ut3, utt3:Number = ut3 * p;
|
||||
var x:Number = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y:Number = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt;
|
||||
out[o] = x;
|
||||
out[o + 1] = y;
|
||||
if (tangents) out[o + 2] = Math.atan2(y - (y1 * uu + cy1 * ut * 2 + cy2 * tt), x - (x1 * uu + cx1 * ut * 2 + cx2 * tt));
|
||||
}
|
||||
public function getOrder() : Number {
|
||||
return _data.order;
|
||||
}
|
||||
|
||||
public function get bones () : Vector.<Bone> {
|
||||
return _bones;
|
||||
public function toString() : String {
|
||||
return _data.name;
|
||||
}
|
||||
}
|
||||
|
||||
public function get data () : PathConstraintData {
|
||||
return _data;
|
||||
}
|
||||
|
||||
public function getOrder () : Number {
|
||||
return _data.order;
|
||||
}
|
||||
|
||||
public function toString () : String {
|
||||
return _data.name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,34 +29,32 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
public dynamic class PathConstraintData {
|
||||
internal var _name : String;
|
||||
public var order : Number;
|
||||
internal var _bones : Vector.<BoneData> = new Vector.<BoneData>();
|
||||
public var target : SlotData;
|
||||
public var positionMode : PositionMode;
|
||||
public var spacingMode : SpacingMode;
|
||||
public var rotateMode : RotateMode;
|
||||
public var offsetRotation : Number;
|
||||
public var position : Number, spacing : Number, rotateMix : Number, translateMix : Number;
|
||||
|
||||
public dynamic class PathConstraintData {
|
||||
internal var _name:String;
|
||||
public var order:Number;
|
||||
internal var _bones:Vector.<BoneData> = new Vector.<BoneData>();
|
||||
public var target:SlotData;
|
||||
public var positionMode:PositionMode;
|
||||
public var spacingMode:SpacingMode;
|
||||
public var rotateMode:RotateMode;
|
||||
public var offsetRotation:Number;
|
||||
public var position:Number, spacing:Number, rotateMix:Number, translateMix:Number;
|
||||
public function PathConstraintData(name : String) {
|
||||
if (name == null) throw new ArgumentError("name cannot be null.");
|
||||
_name = name;
|
||||
}
|
||||
|
||||
public function PathConstraintData (name:String) {
|
||||
if (name == null) throw new ArgumentError("name cannot be null.");
|
||||
_name = name;
|
||||
public function get bones() : Vector.<BoneData> {
|
||||
return _bones;
|
||||
}
|
||||
|
||||
public function get name() : String {
|
||||
return _name;
|
||||
}
|
||||
|
||||
public function toString() : String {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
public function get bones () : Vector.<BoneData> {
|
||||
return _bones;
|
||||
}
|
||||
|
||||
public function get name () : String {
|
||||
return _name;
|
||||
}
|
||||
|
||||
public function toString () : String {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,54 +29,52 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
public class Polygon {
|
||||
public var vertices : Vector.<Number> = new Vector.<Number>();
|
||||
|
||||
public class Polygon {
|
||||
public var vertices:Vector.<Number> = new Vector.<Number>();
|
||||
|
||||
public function Polygon () {
|
||||
}
|
||||
|
||||
/** Returns true if the polygon contains the point. */
|
||||
public function containsPoint (x:Number, y:Number) : Boolean {
|
||||
var nn:int = vertices.length;
|
||||
|
||||
var prevIndex:int = nn - 2;
|
||||
var inside:Boolean = false;
|
||||
for (var ii:int = 0; ii < nn; ii += 2) {
|
||||
var vertexY:Number = vertices[ii + 1];
|
||||
var prevY:Number = vertices[prevIndex + 1];
|
||||
if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) {
|
||||
var vertexX:Number = vertices[ii];
|
||||
if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) inside = !inside;
|
||||
}
|
||||
prevIndex = ii;
|
||||
public function Polygon() {
|
||||
}
|
||||
|
||||
return inside;
|
||||
}
|
||||
|
||||
/** Returns true if the polygon contains the line segment. */
|
||||
public function intersectsSegment (x1:Number, y1:Number, x2:Number, y2:Number) : Boolean {
|
||||
var nn:int = vertices.length;
|
||||
|
||||
var width12:Number = x1 - x2, height12:Number = y1 - y2;
|
||||
var det1:Number = x1 * y2 - y1 * x2;
|
||||
var x3:Number = vertices[nn - 2], y3:Number = vertices[nn - 1];
|
||||
for (var ii:int = 0; ii < nn; ii += 2) {
|
||||
var x4:Number = vertices[ii], y4:Number = vertices[ii + 1];
|
||||
var det2:Number = x3 * y4 - y3 * x4;
|
||||
var width34:Number = x3 - x4, height34:Number = y3 - y4;
|
||||
var det3:Number = width12 * height34 - height12 * width34;
|
||||
var x:Number = (det1 * width34 - width12 * det2) / det3;
|
||||
if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) {
|
||||
var y:Number = (det1 * height34 - height12 * det2) / det3;
|
||||
if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return true;
|
||||
/** Returns true if the polygon contains the point. */
|
||||
public function containsPoint(x : Number, y : Number) : Boolean {
|
||||
var nn : int = vertices.length;
|
||||
|
||||
var prevIndex : int = nn - 2;
|
||||
var inside : Boolean = false;
|
||||
for (var ii : int = 0; ii < nn; ii += 2) {
|
||||
var vertexY : Number = vertices[ii + 1];
|
||||
var prevY : Number = vertices[prevIndex + 1];
|
||||
if ((vertexY < y && prevY >= y) || (prevY < y && vertexY >= y)) {
|
||||
var vertexX : Number = vertices[ii];
|
||||
if (vertexX + (y - vertexY) / (prevY - vertexY) * (vertices[prevIndex] - vertexX) < x) inside = !inside;
|
||||
}
|
||||
prevIndex = ii;
|
||||
}
|
||||
x3 = x4;
|
||||
y3 = y4;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return inside;
|
||||
}
|
||||
|
||||
/** Returns true if the polygon contains the line segment. */
|
||||
public function intersectsSegment(x1 : Number, y1 : Number, x2 : Number, y2 : Number) : Boolean {
|
||||
var nn : int = vertices.length;
|
||||
|
||||
var width12 : Number = x1 - x2, height12 : Number = y1 - y2;
|
||||
var det1 : Number = x1 * y2 - y1 * x2;
|
||||
var x3 : Number = vertices[nn - 2], y3 : Number = vertices[nn - 1];
|
||||
for (var ii : int = 0; ii < nn; ii += 2) {
|
||||
var x4 : Number = vertices[ii], y4 : Number = vertices[ii + 1];
|
||||
var det2 : Number = x3 * y4 - y3 * x4;
|
||||
var width34 : Number = x3 - x4, height34 : Number = y3 - y4;
|
||||
var det3 : Number = width12 * height34 - height12 * width34;
|
||||
var x : Number = (det1 * width34 - width12 * det2) / det3;
|
||||
if (((x >= x3 && x <= x4) || (x >= x4 && x <= x3)) && ((x >= x1 && x <= x2) || (x >= x2 && x <= x1))) {
|
||||
var y : Number = (det1 * height34 - height12 * det2) / det3;
|
||||
if (((y >= y3 && y <= y4) || (y >= y4 && y <= y3)) && ((y >= y1 && y <= y2) || (y >= y2 && y <= y1))) return true;
|
||||
}
|
||||
x3 = x4;
|
||||
y3 = y4;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -29,32 +29,31 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
|
||||
public class Pool {
|
||||
internal var items:Vector.<Object> = new Vector.<Object>();
|
||||
internal var instantiator:Function;
|
||||
|
||||
public function Pool(instantiator:Function) {
|
||||
this.instantiator = instantiator;
|
||||
}
|
||||
|
||||
public function obtain (): Object {
|
||||
return this.items.length > 0 ? this.items.pop() : this.instantiator();
|
||||
}
|
||||
|
||||
public function free (item:Object):void {
|
||||
if (item is Poolable) Poolable(item).reset();
|
||||
items.push(item);
|
||||
}
|
||||
|
||||
public function freeAll (items:Vector):void {
|
||||
for (var i:int = 0; i < items.length; i++) {
|
||||
free(items[i]);
|
||||
public class Pool {
|
||||
internal var items : Vector.<Object> = new Vector.<Object>();
|
||||
internal var instantiator : Function;
|
||||
|
||||
public function Pool(instantiator : Function) {
|
||||
this.instantiator = instantiator;
|
||||
}
|
||||
|
||||
public function obtain() : Object {
|
||||
return this.items.length > 0 ? this.items.pop() : this.instantiator();
|
||||
}
|
||||
|
||||
public function free(item : Object) : void {
|
||||
if (item is Poolable) Poolable(item).reset();
|
||||
items.push(item);
|
||||
}
|
||||
|
||||
public function freeAll(items : Vector) : void {
|
||||
for (var i : int = 0; i < items.length; i++) {
|
||||
free(items[i]);
|
||||
}
|
||||
}
|
||||
|
||||
public function clear() : void {
|
||||
items.length = 0;
|
||||
}
|
||||
}
|
||||
|
||||
public function clear ():void {
|
||||
items.length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,5 +1,35 @@
|
||||
/******************************************************************************
|
||||
* Spine Runtimes Software License v2.5
|
||||
*
|
||||
* Copyright (c) 2013-2016, Esoteric Software
|
||||
* All rights reserved.
|
||||
*
|
||||
* You are granted a perpetual, non-exclusive, non-sublicensable, and
|
||||
* non-transferable license to use, install, execute, and perform the Spine
|
||||
* Runtimes software and derivative works solely for personal or internal
|
||||
* use. Without the written permission of Esoteric Software (see Section 2 of
|
||||
* the Spine Software License Agreement), you may not (a) modify, translate,
|
||||
* adapt, or develop new applications using the Spine Runtimes or otherwise
|
||||
* create derivative works or improvements of the Spine Runtimes or (b) remove,
|
||||
* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
|
||||
* or other intellectual property or proprietary rights notices on or in the
|
||||
* Software, including any copy thereof. Redistributions in binary or source
|
||||
* form must include this license and terms.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
|
||||
* USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
public interface Poolable {
|
||||
function reset ():void;
|
||||
}
|
||||
public interface Poolable {
|
||||
function reset() : void;
|
||||
}
|
||||
}
|
||||
@ -29,10 +29,8 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
|
||||
public class PositionMode {
|
||||
public static const fixed:PositionMode = new PositionMode();
|
||||
public static const percent:PositionMode = new PositionMode();
|
||||
}
|
||||
|
||||
}
|
||||
public class PositionMode {
|
||||
public static const fixed : PositionMode = new PositionMode();
|
||||
public static const percent : PositionMode = new PositionMode();
|
||||
}
|
||||
}
|
||||
@ -29,11 +29,9 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
|
||||
public class RotateMode {
|
||||
public static const tangent:RotateMode = new RotateMode();
|
||||
public static const chain:RotateMode = new RotateMode();
|
||||
public static const chainScale:RotateMode = new RotateMode();
|
||||
}
|
||||
|
||||
}
|
||||
public class RotateMode {
|
||||
public static const tangent : RotateMode = new RotateMode();
|
||||
public static const chain : RotateMode = new RotateMode();
|
||||
public static const chainScale : RotateMode = new RotateMode();
|
||||
}
|
||||
}
|
||||
@ -29,477 +29,479 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
import spine.attachments.MeshAttachment;
|
||||
import spine.attachments.RegionAttachment;
|
||||
import flash.utils.Dictionary;
|
||||
import spine.attachments.PathAttachment;
|
||||
import spine.attachments.Attachment;
|
||||
import spine.attachments.MeshAttachment;
|
||||
import spine.attachments.RegionAttachment;
|
||||
|
||||
public class Skeleton {
|
||||
internal var _data:SkeletonData;
|
||||
public var bones:Vector.<Bone>;
|
||||
public var slots:Vector.<Slot>;
|
||||
public var drawOrder:Vector.<Slot>;
|
||||
public var ikConstraints:Vector.<IkConstraint>;
|
||||
public var transformConstraints:Vector.<TransformConstraint>;
|
||||
public var pathConstraints:Vector.<PathConstraint>;
|
||||
private var _updateCache:Vector.<Updatable> = new Vector.<Updatable>();
|
||||
private var _updateCacheReset:Vector.<Bone> = new Vector.<Bone>();
|
||||
private var _skin:Skin;
|
||||
public var color:Color = new Color(1, 1, 1, 1);
|
||||
public var time:Number = 0;
|
||||
public var flipX:Boolean, flipY:Boolean;
|
||||
public var x:Number = 0, y:Number = 0;
|
||||
import flash.utils.Dictionary;
|
||||
|
||||
public function Skeleton (data:SkeletonData) {
|
||||
if (data == null)
|
||||
throw new ArgumentError("data cannot be null.");
|
||||
_data = data;
|
||||
import spine.attachments.PathAttachment;
|
||||
import spine.attachments.Attachment;
|
||||
|
||||
bones = new Vector.<Bone>();
|
||||
for each (var boneData:BoneData in data.bones) {
|
||||
var bone:Bone;
|
||||
if (boneData.parent == null)
|
||||
bone = new Bone(boneData, this, null);
|
||||
else {
|
||||
var parent:Bone = bones[boneData.parent.index];
|
||||
bone = new Bone(boneData, this, parent);
|
||||
parent.children.push(bone);
|
||||
public class Skeleton {
|
||||
internal var _data : SkeletonData;
|
||||
public var bones : Vector.<Bone>;
|
||||
public var slots : Vector.<Slot>;
|
||||
public var drawOrder : Vector.<Slot>;
|
||||
public var ikConstraints : Vector.<IkConstraint>;
|
||||
public var transformConstraints : Vector.<TransformConstraint>;
|
||||
public var pathConstraints : Vector.<PathConstraint>;
|
||||
private var _updateCache : Vector.<Updatable> = new Vector.<Updatable>();
|
||||
private var _updateCacheReset : Vector.<Bone> = new Vector.<Bone>();
|
||||
private var _skin : Skin;
|
||||
public var color : Color = new Color(1, 1, 1, 1);
|
||||
public var time : Number = 0;
|
||||
public var flipX : Boolean, flipY : Boolean;
|
||||
public var x : Number = 0, y : Number = 0;
|
||||
|
||||
public function Skeleton(data : SkeletonData) {
|
||||
if (data == null)
|
||||
throw new ArgumentError("data cannot be null.");
|
||||
_data = data;
|
||||
|
||||
bones = new Vector.<Bone>();
|
||||
for each (var boneData : BoneData in data.bones) {
|
||||
var bone : Bone;
|
||||
if (boneData.parent == null)
|
||||
bone = new Bone(boneData, this, null);
|
||||
else {
|
||||
var parent : Bone = bones[boneData.parent.index];
|
||||
bone = new Bone(boneData, this, parent);
|
||||
parent.children.push(bone);
|
||||
}
|
||||
bones.push(bone);
|
||||
}
|
||||
bones.push(bone);
|
||||
|
||||
slots = new Vector.<Slot>();
|
||||
drawOrder = new Vector.<Slot>();
|
||||
for each (var slotData : SlotData in data.slots) {
|
||||
bone = bones[slotData.boneData.index];
|
||||
var slot : Slot = new Slot(slotData, bone);
|
||||
slots.push(slot);
|
||||
drawOrder[drawOrder.length] = slot;
|
||||
}
|
||||
|
||||
ikConstraints = new Vector.<IkConstraint>();
|
||||
for each (var ikConstraintData : IkConstraintData in data.ikConstraints)
|
||||
ikConstraints.push(new IkConstraint(ikConstraintData, this));
|
||||
|
||||
transformConstraints = new Vector.<TransformConstraint>();
|
||||
for each (var transformConstraintData : TransformConstraintData in data.transformConstraints)
|
||||
transformConstraints.push(new TransformConstraint(transformConstraintData, this));
|
||||
|
||||
pathConstraints = new Vector.<PathConstraint>();
|
||||
for each (var pathConstraintData : PathConstraintData in data.pathConstraints)
|
||||
pathConstraints.push(new PathConstraint(pathConstraintData, this));
|
||||
|
||||
updateCache();
|
||||
}
|
||||
|
||||
slots = new Vector.<Slot>();
|
||||
drawOrder = new Vector.<Slot>();
|
||||
for each (var slotData:SlotData in data.slots) {
|
||||
bone = bones[slotData.boneData.index];
|
||||
var slot:Slot = new Slot(slotData, bone);
|
||||
slots.push(slot);
|
||||
drawOrder[drawOrder.length] = slot;
|
||||
}
|
||||
|
||||
ikConstraints = new Vector.<IkConstraint>();
|
||||
for each (var ikConstraintData:IkConstraintData in data.ikConstraints)
|
||||
ikConstraints.push(new IkConstraint(ikConstraintData, this));
|
||||
|
||||
transformConstraints = new Vector.<TransformConstraint>();
|
||||
for each (var transformConstraintData:TransformConstraintData in data.transformConstraints)
|
||||
transformConstraints.push(new TransformConstraint(transformConstraintData, this));
|
||||
/** Caches information about bones and constraints. Must be called if bones, constraints, or weighted path attachments are
|
||||
* added or removed. */
|
||||
public function updateCache() : void {
|
||||
var updateCache : Vector.<Updatable> = this._updateCache;
|
||||
updateCache.length = 0;
|
||||
this._updateCacheReset.length = 0;
|
||||
|
||||
pathConstraints = new Vector.<PathConstraint>();
|
||||
for each (var pathConstraintData:PathConstraintData in data.pathConstraints)
|
||||
pathConstraints.push(new PathConstraint(pathConstraintData, this));
|
||||
var bones : Vector.<Bone> = this.bones;
|
||||
var i : Number = 0;
|
||||
var n : Number = 0;
|
||||
for (i = 0, n = bones.length; i < n; i++)
|
||||
bones[i]._sorted = false;
|
||||
|
||||
updateCache();
|
||||
}
|
||||
// IK first, lowest hierarchy depth first.
|
||||
var ikConstraints : Vector.<IkConstraint> = this.ikConstraints;
|
||||
var transformConstraints : Vector.<TransformConstraint> = this.transformConstraints;
|
||||
var pathConstraints : Vector.<PathConstraint> = this.pathConstraints;
|
||||
var ikCount : Number = ikConstraints.length, transformCount : Number = transformConstraints.length, pathCount : Number = pathConstraints.length;
|
||||
var constraintCount : Number = ikCount + transformCount + pathCount;
|
||||
|
||||
/** Caches information about bones and constraints. Must be called if bones, constraints, or weighted path attachments are
|
||||
* added or removed. */
|
||||
public function updateCache () : void {
|
||||
var updateCache:Vector.<Updatable> = this._updateCache;
|
||||
updateCache.length = 0;
|
||||
this._updateCacheReset.length = 0;
|
||||
|
||||
var bones:Vector.<Bone> = this.bones;
|
||||
var i:Number = 0;
|
||||
var n:Number = 0;
|
||||
for (i = 0, n = bones.length; i < n; i++)
|
||||
bones[i]._sorted = false;
|
||||
|
||||
// IK first, lowest hierarchy depth first.
|
||||
var ikConstraints:Vector.<IkConstraint> = this.ikConstraints;
|
||||
var transformConstraints:Vector.<TransformConstraint> = this.transformConstraints;
|
||||
var pathConstraints:Vector.<PathConstraint> = this.pathConstraints;
|
||||
var ikCount:Number = ikConstraints.length, transformCount:Number = transformConstraints.length, pathCount:Number = pathConstraints.length;
|
||||
var constraintCount:Number = ikCount + transformCount + pathCount;
|
||||
|
||||
outer:
|
||||
for (i = 0; i < constraintCount; i++) {
|
||||
var ii:Number = 0;
|
||||
for (ii = 0; ii < ikCount; ii++) {
|
||||
var ikConstraint:IkConstraint = ikConstraints[ii];
|
||||
if (ikConstraint.data.order == i) {
|
||||
sortIkConstraint(ikConstraint);
|
||||
continue outer;
|
||||
outer:
|
||||
for (i = 0; i < constraintCount; i++) {
|
||||
var ii : Number = 0;
|
||||
for (ii = 0; ii < ikCount; ii++) {
|
||||
var ikConstraint : IkConstraint = ikConstraints[ii];
|
||||
if (ikConstraint.data.order == i) {
|
||||
sortIkConstraint(ikConstraint);
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
for (ii = 0; ii < transformCount; ii++) {
|
||||
var transformConstraint : TransformConstraint = transformConstraints[ii];
|
||||
if (transformConstraint.data.order == i) {
|
||||
sortTransformConstraint(transformConstraint);
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
for (ii = 0; ii < pathCount; ii++) {
|
||||
var pathConstraint : PathConstraint = pathConstraints[ii];
|
||||
if (pathConstraint.data.order == i) {
|
||||
sortPathConstraint(pathConstraint);
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (ii = 0; ii < transformCount; ii++) {
|
||||
var transformConstraint:TransformConstraint = transformConstraints[ii];
|
||||
if (transformConstraint.data.order == i) {
|
||||
sortTransformConstraint(transformConstraint);
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
for (ii = 0; ii < pathCount; ii++) {
|
||||
var pathConstraint:PathConstraint = pathConstraints[ii];
|
||||
if (pathConstraint.data.order == i) {
|
||||
sortPathConstraint(pathConstraint);
|
||||
continue outer;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0, n = bones.length; i < n; i++)
|
||||
sortBone(bones[i]);
|
||||
}
|
||||
|
||||
private function sortIkConstraint (constraint:IkConstraint): void {
|
||||
var target:Bone = constraint.target;
|
||||
sortBone(target);
|
||||
|
||||
var constrained:Vector.<Bone> = constraint.bones;
|
||||
var parent:Bone = constrained[0];
|
||||
sortBone(parent);
|
||||
|
||||
if (constrained.length > 1) {
|
||||
var child:Bone = constrained[constrained.length - 1];
|
||||
if (!(_updateCache.indexOf(child) > -1)) _updateCacheReset.push(child);
|
||||
for (i = 0, n = bones.length; i < n; i++)
|
||||
sortBone(bones[i]);
|
||||
}
|
||||
|
||||
_updateCache.push(constraint);
|
||||
private function sortIkConstraint(constraint : IkConstraint) : void {
|
||||
var target : Bone = constraint.target;
|
||||
sortBone(target);
|
||||
|
||||
sortReset(parent.children);
|
||||
constrained[constrained.length - 1]._sorted = true;
|
||||
}
|
||||
var constrained : Vector.<Bone> = constraint.bones;
|
||||
var parent : Bone = constrained[0];
|
||||
sortBone(parent);
|
||||
|
||||
private function sortPathConstraint (constraint:PathConstraint): void {
|
||||
var slot:Slot = constraint.target;
|
||||
var slotIndex:Number = slot.data.index;
|
||||
var slotBone:Bone = slot.bone;
|
||||
if (skin != null) sortPathConstraintAttachment(skin, slotIndex, slotBone);
|
||||
if (data.defaultSkin != null && data.defaultSkin != skin)
|
||||
sortPathConstraintAttachment(data.defaultSkin, slotIndex, slotBone);
|
||||
var i:Number = 0;
|
||||
var n:Number = 0;
|
||||
for (i = 0, n = data.skins.length; i < n; i++)
|
||||
sortPathConstraintAttachment(data.skins[i], slotIndex, slotBone);
|
||||
|
||||
var attachment:Attachment = slot.attachment;
|
||||
if (attachment is PathAttachment) sortPathConstraintAttachment2(attachment, slotBone);
|
||||
|
||||
var constrained:Vector.<Bone> = constraint.bones;
|
||||
var boneCount:Number = constrained.length;
|
||||
for (i = 0; i < boneCount; i++)
|
||||
sortBone(constrained[i]);
|
||||
|
||||
_updateCache.push(constraint);
|
||||
|
||||
for (i = 0; i < boneCount; i++)
|
||||
sortReset(constrained[i].children);
|
||||
for (i = 0; i < boneCount; i++)
|
||||
constrained[i]._sorted = true;
|
||||
}
|
||||
|
||||
private function sortTransformConstraint (constraint:TransformConstraint): void {
|
||||
sortBone(constraint.target);
|
||||
|
||||
var constrained:Vector.<Bone> = constraint.bones;
|
||||
var boneCount:Number = constrained.length;
|
||||
var i:Number = 0;
|
||||
if (constraint.data.local) {
|
||||
for (i = 0; i < boneCount; i++) {
|
||||
var child:Bone = constrained[i];
|
||||
sortBone(child.parent);
|
||||
if (constrained.length > 1) {
|
||||
var child : Bone = constrained[constrained.length - 1];
|
||||
if (!(_updateCache.indexOf(child) > -1)) _updateCacheReset.push(child);
|
||||
}
|
||||
} else {
|
||||
|
||||
_updateCache.push(constraint);
|
||||
|
||||
sortReset(parent.children);
|
||||
constrained[constrained.length - 1]._sorted = true;
|
||||
}
|
||||
|
||||
private function sortPathConstraint(constraint : PathConstraint) : void {
|
||||
var slot : Slot = constraint.target;
|
||||
var slotIndex : Number = slot.data.index;
|
||||
var slotBone : Bone = slot.bone;
|
||||
if (skin != null) sortPathConstraintAttachment(skin, slotIndex, slotBone);
|
||||
if (data.defaultSkin != null && data.defaultSkin != skin)
|
||||
sortPathConstraintAttachment(data.defaultSkin, slotIndex, slotBone);
|
||||
var i : Number = 0;
|
||||
var n : Number = 0;
|
||||
for (i = 0, n = data.skins.length; i < n; i++)
|
||||
sortPathConstraintAttachment(data.skins[i], slotIndex, slotBone);
|
||||
|
||||
var attachment : Attachment = slot.attachment;
|
||||
if (attachment is PathAttachment) sortPathConstraintAttachment2(attachment, slotBone);
|
||||
|
||||
var constrained : Vector.<Bone> = constraint.bones;
|
||||
var boneCount : Number = constrained.length;
|
||||
for (i = 0; i < boneCount; i++)
|
||||
sortBone(constrained[i]);
|
||||
|
||||
_updateCache.push(constraint);
|
||||
|
||||
for (i = 0; i < boneCount; i++)
|
||||
sortReset(constrained[i].children);
|
||||
for (i = 0; i < boneCount; i++)
|
||||
constrained[i]._sorted = true;
|
||||
}
|
||||
|
||||
_updateCache.push(constraint);
|
||||
private function sortTransformConstraint(constraint : TransformConstraint) : void {
|
||||
sortBone(constraint.target);
|
||||
|
||||
for (i = 0; i < boneCount; i++)
|
||||
sortReset(constrained[i].children);
|
||||
for (i = 0; i < boneCount; i++)
|
||||
constrained[i]._sorted = true;
|
||||
}
|
||||
|
||||
private function sortPathConstraintAttachment (skin:Skin, slotIndex:int, slotBone:Bone) : void {
|
||||
var dict:Dictionary = skin.attachments[slotIndex];
|
||||
if (!dict) return;
|
||||
|
||||
for each (var value:Attachment in dict) {
|
||||
sortPathConstraintAttachment2(value, slotBone);
|
||||
}
|
||||
}
|
||||
|
||||
private function sortPathConstraintAttachment2 (attachment:Attachment, slotBone:Bone) : void {
|
||||
var pathAttachment:PathAttachment = attachment as PathAttachment;
|
||||
if (!pathAttachment) return;
|
||||
var pathBones:Vector.<int> = pathAttachment.bones;
|
||||
if (pathBones == null)
|
||||
sortBone(slotBone);
|
||||
else {
|
||||
var bones:Vector.<Bone> = this.bones;
|
||||
var i:int = 0;
|
||||
while (i < pathBones.length) {
|
||||
var boneCount:int = pathBones[i++];
|
||||
for (var n:int = i + boneCount; i < n; i++) {
|
||||
sortBone(bones[pathBones[i]]);
|
||||
var constrained : Vector.<Bone> = constraint.bones;
|
||||
var boneCount : Number = constrained.length;
|
||||
var i : Number = 0;
|
||||
if (constraint.data.local) {
|
||||
for (i = 0; i < boneCount; i++) {
|
||||
var child : Bone = constrained[i];
|
||||
sortBone(child.parent);
|
||||
if (!(_updateCache.indexOf(child) > -1)) _updateCacheReset.push(child);
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < boneCount; i++)
|
||||
sortBone(constrained[i]);
|
||||
}
|
||||
|
||||
_updateCache.push(constraint);
|
||||
|
||||
for (i = 0; i < boneCount; i++)
|
||||
sortReset(constrained[i].children);
|
||||
for (i = 0; i < boneCount; i++)
|
||||
constrained[i]._sorted = true;
|
||||
}
|
||||
|
||||
private function sortPathConstraintAttachment(skin : Skin, slotIndex : int, slotBone : Bone) : void {
|
||||
var dict : Dictionary = skin.attachments[slotIndex];
|
||||
if (!dict) return;
|
||||
|
||||
for each (var value : Attachment in dict) {
|
||||
sortPathConstraintAttachment2(value, slotBone);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function sortBone (bone:Bone) : void {
|
||||
if (bone._sorted) return;
|
||||
var parent:Bone = bone.parent;
|
||||
if (parent != null) sortBone(parent);
|
||||
bone._sorted = true;
|
||||
_updateCache.push(bone);
|
||||
}
|
||||
|
||||
private function sortReset (bones:Vector.<Bone>) : void {
|
||||
for (var i:int = 0, n:int = bones.length; i < n; i++) {
|
||||
var bone:Bone = bones[i];
|
||||
if (bone._sorted) sortReset(bone.children);
|
||||
bone._sorted = false;
|
||||
}
|
||||
}
|
||||
|
||||
/** Updates the world transform for each bone and applies constraints. */
|
||||
public function updateWorldTransform () : void {
|
||||
var updateCacheReset:Vector.<Bone> = this._updateCacheReset;
|
||||
for each (var bone:Bone in updateCacheReset) {
|
||||
bone.ax = bone.x;
|
||||
bone.ay = bone.y;
|
||||
bone.arotation = bone.rotation;
|
||||
bone.ascaleX = bone.scaleX;
|
||||
bone.ascaleY = bone.scaleY;
|
||||
bone.ashearX = bone.shearX;
|
||||
bone.ashearY = bone.shearY;
|
||||
bone.appliedValid = true;
|
||||
}
|
||||
for each (var updatable:Updatable in _updateCache)
|
||||
updatable.update();
|
||||
}
|
||||
|
||||
/** Sets the bones, constraints, and slots to their setup pose values. */
|
||||
public function setToSetupPose () : void {
|
||||
setBonesToSetupPose();
|
||||
setSlotsToSetupPose();
|
||||
}
|
||||
|
||||
/** Sets the bones and constraints to their setup pose values. */
|
||||
public function setBonesToSetupPose () : void {
|
||||
for each (var bone:Bone in bones)
|
||||
bone.setToSetupPose();
|
||||
|
||||
for each (var ikConstraint:IkConstraint in ikConstraints) {
|
||||
ikConstraint.bendDirection = ikConstraint._data.bendDirection;
|
||||
ikConstraint.mix = ikConstraint._data.mix;
|
||||
}
|
||||
|
||||
for each (var transformConstraint:TransformConstraint in transformConstraints) {
|
||||
transformConstraint.rotateMix = transformConstraint._data.rotateMix;
|
||||
transformConstraint.translateMix = transformConstraint._data.translateMix;
|
||||
transformConstraint.scaleMix = transformConstraint._data.scaleMix;
|
||||
transformConstraint.shearMix = transformConstraint._data.shearMix;
|
||||
}
|
||||
|
||||
for each (var pathConstraint:PathConstraint in pathConstraints) {
|
||||
pathConstraint.position = pathConstraint._data.position;
|
||||
pathConstraint.spacing = pathConstraint._data.spacing;
|
||||
pathConstraint.rotateMix = pathConstraint._data.rotateMix;
|
||||
pathConstraint.translateMix = pathConstraint._data.translateMix;
|
||||
}
|
||||
}
|
||||
|
||||
public function setSlotsToSetupPose () : void {
|
||||
var i:int = 0;
|
||||
for each (var slot:Slot in slots) {
|
||||
drawOrder[i++] = slot;
|
||||
slot.setToSetupPose();
|
||||
}
|
||||
}
|
||||
|
||||
public function get data () : SkeletonData {
|
||||
return _data;
|
||||
}
|
||||
|
||||
public function get getUpdateCache () : Vector.<Updatable> {
|
||||
return _updateCache;
|
||||
}
|
||||
|
||||
public function get rootBone () : Bone {
|
||||
if (bones.length == 0) return null;
|
||||
return bones[0];
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
public function findBone (boneName:String) : Bone {
|
||||
if (boneName == null)
|
||||
throw new ArgumentError("boneName cannot be null.");
|
||||
for each (var bone:Bone in bones)
|
||||
if (bone._data._name == boneName) return bone;
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return -1 if the bone was not found. */
|
||||
public function findBoneIndex (boneName:String) : int {
|
||||
if (boneName == null)
|
||||
throw new ArgumentError("boneName cannot be null.");
|
||||
var i:int = 0;
|
||||
for each (var bone:Bone in bones) {
|
||||
if (bone._data._name == boneName) return i;
|
||||
i++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
public function findSlot (slotName:String) : Slot {
|
||||
if (slotName == null)
|
||||
throw new ArgumentError("slotName cannot be null.");
|
||||
for each (var slot:Slot in slots)
|
||||
if (slot._data._name == slotName) return slot;
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return -1 if the bone was not found. */
|
||||
public function findSlotIndex (slotName:String) : int {
|
||||
if (slotName == null)
|
||||
throw new ArgumentError("slotName cannot be null.");
|
||||
var i:int = 0;
|
||||
for each (var slot:Slot in slots) {
|
||||
if (slot._data._name == slotName) return i;
|
||||
i++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public function get skin () : Skin {
|
||||
return _skin;
|
||||
}
|
||||
|
||||
public function set skinName (skinName:String) : void {
|
||||
var skin:Skin = data.findSkin(skinName);
|
||||
if (skin == null) throw new ArgumentError("Skin not found: " + skinName);
|
||||
this.skin = skin;
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
public function get skinName () : String {
|
||||
return _skin == null ? null : _skin._name;
|
||||
}
|
||||
|
||||
/** Sets the skin used to look up attachments before looking in the {@link SkeletonData#getDefaultSkin() default skin}.
|
||||
* Attachments from the new skin are attached if the corresponding attachment from the old skin was attached. If there was
|
||||
* no old skin, each slot's setup mode attachment is attached from the new skin.
|
||||
* @param newSkin May be null. */
|
||||
public function set skin (newSkin:Skin) : void {
|
||||
if (newSkin) {
|
||||
if (skin)
|
||||
newSkin.attachAll(this, skin);
|
||||
private function sortPathConstraintAttachment2(attachment : Attachment, slotBone : Bone) : void {
|
||||
var pathAttachment : PathAttachment = attachment as PathAttachment;
|
||||
if (!pathAttachment) return;
|
||||
var pathBones : Vector.<int> = pathAttachment.bones;
|
||||
if (pathBones == null)
|
||||
sortBone(slotBone);
|
||||
else {
|
||||
var i:int = 0;
|
||||
for each (var slot:Slot in slots) {
|
||||
var name:String = slot._data.attachmentName;
|
||||
if (name) {
|
||||
var attachment:Attachment = newSkin.getAttachment(i, name);
|
||||
if (attachment) slot.attachment = attachment;
|
||||
var bones : Vector.<Bone> = this.bones;
|
||||
var i : int = 0;
|
||||
while (i < pathBones.length) {
|
||||
var boneCount : int = pathBones[i++];
|
||||
for (var n : int = i + boneCount; i < n; i++) {
|
||||
sortBone(bones[pathBones[i]]);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
_skin = newSkin;
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
public function getAttachmentForSlotName (slotName:String, attachmentName:String) : Attachment {
|
||||
return getAttachmentForSlotIndex(data.findSlotIndex(slotName), attachmentName);
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
public function getAttachmentForSlotIndex (slotIndex:int, attachmentName:String) : Attachment {
|
||||
if (attachmentName == null) throw new ArgumentError("attachmentName cannot be null.");
|
||||
if (skin != null) {
|
||||
var attachment:Attachment = skin.getAttachment(slotIndex, attachmentName);
|
||||
if (attachment != null) return attachment;
|
||||
private function sortBone(bone : Bone) : void {
|
||||
if (bone._sorted) return;
|
||||
var parent : Bone = bone.parent;
|
||||
if (parent != null) sortBone(parent);
|
||||
bone._sorted = true;
|
||||
_updateCache.push(bone);
|
||||
}
|
||||
if (data.defaultSkin != null) return data.defaultSkin.getAttachment(slotIndex, attachmentName);
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @param attachmentName May be null. */
|
||||
public function setAttachment (slotName:String, attachmentName:String) : void {
|
||||
if (slotName == null) throw new ArgumentError("slotName cannot be null.");
|
||||
var i:int = 0;
|
||||
for each (var slot:Slot in slots) {
|
||||
if (slot._data._name == slotName) {
|
||||
var attachment:Attachment = null;
|
||||
if (attachmentName != null) {
|
||||
attachment = getAttachmentForSlotIndex(i, attachmentName);
|
||||
if (attachment == null)
|
||||
throw new ArgumentError("Attachment not found: " + attachmentName + ", for slot: " + slotName);
|
||||
}
|
||||
slot.attachment = attachment;
|
||||
return;
|
||||
private function sortReset(bones : Vector.<Bone>) : void {
|
||||
for (var i : int = 0, n : int = bones.length; i < n; i++) {
|
||||
var bone : Bone = bones[i];
|
||||
if (bone._sorted) sortReset(bone.children);
|
||||
bone._sorted = false;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
throw new ArgumentError("Slot not found: " + slotName);
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
public function findIkConstraint (constraintName:String) : IkConstraint {
|
||||
if (constraintName == null) throw new ArgumentError("constraintName cannot be null.");
|
||||
for each (var ikConstraint:IkConstraint in ikConstraints)
|
||||
if (ikConstraint._data._name == constraintName) return ikConstraint;
|
||||
return null;
|
||||
}
|
||||
/** Updates the world transform for each bone and applies constraints. */
|
||||
public function updateWorldTransform() : void {
|
||||
var updateCacheReset : Vector.<Bone> = this._updateCacheReset;
|
||||
for each (var bone : Bone in updateCacheReset) {
|
||||
bone.ax = bone.x;
|
||||
bone.ay = bone.y;
|
||||
bone.arotation = bone.rotation;
|
||||
bone.ascaleX = bone.scaleX;
|
||||
bone.ascaleY = bone.scaleY;
|
||||
bone.ashearX = bone.shearX;
|
||||
bone.ashearY = bone.shearY;
|
||||
bone.appliedValid = true;
|
||||
}
|
||||
for each (var updatable : Updatable in _updateCache)
|
||||
updatable.update();
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
public function findTransformConstraint (constraintName:String) : TransformConstraint {
|
||||
if (constraintName == null) throw new ArgumentError("constraintName cannot be null.");
|
||||
for each (var transformConstraint:TransformConstraint in transformConstraints)
|
||||
if (transformConstraint._data._name == constraintName) return transformConstraint;
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
public function findPathConstraint (constraintName:String) : PathConstraint {
|
||||
if (constraintName == null) throw new ArgumentError("constraintName cannot be null.");
|
||||
for each (var pathConstraint:PathConstraint in pathConstraints)
|
||||
if (pathConstraint._data._name == constraintName) return pathConstraint;
|
||||
return null;
|
||||
}
|
||||
/** Sets the bones, constraints, and slots to their setup pose values. */
|
||||
public function setToSetupPose() : void {
|
||||
setBonesToSetupPose();
|
||||
setSlotsToSetupPose();
|
||||
}
|
||||
|
||||
public function update (delta:Number) : void {
|
||||
time += delta;
|
||||
}
|
||||
/** Sets the bones and constraints to their setup pose values. */
|
||||
public function setBonesToSetupPose() : void {
|
||||
for each (var bone : Bone in bones)
|
||||
bone.setToSetupPose();
|
||||
|
||||
public function toString () : String {
|
||||
return _data.name != null ? _data.name : super.toString();
|
||||
}
|
||||
|
||||
public function getBounds (offset: Vector.<Number>, size: Vector.<Number>, temp: Vector.<Number>) : void {
|
||||
for each (var ikConstraint : IkConstraint in ikConstraints) {
|
||||
ikConstraint.bendDirection = ikConstraint._data.bendDirection;
|
||||
ikConstraint.mix = ikConstraint._data.mix;
|
||||
}
|
||||
|
||||
for each (var transformConstraint : TransformConstraint in transformConstraints) {
|
||||
transformConstraint.rotateMix = transformConstraint._data.rotateMix;
|
||||
transformConstraint.translateMix = transformConstraint._data.translateMix;
|
||||
transformConstraint.scaleMix = transformConstraint._data.scaleMix;
|
||||
transformConstraint.shearMix = transformConstraint._data.shearMix;
|
||||
}
|
||||
|
||||
for each (var pathConstraint : PathConstraint in pathConstraints) {
|
||||
pathConstraint.position = pathConstraint._data.position;
|
||||
pathConstraint.spacing = pathConstraint._data.spacing;
|
||||
pathConstraint.rotateMix = pathConstraint._data.rotateMix;
|
||||
pathConstraint.translateMix = pathConstraint._data.translateMix;
|
||||
}
|
||||
}
|
||||
|
||||
public function setSlotsToSetupPose() : void {
|
||||
var i : int = 0;
|
||||
for each (var slot : Slot in slots) {
|
||||
drawOrder[i++] = slot;
|
||||
slot.setToSetupPose();
|
||||
}
|
||||
}
|
||||
|
||||
public function get data() : SkeletonData {
|
||||
return _data;
|
||||
}
|
||||
|
||||
public function get getUpdateCache() : Vector.<Updatable> {
|
||||
return _updateCache;
|
||||
}
|
||||
|
||||
public function get rootBone() : Bone {
|
||||
if (bones.length == 0) return null;
|
||||
return bones[0];
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
public function findBone(boneName : String) : Bone {
|
||||
if (boneName == null)
|
||||
throw new ArgumentError("boneName cannot be null.");
|
||||
for each (var bone : Bone in bones)
|
||||
if (bone._data._name == boneName) return bone;
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return -1 if the bone was not found. */
|
||||
public function findBoneIndex(boneName : String) : int {
|
||||
if (boneName == null)
|
||||
throw new ArgumentError("boneName cannot be null.");
|
||||
var i : int = 0;
|
||||
for each (var bone : Bone in bones) {
|
||||
if (bone._data._name == boneName) return i;
|
||||
i++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
public function findSlot(slotName : String) : Slot {
|
||||
if (slotName == null)
|
||||
throw new ArgumentError("slotName cannot be null.");
|
||||
for each (var slot : Slot in slots)
|
||||
if (slot._data._name == slotName) return slot;
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return -1 if the bone was not found. */
|
||||
public function findSlotIndex(slotName : String) : int {
|
||||
if (slotName == null)
|
||||
throw new ArgumentError("slotName cannot be null.");
|
||||
var i : int = 0;
|
||||
for each (var slot : Slot in slots) {
|
||||
if (slot._data._name == slotName) return i;
|
||||
i++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
public function get skin() : Skin {
|
||||
return _skin;
|
||||
}
|
||||
|
||||
public function set skinName(skinName : String) : void {
|
||||
var skin : Skin = data.findSkin(skinName);
|
||||
if (skin == null) throw new ArgumentError("Skin not found: " + skinName);
|
||||
this.skin = skin;
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
public function get skinName() : String {
|
||||
return _skin == null ? null : _skin._name;
|
||||
}
|
||||
|
||||
/** Sets the skin used to look up attachments before looking in the {@link SkeletonData#getDefaultSkin() default skin}.
|
||||
* Attachments from the new skin are attached if the corresponding attachment from the old skin was attached. If there was
|
||||
* no old skin, each slot's setup mode attachment is attached from the new skin.
|
||||
* @param newSkin May be null. */
|
||||
public function set skin(newSkin : Skin) : void {
|
||||
if (newSkin) {
|
||||
if (skin)
|
||||
newSkin.attachAll(this, skin);
|
||||
else {
|
||||
var i : int = 0;
|
||||
for each (var slot : Slot in slots) {
|
||||
var name : String = slot._data.attachmentName;
|
||||
if (name) {
|
||||
var attachment : Attachment = newSkin.getAttachment(i, name);
|
||||
if (attachment) slot.attachment = attachment;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
_skin = newSkin;
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
public function getAttachmentForSlotName(slotName : String, attachmentName : String) : Attachment {
|
||||
return getAttachmentForSlotIndex(data.findSlotIndex(slotName), attachmentName);
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
public function getAttachmentForSlotIndex(slotIndex : int, attachmentName : String) : Attachment {
|
||||
if (attachmentName == null) throw new ArgumentError("attachmentName cannot be null.");
|
||||
if (skin != null) {
|
||||
var attachment : Attachment = skin.getAttachment(slotIndex, attachmentName);
|
||||
if (attachment != null) return attachment;
|
||||
}
|
||||
if (data.defaultSkin != null) return data.defaultSkin.getAttachment(slotIndex, attachmentName);
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @param attachmentName May be null. */
|
||||
public function setAttachment(slotName : String, attachmentName : String) : void {
|
||||
if (slotName == null) throw new ArgumentError("slotName cannot be null.");
|
||||
var i : int = 0;
|
||||
for each (var slot : Slot in slots) {
|
||||
if (slot._data._name == slotName) {
|
||||
var attachment : Attachment = null;
|
||||
if (attachmentName != null) {
|
||||
attachment = getAttachmentForSlotIndex(i, attachmentName);
|
||||
if (attachment == null)
|
||||
throw new ArgumentError("Attachment not found: " + attachmentName + ", for slot: " + slotName);
|
||||
}
|
||||
slot.attachment = attachment;
|
||||
return;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
throw new ArgumentError("Slot not found: " + slotName);
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
public function findIkConstraint(constraintName : String) : IkConstraint {
|
||||
if (constraintName == null) throw new ArgumentError("constraintName cannot be null.");
|
||||
for each (var ikConstraint : IkConstraint in ikConstraints)
|
||||
if (ikConstraint._data._name == constraintName) return ikConstraint;
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
public function findTransformConstraint(constraintName : String) : TransformConstraint {
|
||||
if (constraintName == null) throw new ArgumentError("constraintName cannot be null.");
|
||||
for each (var transformConstraint : TransformConstraint in transformConstraints)
|
||||
if (transformConstraint._data._name == constraintName) return transformConstraint;
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
public function findPathConstraint(constraintName : String) : PathConstraint {
|
||||
if (constraintName == null) throw new ArgumentError("constraintName cannot be null.");
|
||||
for each (var pathConstraint : PathConstraint in pathConstraints)
|
||||
if (pathConstraint._data._name == constraintName) return pathConstraint;
|
||||
return null;
|
||||
}
|
||||
|
||||
public function update(delta : Number) : void {
|
||||
time += delta;
|
||||
}
|
||||
|
||||
public function toString() : String {
|
||||
return _data.name != null ? _data.name : super.toString();
|
||||
}
|
||||
|
||||
public function getBounds(offset : Vector.<Number>, size : Vector.<Number>, temp : Vector.<Number>) : void {
|
||||
if (offset == null) throw new ArgumentError("offset cannot be null.");
|
||||
if (size == null) throw new ArgumentError("size cannot be null.");
|
||||
var drawOrder:Vector.<Slot> = this.drawOrder;
|
||||
var minX:Number = Number.POSITIVE_INFINITY, minY:Number = Number.POSITIVE_INFINITY, maxX:Number = Number.NEGATIVE_INFINITY, maxY:Number = Number.NEGATIVE_INFINITY;
|
||||
for (var i:int = 0, n:int = drawOrder.length; i < n; i++) {
|
||||
var slot:Slot = drawOrder[i];
|
||||
var verticesLength:int = 0;
|
||||
var vertices: Vector.<Number> = null;
|
||||
var attachment:Attachment = slot.attachment;
|
||||
var drawOrder : Vector.<Slot> = this.drawOrder;
|
||||
var minX : Number = Number.POSITIVE_INFINITY, minY : Number = Number.POSITIVE_INFINITY, maxX : Number = Number.NEGATIVE_INFINITY, maxY : Number = Number.NEGATIVE_INFINITY;
|
||||
for (var i : int = 0, n : int = drawOrder.length; i < n; i++) {
|
||||
var slot : Slot = drawOrder[i];
|
||||
var verticesLength : int = 0;
|
||||
var vertices : Vector.<Number> = null;
|
||||
var attachment : Attachment = slot.attachment;
|
||||
if (attachment is RegionAttachment) {
|
||||
verticesLength = 8;
|
||||
temp.length = verticesLength;
|
||||
vertices = temp;
|
||||
(attachment as RegionAttachment).computeWorldVertices(slot.bone, vertices, 0, 2);
|
||||
} else if (attachment is MeshAttachment) {
|
||||
var mesh:MeshAttachment = attachment as MeshAttachment;
|
||||
} else if (attachment is MeshAttachment) {
|
||||
var mesh : MeshAttachment = attachment as MeshAttachment;
|
||||
verticesLength = mesh.worldVerticesLength;
|
||||
temp.length = verticesLength;
|
||||
vertices = temp;
|
||||
mesh.computeWorldVertices(slot, 0, verticesLength, vertices, 0, 2);
|
||||
}
|
||||
if (vertices != null) {
|
||||
for (var ii:int = 0, nn:int = vertices.length; ii < nn; ii += 8) {
|
||||
var x:Number = vertices[ii], y:Number = vertices[ii + 1];
|
||||
for (var ii : int = 0, nn : int = vertices.length; ii < nn; ii += 8) {
|
||||
var x : Number = vertices[ii], y : Number = vertices[ii + 1];
|
||||
minX = Math.min(minX, x);
|
||||
minY = Math.min(minY, y);
|
||||
maxX = Math.max(maxX, x);
|
||||
@ -512,6 +514,5 @@ public class Skeleton {
|
||||
size[0] = maxX - minX;
|
||||
size[1] = maxY - minY;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -29,131 +29,128 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
import spine.attachments.BoundingBoxAttachment;
|
||||
import spine.attachments.BoundingBoxAttachment;
|
||||
|
||||
public class SkeletonBounds {
|
||||
private var polygonPool:Vector.<Polygon> = new Vector.<Polygon>();
|
||||
public class SkeletonBounds {
|
||||
private var polygonPool : Vector.<Polygon> = new Vector.<Polygon>();
|
||||
public var boundingBoxes : Vector.<BoundingBoxAttachment> = new Vector.<BoundingBoxAttachment>();
|
||||
public var polygons : Vector.<Polygon> = new Vector.<Polygon>();
|
||||
public var minX : Number, minY : Number, maxX : Number, maxY : Number;
|
||||
|
||||
public var boundingBoxes:Vector.<BoundingBoxAttachment> = new Vector.<BoundingBoxAttachment>();
|
||||
public var polygons:Vector.<Polygon> = new Vector.<Polygon>();
|
||||
public var minX:Number, minY:Number, maxX:Number, maxY:Number;
|
||||
|
||||
public function SkeletonBounds () {
|
||||
}
|
||||
|
||||
public function update (skeleton:Skeleton, updateAabb:Boolean) : void {
|
||||
var slots:Vector.<Slot> = skeleton.slots;
|
||||
var slotCount:int = slots.length;
|
||||
|
||||
boundingBoxes.length = 0;
|
||||
for each (var polygon:Polygon in polygons)
|
||||
polygonPool[polygonPool.length] = polygon;
|
||||
polygons.length = 0;
|
||||
|
||||
for (var i:int = 0; i < slotCount; i++) {
|
||||
var slot:Slot = slots[i];
|
||||
var boundingBox:BoundingBoxAttachment = slot.attachment as BoundingBoxAttachment;
|
||||
if (boundingBox == null) continue;
|
||||
boundingBoxes[boundingBoxes.length] = boundingBox;
|
||||
|
||||
var poolCount:int = polygonPool.length;
|
||||
if (poolCount > 0) {
|
||||
polygon = polygonPool[poolCount - 1];
|
||||
polygonPool.splice(poolCount - 1, 1);
|
||||
} else
|
||||
polygon = new Polygon();
|
||||
polygons[polygons.length] = polygon;
|
||||
|
||||
polygon.vertices.length = boundingBox.worldVerticesLength;
|
||||
boundingBox.computeWorldVertices(slot, 0, boundingBox.worldVerticesLength, polygon.vertices, 0, 2);
|
||||
public function SkeletonBounds() {
|
||||
}
|
||||
|
||||
if (updateAabb)
|
||||
aabbCompute();
|
||||
else {
|
||||
minX = Number.MIN_VALUE;
|
||||
minY = Number.MIN_VALUE;
|
||||
maxX = Number.MAX_VALUE;
|
||||
maxY = Number.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
public function update(skeleton : Skeleton, updateAabb : Boolean) : void {
|
||||
var slots : Vector.<Slot> = skeleton.slots;
|
||||
var slotCount : int = slots.length;
|
||||
|
||||
private function aabbCompute () : void {
|
||||
var minX:Number = Number.MAX_VALUE, minY:Number = Number.MAX_VALUE;
|
||||
var maxX:Number = -Number.MAX_VALUE, maxY:Number = -Number.MAX_VALUE;
|
||||
for (var i:int = 0, n:int = polygons.length; i < n; i++) {
|
||||
var polygon:Polygon = polygons[i];
|
||||
var vertices:Vector.<Number> = polygon.vertices;
|
||||
for (var ii:int = 0, nn:int = vertices.length; ii < nn; ii += 2) {
|
||||
var x:Number = vertices[ii];
|
||||
var y:Number = vertices[ii + 1];
|
||||
minX = Math.min(minX, x);
|
||||
minY = Math.min(minY, y);
|
||||
maxX = Math.max(maxX, x);
|
||||
maxY = Math.max(maxY, y);
|
||||
boundingBoxes.length = 0;
|
||||
for each (var polygon : Polygon in polygons)
|
||||
polygonPool[polygonPool.length] = polygon;
|
||||
polygons.length = 0;
|
||||
|
||||
for (var i : int = 0; i < slotCount; i++) {
|
||||
var slot : Slot = slots[i];
|
||||
var boundingBox : BoundingBoxAttachment = slot.attachment as BoundingBoxAttachment;
|
||||
if (boundingBox == null) continue;
|
||||
boundingBoxes[boundingBoxes.length] = boundingBox;
|
||||
|
||||
var poolCount : int = polygonPool.length;
|
||||
if (poolCount > 0) {
|
||||
polygon = polygonPool[poolCount - 1];
|
||||
polygonPool.splice(poolCount - 1, 1);
|
||||
} else
|
||||
polygon = new Polygon();
|
||||
polygons[polygons.length] = polygon;
|
||||
|
||||
polygon.vertices.length = boundingBox.worldVerticesLength;
|
||||
boundingBox.computeWorldVertices(slot, 0, boundingBox.worldVerticesLength, polygon.vertices, 0, 2);
|
||||
}
|
||||
|
||||
if (updateAabb)
|
||||
aabbCompute();
|
||||
else {
|
||||
minX = Number.MIN_VALUE;
|
||||
minY = Number.MIN_VALUE;
|
||||
maxX = Number.MAX_VALUE;
|
||||
maxY = Number.MAX_VALUE;
|
||||
}
|
||||
}
|
||||
this.minX = minX;
|
||||
this.minY = minY;
|
||||
this.maxX = maxX;
|
||||
this.maxY = maxY;
|
||||
}
|
||||
|
||||
|
||||
/** Returns true if the axis aligned bounding box contains the point. */
|
||||
public function aabbContainsPoint (x:Number, y:Number) : Boolean {
|
||||
return x >= minX && x <= maxX && y >= minY && y <= maxY;
|
||||
}
|
||||
|
||||
/** Returns true if the axis aligned bounding box intersects the line segment. */
|
||||
public function aabbIntersectsSegment (x1:Number, y1:Number, x2:Number, y2:Number) : Boolean {
|
||||
if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY))
|
||||
|
||||
private function aabbCompute() : void {
|
||||
var minX : Number = Number.MAX_VALUE, minY : Number = Number.MAX_VALUE;
|
||||
var maxX : Number = -Number.MAX_VALUE, maxY : Number = -Number.MAX_VALUE;
|
||||
for (var i : int = 0, n : int = polygons.length; i < n; i++) {
|
||||
var polygon : Polygon = polygons[i];
|
||||
var vertices : Vector.<Number> = polygon.vertices;
|
||||
for (var ii : int = 0, nn : int = vertices.length; ii < nn; ii += 2) {
|
||||
var x : Number = vertices[ii];
|
||||
var y : Number = vertices[ii + 1];
|
||||
minX = Math.min(minX, x);
|
||||
minY = Math.min(minY, y);
|
||||
maxX = Math.max(maxX, x);
|
||||
maxY = Math.max(maxY, y);
|
||||
}
|
||||
}
|
||||
this.minX = minX;
|
||||
this.minY = minY;
|
||||
this.maxX = maxX;
|
||||
this.maxY = maxY;
|
||||
}
|
||||
|
||||
/** Returns true if the axis aligned bounding box contains the point. */
|
||||
public function aabbContainsPoint(x : Number, y : Number) : Boolean {
|
||||
return x >= minX && x <= maxX && y >= minY && y <= maxY;
|
||||
}
|
||||
|
||||
/** Returns true if the axis aligned bounding box intersects the line segment. */
|
||||
public function aabbIntersectsSegment(x1 : Number, y1 : Number, x2 : Number, y2 : Number) : Boolean {
|
||||
if ((x1 <= minX && x2 <= minX) || (y1 <= minY && y2 <= minY) || (x1 >= maxX && x2 >= maxX) || (y1 >= maxY && y2 >= maxY))
|
||||
return false;
|
||||
var m : Number = (y2 - y1) / (x2 - x1);
|
||||
var y : Number = m * (minX - x1) + y1;
|
||||
if (y > minY && y < maxY) return true;
|
||||
y = m * (maxX - x1) + y1;
|
||||
if (y > minY && y < maxY) return true;
|
||||
var x : Number = (minY - y1) / m + x1;
|
||||
if (x > minX && x < maxX) return true;
|
||||
x = (maxY - y1) / m + x1;
|
||||
if (x > minX && x < maxX) return true;
|
||||
return false;
|
||||
var m:Number = (y2 - y1) / (x2 - x1);
|
||||
var y:Number = m * (minX - x1) + y1;
|
||||
if (y > minY && y < maxY) return true;
|
||||
y = m * (maxX - x1) + y1;
|
||||
if (y > minY && y < maxY) return true;
|
||||
var x:Number = (minY - y1) / m + x1;
|
||||
if (x > minX && x < maxX) return true;
|
||||
x = (maxY - y1) / m + x1;
|
||||
if (x > minX && x < maxX) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/** Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. */
|
||||
public function aabbIntersectsSkeleton (bounds:SkeletonBounds) : Boolean {
|
||||
return minX < bounds.maxX && maxX > bounds.minX && minY < bounds.maxY && maxY > bounds.minY;
|
||||
}
|
||||
|
||||
/** Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more
|
||||
* efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true. */
|
||||
public function containsPoint (x:Number, y:Number) : BoundingBoxAttachment {
|
||||
for (var i:int = 0, n:int = polygons.length; i < n; i++)
|
||||
if (polygons[i].containsPoint(x, y)) return boundingBoxes[i];
|
||||
return null;
|
||||
}
|
||||
|
||||
/** Returns the first bounding box attachment that contains the line segment, or null. When doing many checks, it is usually
|
||||
* more efficient to only call this method if {@link #aabbIntersectsSegment(float, float, float, float)} returns true. */
|
||||
public function intersectsSegment (x1:Number, y1:Number, x2:Number, y2:Number) : BoundingBoxAttachment {
|
||||
for (var i:int = 0, n:int = polygons.length; i < n; i++)
|
||||
if (polygons[i].intersectsSegment(x1, y1, x2, y2)) return boundingBoxes[i];
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public function getPolygon (attachment:BoundingBoxAttachment) : Polygon {
|
||||
var index:int = boundingBoxes.indexOf(attachment);
|
||||
return index == -1 ? null : polygons[index];
|
||||
}
|
||||
/** Returns true if the axis aligned bounding box intersects the axis aligned bounding box of the specified bounds. */
|
||||
public function aabbIntersectsSkeleton(bounds : SkeletonBounds) : Boolean {
|
||||
return minX < bounds.maxX && maxX > bounds.minX && minY < bounds.maxY && maxY > bounds.minY;
|
||||
}
|
||||
|
||||
public function get width () : Number {
|
||||
return maxX - minX;
|
||||
}
|
||||
|
||||
public function get height () : Number {
|
||||
return maxY - minY;
|
||||
}
|
||||
}
|
||||
/** Returns the first bounding box attachment that contains the point, or null. When doing many checks, it is usually more
|
||||
* efficient to only call this method if {@link #aabbContainsPoint(float, float)} returns true. */
|
||||
public function containsPoint(x : Number, y : Number) : BoundingBoxAttachment {
|
||||
for (var i : int = 0, n : int = polygons.length; i < n; i++)
|
||||
if (polygons[i].containsPoint(x, y)) return boundingBoxes[i];
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
/** Returns the first bounding box attachment that contains the line segment, or null. When doing many checks, it is usually
|
||||
* more efficient to only call this method if {@link #aabbIntersectsSegment(float, float, float, float)} returns true. */
|
||||
public function intersectsSegment(x1 : Number, y1 : Number, x2 : Number, y2 : Number) : BoundingBoxAttachment {
|
||||
for (var i : int = 0, n : int = polygons.length; i < n; i++)
|
||||
if (polygons[i].intersectsSegment(x1, y1, x2, y2)) return boundingBoxes[i];
|
||||
return null;
|
||||
}
|
||||
|
||||
public function getPolygon(attachment : BoundingBoxAttachment) : Polygon {
|
||||
var index : int = boundingBoxes.indexOf(attachment);
|
||||
return index == -1 ? null : polygons[index];
|
||||
}
|
||||
|
||||
public function get width() : Number {
|
||||
return maxX - minX;
|
||||
}
|
||||
|
||||
public function get height() : Number {
|
||||
return maxY - minY;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -29,155 +29,144 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
import spine.animation.Animation;
|
||||
import spine.animation.Animation;
|
||||
|
||||
public class SkeletonData {
|
||||
/** May be null. */
|
||||
public var name:String;
|
||||
public var bones:Vector.<BoneData> = new Vector.<BoneData>(); // Ordered parents first.
|
||||
public var slots:Vector.<SlotData> = new Vector.<SlotData>(); // Setup pose draw order.
|
||||
public var skins:Vector.<Skin> = new Vector.<Skin>();
|
||||
public var defaultSkin:Skin;
|
||||
public var events:Vector.<EventData> = new Vector.<EventData>();
|
||||
public var animations:Vector.<Animation> = new Vector.<Animation>();
|
||||
public var ikConstraints:Vector.<IkConstraintData> = new Vector.<IkConstraintData>();
|
||||
public var transformConstraints:Vector.<TransformConstraintData> = new Vector.<TransformConstraintData>();
|
||||
public var pathConstraints:Vector.<PathConstraintData> = new Vector.<PathConstraintData>();
|
||||
public var width:Number, height:Number;
|
||||
public var version:String, hash:String;
|
||||
|
||||
public var fps:Number;
|
||||
public var imagesPath:String;
|
||||
|
||||
public function SkeletonData () {
|
||||
}
|
||||
public class SkeletonData {
|
||||
/** May be null. */
|
||||
public var name : String;
|
||||
public var bones : Vector.<BoneData> = new Vector.<BoneData>(); // Ordered parents first.
|
||||
public var slots : Vector.<SlotData> = new Vector.<SlotData>(); // Setup pose draw order.
|
||||
public var skins : Vector.<Skin> = new Vector.<Skin>();
|
||||
public var defaultSkin : Skin;
|
||||
public var events : Vector.<EventData> = new Vector.<EventData>();
|
||||
public var animations : Vector.<Animation> = new Vector.<Animation>();
|
||||
public var ikConstraints : Vector.<IkConstraintData> = new Vector.<IkConstraintData>();
|
||||
public var transformConstraints : Vector.<TransformConstraintData> = new Vector.<TransformConstraintData>();
|
||||
public var pathConstraints : Vector.<PathConstraintData> = new Vector.<PathConstraintData>();
|
||||
public var width : Number, height : Number;
|
||||
public var version : String, hash : String;
|
||||
public var fps : Number;
|
||||
public var imagesPath : String;
|
||||
|
||||
// --- Bones.
|
||||
|
||||
/** @return May be null. */
|
||||
public function findBone (boneName:String) : BoneData {
|
||||
if (boneName == null) throw new ArgumentError("boneName cannot be null.");
|
||||
for (var i:int = 0, n:int = bones.length; i < n; i++) {
|
||||
var bone:BoneData = bones[i];
|
||||
if (bone._name == boneName) return bone;
|
||||
public function SkeletonData() {
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return -1 if the bone was not found. */
|
||||
public function findBoneIndex (boneName:String) : int {
|
||||
if (boneName == null) throw new ArgumentError("boneName cannot be null.");
|
||||
for (var i:int = 0, n:int = bones.length; i < n; i++)
|
||||
if (bones[i]._name == boneName) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// --- Slots.
|
||||
|
||||
/** @return May be null. */
|
||||
public function findSlot (slotName:String) : SlotData {
|
||||
if (slotName == null) throw new ArgumentError("slotName cannot be null.");
|
||||
for (var i:int = 0, n:int = slots.length; i < n; i++) {
|
||||
var slot:SlotData = slots[i];
|
||||
if (slot._name == slotName) return slot;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return -1 if the bone was not found. */
|
||||
public function findSlotIndex (slotName:String) : int {
|
||||
if (slotName == null) throw new ArgumentError("slotName cannot be null.");
|
||||
for (var i:int = 0, n:int = slots.length; i < n; i++)
|
||||
if (slots[i]._name == slotName) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// --- Skins.
|
||||
|
||||
/** @return May be null. */
|
||||
public function findSkin (skinName:String) : Skin {
|
||||
if (skinName == null) throw new ArgumentError("skinName cannot be null.");
|
||||
for each (var skin:Skin in skins)
|
||||
if (skin._name == skinName) return skin;
|
||||
return null;
|
||||
}
|
||||
|
||||
// --- Events.
|
||||
|
||||
/** @return May be null. */
|
||||
public function findEvent (eventName:String) : EventData {
|
||||
if (eventName == null) throw new ArgumentError("eventName cannot be null.");
|
||||
for each (var eventData:EventData in events)
|
||||
if (eventData._name == eventName) return eventData;
|
||||
return null;
|
||||
}
|
||||
|
||||
// --- Animations.
|
||||
|
||||
/** @return May be null. */
|
||||
public function findAnimation (animationName:String) : Animation {
|
||||
if (animationName == null) throw new ArgumentError("animationName cannot be null.");
|
||||
for each (var animation:Animation in animations)
|
||||
if (animation.name == animationName) return animation;
|
||||
return null;
|
||||
}
|
||||
|
||||
// --- IK constraints.
|
||||
|
||||
/** @return May be null. */
|
||||
public function findIkConstraint (constraintName:String) : IkConstraintData {
|
||||
if (constraintName == null) throw new ArgumentError("constraintName cannot be null.");
|
||||
for each (var ikConstraintData:IkConstraintData in ikConstraints)
|
||||
if (ikConstraintData._name == constraintName) return ikConstraintData;
|
||||
return null;
|
||||
}
|
||||
|
||||
// --- Transform constraints.
|
||||
|
||||
/** @return May be null. */
|
||||
public function findTransformConstraint (constraintName:String) : TransformConstraintData {
|
||||
if (constraintName == null) throw new ArgumentError("constraintName cannot be null.");
|
||||
for each (var transformConstraintData:TransformConstraintData in transformConstraints)
|
||||
if (transformConstraintData._name == constraintName) return transformConstraintData;
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return -1 if the transform constraint was not found. */
|
||||
public function findTransformConstraintIndex (transformConstraintName:String) : int {
|
||||
if (transformConstraintName == null) throw new ArgumentError("transformConstraintName cannot be null.");
|
||||
var transformConstraints:Vector.<TransformConstraintData> = this.transformConstraints;
|
||||
for (var i:int = 0, n:int = transformConstraints.length; i < n; i++)
|
||||
if (transformConstraints[i].name == transformConstraintName) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// --- Path constraints.
|
||||
|
||||
// --- Bones.
|
||||
/** @return May be null. */
|
||||
public function findPathConstraint (constraintName:String) : PathConstraintData {
|
||||
if (constraintName == null) throw new ArgumentError("constraintName cannot be null.");
|
||||
var pathConstraints:Vector.<PathConstraintData> = this.pathConstraints;
|
||||
for (var i:int = 0, n:int = pathConstraints.length; i < n; i++) {
|
||||
var constraint:PathConstraintData = pathConstraints[i];
|
||||
if (constraint.name == constraintName) return constraint;
|
||||
public function findBone(boneName : String) : BoneData {
|
||||
if (boneName == null) throw new ArgumentError("boneName cannot be null.");
|
||||
for (var i : int = 0, n : int = bones.length; i < n; i++) {
|
||||
var bone : BoneData = bones[i];
|
||||
if (bone._name == boneName) return bone;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return -1 if the bone was not found. */
|
||||
public function findBoneIndex(boneName : String) : int {
|
||||
if (boneName == null) throw new ArgumentError("boneName cannot be null.");
|
||||
for (var i : int = 0, n : int = bones.length; i < n; i++)
|
||||
if (bones[i]._name == boneName) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// --- Slots.
|
||||
/** @return May be null. */
|
||||
public function findSlot(slotName : String) : SlotData {
|
||||
if (slotName == null) throw new ArgumentError("slotName cannot be null.");
|
||||
for (var i : int = 0, n : int = slots.length; i < n; i++) {
|
||||
var slot : SlotData = slots[i];
|
||||
if (slot._name == slotName) return slot;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return -1 if the bone was not found. */
|
||||
public function findSlotIndex(slotName : String) : int {
|
||||
if (slotName == null) throw new ArgumentError("slotName cannot be null.");
|
||||
for (var i : int = 0, n : int = slots.length; i < n; i++)
|
||||
if (slots[i]._name == slotName) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// --- Skins.
|
||||
/** @return May be null. */
|
||||
public function findSkin(skinName : String) : Skin {
|
||||
if (skinName == null) throw new ArgumentError("skinName cannot be null.");
|
||||
for each (var skin : Skin in skins)
|
||||
if (skin._name == skinName) return skin;
|
||||
return null;
|
||||
}
|
||||
|
||||
// --- Events.
|
||||
/** @return May be null. */
|
||||
public function findEvent(eventName : String) : EventData {
|
||||
if (eventName == null) throw new ArgumentError("eventName cannot be null.");
|
||||
for each (var eventData : EventData in events)
|
||||
if (eventData._name == eventName) return eventData;
|
||||
return null;
|
||||
}
|
||||
|
||||
// --- Animations.
|
||||
/** @return May be null. */
|
||||
public function findAnimation(animationName : String) : Animation {
|
||||
if (animationName == null) throw new ArgumentError("animationName cannot be null.");
|
||||
for each (var animation : Animation in animations)
|
||||
if (animation.name == animationName) return animation;
|
||||
return null;
|
||||
}
|
||||
|
||||
// --- IK constraints.
|
||||
/** @return May be null. */
|
||||
public function findIkConstraint(constraintName : String) : IkConstraintData {
|
||||
if (constraintName == null) throw new ArgumentError("constraintName cannot be null.");
|
||||
for each (var ikConstraintData : IkConstraintData in ikConstraints)
|
||||
if (ikConstraintData._name == constraintName) return ikConstraintData;
|
||||
return null;
|
||||
}
|
||||
|
||||
// --- Transform constraints.
|
||||
/** @return May be null. */
|
||||
public function findTransformConstraint(constraintName : String) : TransformConstraintData {
|
||||
if (constraintName == null) throw new ArgumentError("constraintName cannot be null.");
|
||||
for each (var transformConstraintData : TransformConstraintData in transformConstraints)
|
||||
if (transformConstraintData._name == constraintName) return transformConstraintData;
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return -1 if the transform constraint was not found. */
|
||||
public function findTransformConstraintIndex(transformConstraintName : String) : int {
|
||||
if (transformConstraintName == null) throw new ArgumentError("transformConstraintName cannot be null.");
|
||||
var transformConstraints : Vector.<TransformConstraintData> = this.transformConstraints;
|
||||
for (var i : int = 0, n : int = transformConstraints.length; i < n; i++)
|
||||
if (transformConstraints[i].name == transformConstraintName) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// --- Path constraints.
|
||||
/** @return May be null. */
|
||||
public function findPathConstraint(constraintName : String) : PathConstraintData {
|
||||
if (constraintName == null) throw new ArgumentError("constraintName cannot be null.");
|
||||
var pathConstraints : Vector.<PathConstraintData> = this.pathConstraints;
|
||||
for (var i : int = 0, n : int = pathConstraints.length; i < n; i++) {
|
||||
var constraint : PathConstraintData = pathConstraints[i];
|
||||
if (constraint.name == constraintName) return constraint;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return -1 if the path constraint was not found. */
|
||||
public function findPathConstraintIndex(pathConstraintName : String) : int {
|
||||
if (pathConstraintName == null) throw new ArgumentError("pathConstraintName cannot be null.");
|
||||
var pathConstraints : Vector.<PathConstraintData> = this.pathConstraints;
|
||||
for (var i : int = 0, n : int = pathConstraints.length; i < n; i++)
|
||||
if (pathConstraints[i].name == pathConstraintName) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ---
|
||||
public function toString() : String {
|
||||
return name != null ? name : super.toString();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @return -1 if the path constraint was not found. */
|
||||
public function findPathConstraintIndex (pathConstraintName:String) : int {
|
||||
if (pathConstraintName == null) throw new ArgumentError("pathConstraintName cannot be null.");
|
||||
var pathConstraints:Vector.<PathConstraintData> = this.pathConstraints;
|
||||
for (var i:int = 0, n:int = pathConstraints.length; i < n; i++)
|
||||
if (pathConstraints[i].name == pathConstraintName) return i;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// ---
|
||||
|
||||
public function toString () : String {
|
||||
return name != null ? name : super.toString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -29,65 +29,64 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
import flash.utils.Dictionary;
|
||||
import flash.utils.Dictionary;
|
||||
|
||||
import spine.attachments.Attachment;
|
||||
import spine.attachments.Attachment;
|
||||
|
||||
/** Stores attachments by slot index and attachment name. */
|
||||
public class Skin {
|
||||
internal var _name:String;
|
||||
private var _attachments:Vector.<Dictionary> = new Vector.<Dictionary>();
|
||||
/** Stores attachments by slot index and attachment name. */
|
||||
public class Skin {
|
||||
internal var _name : String;
|
||||
private var _attachments : Vector.<Dictionary> = new Vector.<Dictionary>();
|
||||
|
||||
public function Skin (name:String) {
|
||||
if (name == null) throw new ArgumentError("name cannot be null.");
|
||||
_name = name;
|
||||
}
|
||||
public function Skin(name : String) {
|
||||
if (name == null) throw new ArgumentError("name cannot be null.");
|
||||
_name = name;
|
||||
}
|
||||
|
||||
public function addAttachment (slotIndex:int, name:String, attachment:Attachment) : void {
|
||||
if (attachment == null) throw new ArgumentError("attachment cannot be null.");
|
||||
if (slotIndex >= attachments.length) attachments.length = slotIndex + 1;
|
||||
if (!attachments[slotIndex]) attachments[slotIndex] = new Dictionary();
|
||||
attachments[slotIndex][name] = attachment;
|
||||
}
|
||||
public function addAttachment(slotIndex : int, name : String, attachment : Attachment) : void {
|
||||
if (attachment == null) throw new ArgumentError("attachment cannot be null.");
|
||||
if (slotIndex >= attachments.length) attachments.length = slotIndex + 1;
|
||||
if (!attachments[slotIndex]) attachments[slotIndex] = new Dictionary();
|
||||
attachments[slotIndex][name] = attachment;
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
public function getAttachment (slotIndex:int, name:String) : Attachment {
|
||||
if (slotIndex >= attachments.length) return null;
|
||||
var dictionary:Dictionary = attachments[slotIndex];
|
||||
return dictionary ? dictionary[name] : null;
|
||||
}
|
||||
/** @return May be null. */
|
||||
public function getAttachment(slotIndex : int, name : String) : Attachment {
|
||||
if (slotIndex >= attachments.length) return null;
|
||||
var dictionary : Dictionary = attachments[slotIndex];
|
||||
return dictionary ? dictionary[name] : null;
|
||||
}
|
||||
|
||||
public function get attachments () : Vector.<Dictionary> {
|
||||
return _attachments;
|
||||
}
|
||||
public function get attachments() : Vector.<Dictionary> {
|
||||
return _attachments;
|
||||
}
|
||||
|
||||
public function get name () : String {
|
||||
return _name;
|
||||
}
|
||||
public function get name() : String {
|
||||
return _name;
|
||||
}
|
||||
|
||||
public function toString () : String {
|
||||
return _name;
|
||||
}
|
||||
public function toString() : String {
|
||||
return _name;
|
||||
}
|
||||
|
||||
/** Attach each attachment in this skin if the corresponding attachment in the old skin is currently attached. */
|
||||
public function attachAll (skeleton:Skeleton, oldSkin:Skin) : void {
|
||||
var slotIndex:int = 0;
|
||||
for each (var slot:Slot in skeleton.slots) {
|
||||
var slotAttachment:Attachment = slot.attachment;
|
||||
if (slotAttachment && slotIndex < oldSkin.attachments.length) {
|
||||
var dictionary:Dictionary = oldSkin.attachments[slotIndex];
|
||||
for (var name:String in dictionary) {
|
||||
var skinAttachment:Attachment = dictionary[name];
|
||||
if (slotAttachment == skinAttachment) {
|
||||
var attachment:Attachment = getAttachment(slotIndex, name);
|
||||
if (attachment != null) slot.attachment = attachment;
|
||||
break;
|
||||
/** Attach each attachment in this skin if the corresponding attachment in the old skin is currently attached. */
|
||||
public function attachAll(skeleton : Skeleton, oldSkin : Skin) : void {
|
||||
var slotIndex : int = 0;
|
||||
for each (var slot : Slot in skeleton.slots) {
|
||||
var slotAttachment : Attachment = slot.attachment;
|
||||
if (slotAttachment && slotIndex < oldSkin.attachments.length) {
|
||||
var dictionary : Dictionary = oldSkin.attachments[slotIndex];
|
||||
for (var name : String in dictionary) {
|
||||
var skinAttachment : Attachment = dictionary[name];
|
||||
if (slotAttachment == skinAttachment) {
|
||||
var attachment : Attachment = getAttachment(slotIndex, name);
|
||||
if (attachment != null) slot.attachment = attachment;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
slotIndex++;
|
||||
}
|
||||
slotIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,76 +29,75 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
import spine.attachments.Attachment;
|
||||
import spine.attachments.Attachment;
|
||||
|
||||
public class Slot {
|
||||
internal var _data:SlotData;
|
||||
internal var _bone:Bone;
|
||||
public var color:Color;
|
||||
public var darkColor:Color;
|
||||
internal var _attachment:Attachment;
|
||||
private var _attachmentTime:Number;
|
||||
public var attachmentVertices:Vector.<Number> = new Vector.<Number>();
|
||||
public class Slot {
|
||||
internal var _data : SlotData;
|
||||
internal var _bone : Bone;
|
||||
public var color : Color;
|
||||
public var darkColor : Color;
|
||||
internal var _attachment : Attachment;
|
||||
private var _attachmentTime : Number;
|
||||
public var attachmentVertices : Vector.<Number> = new Vector.<Number>();
|
||||
|
||||
public function Slot (data:SlotData, bone:Bone) {
|
||||
if (data == null) throw new ArgumentError("data cannot be null.");
|
||||
if (bone == null) throw new ArgumentError("bone cannot be null.");
|
||||
_data = data;
|
||||
_bone = bone;
|
||||
this.color = new Color(1, 1, 1, 1);
|
||||
this.darkColor = data.darkColor == null ? null : new Color(1, 1, 1, 1);
|
||||
setToSetupPose();
|
||||
}
|
||||
public function Slot(data : SlotData, bone : Bone) {
|
||||
if (data == null) throw new ArgumentError("data cannot be null.");
|
||||
if (bone == null) throw new ArgumentError("bone cannot be null.");
|
||||
_data = data;
|
||||
_bone = bone;
|
||||
this.color = new Color(1, 1, 1, 1);
|
||||
this.darkColor = data.darkColor == null ? null : new Color(1, 1, 1, 1);
|
||||
setToSetupPose();
|
||||
}
|
||||
|
||||
public function get data () : SlotData {
|
||||
return _data;
|
||||
}
|
||||
|
||||
public function get bone () : Bone {
|
||||
return _bone;
|
||||
}
|
||||
|
||||
public function get skeleton () : Skeleton {
|
||||
return _bone._skeleton;
|
||||
}
|
||||
public function get data() : SlotData {
|
||||
return _data;
|
||||
}
|
||||
|
||||
/** @return May be null. */
|
||||
public function get attachment () : Attachment {
|
||||
return _attachment;
|
||||
}
|
||||
public function get bone() : Bone {
|
||||
return _bone;
|
||||
}
|
||||
|
||||
/** Sets the attachment and resets {@link #getAttachmentTime()}.
|
||||
* @param attachment May be null. */
|
||||
public function set attachment (attachment:Attachment) : void {
|
||||
if (_attachment == attachment) return;
|
||||
_attachment = attachment;
|
||||
_attachmentTime = _bone._skeleton.time;
|
||||
attachmentVertices.length = 0;
|
||||
}
|
||||
public function get skeleton() : Skeleton {
|
||||
return _bone._skeleton;
|
||||
}
|
||||
|
||||
public function set attachmentTime (time:Number) : void {
|
||||
_attachmentTime = _bone._skeleton.time - time;
|
||||
}
|
||||
/** @return May be null. */
|
||||
public function get attachment() : Attachment {
|
||||
return _attachment;
|
||||
}
|
||||
|
||||
/** Returns the time since the attachment was set. */
|
||||
public function get attachmentTime () : Number {
|
||||
return _bone._skeleton.time - _attachmentTime;
|
||||
}
|
||||
/** Sets the attachment and resets {@link #getAttachmentTime()}.
|
||||
* @param attachment May be null. */
|
||||
public function set attachment(attachment : Attachment) : void {
|
||||
if (_attachment == attachment) return;
|
||||
_attachment = attachment;
|
||||
_attachmentTime = _bone._skeleton.time;
|
||||
attachmentVertices.length = 0;
|
||||
}
|
||||
|
||||
public function setToSetupPose () : void {
|
||||
color.setFromColor(data.color);
|
||||
if (darkColor != null) darkColor.setFromColor(this.data.darkColor);
|
||||
if (_data.attachmentName == null)
|
||||
attachment = null;
|
||||
else {
|
||||
_attachment = null;
|
||||
attachment = _bone._skeleton.getAttachmentForSlotIndex(data.index, data.attachmentName);
|
||||
public function set attachmentTime(time : Number) : void {
|
||||
_attachmentTime = _bone._skeleton.time - time;
|
||||
}
|
||||
|
||||
/** Returns the time since the attachment was set. */
|
||||
public function get attachmentTime() : Number {
|
||||
return _bone._skeleton.time - _attachmentTime;
|
||||
}
|
||||
|
||||
public function setToSetupPose() : void {
|
||||
color.setFromColor(data.color);
|
||||
if (darkColor != null) darkColor.setFromColor(this.data.darkColor);
|
||||
if (_data.attachmentName == null)
|
||||
attachment = null;
|
||||
else {
|
||||
_attachment = null;
|
||||
attachment = _bone._skeleton.getAttachmentForSlotIndex(data.index, data.attachmentName);
|
||||
}
|
||||
}
|
||||
|
||||
public function toString() : String {
|
||||
return _data.name;
|
||||
}
|
||||
}
|
||||
|
||||
public function toString () : String {
|
||||
return _data.name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,40 +29,38 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
public class SlotData {
|
||||
internal var _index : int;
|
||||
internal var _name : String;
|
||||
internal var _boneData : BoneData;
|
||||
public var color : Color = new Color(1, 1, 1, 1);
|
||||
public var darkColor : Color;
|
||||
public var attachmentName : String;
|
||||
public var blendMode : BlendMode;
|
||||
|
||||
public class SlotData {
|
||||
internal var _index:int;
|
||||
internal var _name:String;
|
||||
internal var _boneData:BoneData;
|
||||
public var color: Color = new Color(1, 1, 1, 1);
|
||||
public var darkColor: Color;
|
||||
public var attachmentName:String;
|
||||
public var blendMode:BlendMode;
|
||||
public function SlotData(index : int, name : String, boneData : BoneData) {
|
||||
if (index < 0) throw new ArgumentError("index must be >= 0.");
|
||||
if (name == null) throw new ArgumentError("name cannot be null.");
|
||||
if (boneData == null) throw new ArgumentError("boneData cannot be null.");
|
||||
_index = index;
|
||||
_name = name;
|
||||
_boneData = boneData;
|
||||
}
|
||||
|
||||
public function SlotData (index:int, name:String, boneData:BoneData) {
|
||||
if (index < 0) throw new ArgumentError("index must be >= 0.");
|
||||
if (name == null) throw new ArgumentError("name cannot be null.");
|
||||
if (boneData == null) throw new ArgumentError("boneData cannot be null.");
|
||||
_index = index;
|
||||
_name = name;
|
||||
_boneData = boneData;
|
||||
public function get index() : int {
|
||||
return _index;
|
||||
}
|
||||
|
||||
public function get name() : String {
|
||||
return _name;
|
||||
}
|
||||
|
||||
public function get boneData() : BoneData {
|
||||
return _boneData;
|
||||
}
|
||||
|
||||
public function toString() : String {
|
||||
return _name;
|
||||
}
|
||||
}
|
||||
|
||||
public function get index () : int {
|
||||
return _index;
|
||||
}
|
||||
|
||||
public function get name () : String {
|
||||
return _name;
|
||||
}
|
||||
|
||||
public function get boneData () : BoneData {
|
||||
return _boneData;
|
||||
}
|
||||
|
||||
public function toString () : String {
|
||||
return _name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,11 +29,9 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
|
||||
public class SpacingMode {
|
||||
public static const length:SpacingMode = new SpacingMode();
|
||||
public static const fixed:SpacingMode = new SpacingMode();
|
||||
public static const percent:SpacingMode = new SpacingMode();
|
||||
}
|
||||
|
||||
}
|
||||
public class SpacingMode {
|
||||
public static const length : SpacingMode = new SpacingMode();
|
||||
public static const fixed : SpacingMode = new SpacingMode();
|
||||
public static const percent : SpacingMode = new SpacingMode();
|
||||
}
|
||||
}
|
||||
@ -29,268 +29,266 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
public class TransformConstraint implements Constraint {
|
||||
internal var _data : TransformConstraintData;
|
||||
internal var _bones : Vector.<Bone>;
|
||||
public var target : Bone;
|
||||
public var rotateMix : Number;
|
||||
public var translateMix : Number;
|
||||
public var scaleMix : Number;
|
||||
public var shearMix : Number;
|
||||
internal var _temp : Vector.<Number> = new Vector.<Number>(2);
|
||||
|
||||
public class TransformConstraint implements Constraint {
|
||||
internal var _data:TransformConstraintData;
|
||||
internal var _bones:Vector.<Bone>;
|
||||
public var target:Bone;
|
||||
public var rotateMix:Number;
|
||||
public var translateMix:Number;
|
||||
public var scaleMix:Number;
|
||||
public var shearMix:Number;
|
||||
internal var _temp:Vector.<Number> = new Vector.<Number>(2);
|
||||
public function TransformConstraint(data : TransformConstraintData, skeleton : Skeleton) {
|
||||
if (data == null) throw new ArgumentError("data cannot be null.");
|
||||
if (skeleton == null) throw new ArgumentError("skeleton cannot be null.");
|
||||
_data = data;
|
||||
rotateMix = data.rotateMix;
|
||||
translateMix = data.translateMix;
|
||||
scaleMix = data.scaleMix;
|
||||
shearMix = data.shearMix;
|
||||
_bones = new Vector.<Bone>();
|
||||
for each (var boneData : BoneData in data.bones)
|
||||
_bones.push(skeleton.findBone(boneData.name));
|
||||
target = skeleton.findBone(data.target._name);
|
||||
}
|
||||
|
||||
public function TransformConstraint (data:TransformConstraintData, skeleton:Skeleton) {
|
||||
if (data == null) throw new ArgumentError("data cannot be null.");
|
||||
if (skeleton == null) throw new ArgumentError("skeleton cannot be null.");
|
||||
_data = data;
|
||||
rotateMix = data.rotateMix;
|
||||
translateMix = data.translateMix;
|
||||
scaleMix = data.scaleMix;
|
||||
shearMix = data.shearMix;
|
||||
_bones = new Vector.<Bone>();
|
||||
for each (var boneData:BoneData in data.bones)
|
||||
_bones.push(skeleton.findBone(boneData.name));
|
||||
target = skeleton.findBone(data.target._name);
|
||||
}
|
||||
public function apply() : void {
|
||||
update();
|
||||
}
|
||||
|
||||
public function apply () : void {
|
||||
update();
|
||||
}
|
||||
|
||||
public function update () : void {
|
||||
if (data.local) {
|
||||
if (data.relative)
|
||||
applyRelativeLocal();
|
||||
else
|
||||
applyAbsoluteLocal();
|
||||
public function update() : void {
|
||||
if (data.local) {
|
||||
if (data.relative)
|
||||
applyRelativeLocal();
|
||||
else
|
||||
applyAbsoluteLocal();
|
||||
} else {
|
||||
if (data.relative)
|
||||
applyRelativeWorld();
|
||||
else
|
||||
applyAbsoluteWorld();
|
||||
}
|
||||
}
|
||||
|
||||
} else {
|
||||
if (data.relative)
|
||||
applyRelativeWorld();
|
||||
else
|
||||
applyAbsoluteWorld();
|
||||
internal function applyAbsoluteWorld() : void {
|
||||
var rotateMix : Number = this.rotateMix, translateMix : Number = this.translateMix, scaleMix : Number = this.scaleMix, shearMix : Number = this.shearMix;
|
||||
var target : Bone = this.target;
|
||||
var ta : Number = target.a, tb : Number = target.b, tc : Number = target.c, td : Number = target.d;
|
||||
var degRadReflect : Number = ta * td - tb * tc > 0 ? MathUtils.degRad : -MathUtils.degRad;
|
||||
var offsetRotation : Number = data.offsetRotation * degRadReflect;
|
||||
var offsetShearY : Number = data.offsetShearY * degRadReflect;
|
||||
var bones : Vector.<Bone> = this._bones;
|
||||
for (var i : int = 0, n : int = bones.length; i < n; i++) {
|
||||
var bone : Bone = bones[i];
|
||||
var modified : Boolean = false;
|
||||
|
||||
if (rotateMix != 0) {
|
||||
var a : Number = bone.a, b : Number = bone.b, c : Number = bone.c, d : Number = bone.d;
|
||||
var r : Number = Math.atan2(tc, ta) - Math.atan2(c, a) + offsetRotation;
|
||||
if (r > Math.PI)
|
||||
r -= Math.PI * 2;
|
||||
else if (r < -Math.PI) r += Math.PI * 2;
|
||||
r *= rotateMix;
|
||||
var cos : Number = Math.cos(r), sin : Number = Math.sin(r);
|
||||
bone.a = cos * a - sin * c;
|
||||
bone.b = cos * b - sin * d;
|
||||
bone.c = sin * a + cos * c;
|
||||
bone.d = sin * b + cos * d;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (translateMix != 0) {
|
||||
_temp[0] = data.offsetX;
|
||||
_temp[1] = data.offsetY;
|
||||
target.localToWorld(_temp);
|
||||
bone.worldX += (_temp[0] - bone.worldX) * translateMix;
|
||||
bone.worldY += (_temp[1] - bone.worldY) * translateMix;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (scaleMix > 0) {
|
||||
var s : Number = Math.sqrt(bone.a * bone.a + bone.c * bone.c);
|
||||
var ts : Number = Math.sqrt(ta * ta + tc * tc);
|
||||
if (s > 0.00001) s = (s + (ts - s + data.offsetScaleX) * scaleMix) / s;
|
||||
bone.a *= s;
|
||||
bone.c *= s;
|
||||
s = Math.sqrt(bone.b * bone.b + bone.d * bone.d);
|
||||
ts = Math.sqrt(tb * tb + td * td);
|
||||
if (s > 0.00001) s = (s + (ts - s + data.offsetScaleY) * scaleMix) / s;
|
||||
bone.b *= s;
|
||||
bone.d *= s;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (shearMix > 0) {
|
||||
b = bone.b
|
||||
,
|
||||
d = bone.d;
|
||||
var by : Number = Math.atan2(d, b);
|
||||
r = Math.atan2(td, tb) - Math.atan2(tc, ta) - (by - Math.atan2(bone.c, bone.a));
|
||||
if (r > Math.PI)
|
||||
r -= Math.PI * 2;
|
||||
else if (r < -Math.PI) r += Math.PI * 2;
|
||||
r = by + (r + offsetShearY) * shearMix;
|
||||
s = Math.sqrt(b * b + d * d);
|
||||
bone.b = Math.cos(r) * s;
|
||||
bone.d = Math.sin(r) * s;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (modified) bone.appliedValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
public function applyRelativeWorld() : void {
|
||||
var rotateMix : Number = this.rotateMix, translateMix : Number = this.translateMix, scaleMix : Number = this.scaleMix, shearMix : Number = this.shearMix;
|
||||
var target : Bone = this.target;
|
||||
var ta : Number = target.a, tb : Number = target.b, tc : Number = target.c, td : Number = target.d;
|
||||
var degRadReflect : Number = ta * td - tb * tc > 0 ? MathUtils.degRad : -MathUtils.degRad;
|
||||
var offsetRotation : Number = this.data.offsetRotation * degRadReflect, offsetShearY : Number = this.data.offsetShearY * degRadReflect;
|
||||
var bones : Vector.<Bone> = this.bones;
|
||||
for (var i : int = 0, n : int = bones.length; i < n; i++) {
|
||||
var bone : Bone = bones[i];
|
||||
var modified : Boolean = false;
|
||||
|
||||
if (rotateMix != 0) {
|
||||
var a : Number = bone.a, b : Number = bone.b, c : Number = bone.c, d : Number = bone.d;
|
||||
var r : Number = Math.atan2(tc, ta) + offsetRotation;
|
||||
if (r > MathUtils.PI)
|
||||
r -= MathUtils.PI2;
|
||||
else if (r < -MathUtils.PI) r += MathUtils.PI2;
|
||||
r *= rotateMix;
|
||||
var cos : Number = Math.cos(r), sin : Number = Math.sin(r);
|
||||
bone.a = cos * a - sin * c;
|
||||
bone.b = cos * b - sin * d;
|
||||
bone.c = sin * a + cos * c;
|
||||
bone.d = sin * b + cos * d;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (translateMix != 0) {
|
||||
var temp : Vector.<Number> = this._temp;
|
||||
temp[0] = this._data.offsetX;
|
||||
temp[1] = this._data.offsetY;
|
||||
target.localToWorld(temp);
|
||||
bone.worldX += temp[0] * translateMix;
|
||||
bone.worldY += temp[1] * translateMix;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (scaleMix > 0) {
|
||||
var s : Number = (Math.sqrt(ta * ta + tc * tc) - 1 + this.data.offsetScaleX) * scaleMix + 1;
|
||||
bone.a *= s;
|
||||
bone.c *= s;
|
||||
s = (Math.sqrt(tb * tb + td * td) - 1 + this.data.offsetScaleY) * scaleMix + 1;
|
||||
bone.b *= s;
|
||||
bone.d *= s;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (shearMix > 0) {
|
||||
r = Math.atan2(td, tb) - Math.atan2(tc, ta);
|
||||
if (r > MathUtils.PI)
|
||||
r -= MathUtils.PI2;
|
||||
else if (r < -MathUtils.PI) r += MathUtils.PI2;
|
||||
b = bone.b;
|
||||
d = bone.d;
|
||||
r = Math.atan2(d, b) + (r - MathUtils.PI / 2 + offsetShearY) * shearMix;
|
||||
s = Math.sqrt(b * b + d * d);
|
||||
bone.b = Math.cos(r) * s;
|
||||
bone.d = Math.sin(r) * s;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (modified) bone.appliedValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
public function applyAbsoluteLocal() : void {
|
||||
var rotateMix : Number = this.rotateMix, translateMix : Number = this.translateMix, scaleMix : Number = this.scaleMix, shearMix : Number = this.shearMix;
|
||||
var target : Bone = this.target;
|
||||
if (!target.appliedValid) target.updateAppliedTransform();
|
||||
var bones : Vector.<Bone> = this.bones;
|
||||
for (var i : int = 0, n : int = bones.length; i < n; i++) {
|
||||
var bone : Bone = bones[i];
|
||||
if (!bone.appliedValid) bone.updateAppliedTransform();
|
||||
|
||||
var rotation : Number = bone.arotation;
|
||||
if (rotateMix != 0) {
|
||||
var r : Number = target.arotation - rotation + this.data.offsetRotation;
|
||||
r -= (16384 - ((16384.499999999996 - r / 360) | 0)) * 360;
|
||||
rotation += r * rotateMix;
|
||||
}
|
||||
|
||||
var x : Number = bone.ax, y : Number = bone.ay;
|
||||
if (translateMix != 0) {
|
||||
x += (target.ax - x + this.data.offsetX) * translateMix;
|
||||
y += (target.ay - y + this.data.offsetY) * translateMix;
|
||||
}
|
||||
|
||||
var scaleX : Number = bone.ascaleX, scaleY : Number = bone.ascaleY;
|
||||
if (scaleMix > 0) {
|
||||
if (scaleX > 0.00001) scaleX = (scaleX + (target.ascaleX - scaleX + this.data.offsetScaleX) * scaleMix) / scaleX;
|
||||
if (scaleY > 0.00001) scaleY = (scaleY + (target.ascaleY - scaleY + this.data.offsetScaleY) * scaleMix) / scaleY;
|
||||
}
|
||||
|
||||
var shearY : Number = bone.ashearY;
|
||||
if (shearMix > 0) {
|
||||
r = target.ashearY - shearY + this.data.offsetShearY;
|
||||
r -= (16384 - ((16384.499999999996 - r / 360) | 0)) * 360;
|
||||
bone.shearY += r * shearMix;
|
||||
}
|
||||
|
||||
bone.updateWorldTransformWith(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY);
|
||||
}
|
||||
}
|
||||
|
||||
public function applyRelativeLocal() : void {
|
||||
var rotateMix : Number = this.rotateMix, translateMix : Number = this.translateMix, scaleMix : Number = this.scaleMix, shearMix : Number = this.shearMix;
|
||||
var target : Bone = this.target;
|
||||
if (!target.appliedValid) target.updateAppliedTransform();
|
||||
var bones : Vector.<Bone> = this.bones;
|
||||
for (var i : int = 0, n : int = bones.length; i < n; i++) {
|
||||
var bone : Bone = bones[i];
|
||||
if (!bone.appliedValid) bone.updateAppliedTransform();
|
||||
|
||||
var rotation : Number = bone.arotation;
|
||||
if (rotateMix != 0) rotation += (target.arotation + this.data.offsetRotation) * rotateMix;
|
||||
|
||||
var x : Number = bone.ax, y : Number = bone.ay;
|
||||
if (translateMix != 0) {
|
||||
x += (target.ax + this.data.offsetX) * translateMix;
|
||||
y += (target.ay + this.data.offsetY) * translateMix;
|
||||
}
|
||||
|
||||
var scaleX : Number = bone.ascaleX, scaleY : Number = bone.ascaleY;
|
||||
if (scaleMix > 0) {
|
||||
if (scaleX > 0.00001) scaleX *= ((target.ascaleX - 1 + this.data.offsetScaleX) * scaleMix) + 1;
|
||||
if (scaleY > 0.00001) scaleY *= ((target.ascaleY - 1 + this.data.offsetScaleY) * scaleMix) + 1;
|
||||
}
|
||||
|
||||
var shearY : Number = bone.ashearY;
|
||||
if (shearMix > 0) shearY += (target.ashearY + this.data.offsetShearY) * shearMix;
|
||||
|
||||
bone.updateWorldTransformWith(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY);
|
||||
}
|
||||
}
|
||||
|
||||
public function getOrder() : Number {
|
||||
return _data.order;
|
||||
}
|
||||
|
||||
public function get data() : TransformConstraintData {
|
||||
return _data;
|
||||
}
|
||||
|
||||
public function get bones() : Vector.<Bone> {
|
||||
return _bones;
|
||||
}
|
||||
|
||||
public function toString() : String {
|
||||
return _data._name;
|
||||
}
|
||||
}
|
||||
|
||||
internal function applyAbsoluteWorld () : void {
|
||||
var rotateMix:Number = this.rotateMix, translateMix:Number = this.translateMix, scaleMix:Number = this.scaleMix, shearMix:Number = this.shearMix;
|
||||
var target:Bone = this.target;
|
||||
var ta:Number = target.a, tb:Number = target.b, tc:Number = target.c, td:Number = target.d;
|
||||
var degRadReflect:Number = ta * td - tb * tc > 0 ? MathUtils.degRad : -MathUtils.degRad;
|
||||
var offsetRotation:Number = data.offsetRotation * degRadReflect;
|
||||
var offsetShearY:Number = data.offsetShearY * degRadReflect;
|
||||
var bones:Vector.<Bone> = this._bones;
|
||||
for (var i:int = 0, n:int = bones.length; i < n; i++) {
|
||||
var bone:Bone = bones[i];
|
||||
var modified:Boolean = false;
|
||||
|
||||
if (rotateMix != 0) {
|
||||
var a:Number = bone.a, b:Number = bone.b, c:Number = bone.c, d:Number = bone.d;
|
||||
var r:Number = Math.atan2(tc, ta) - Math.atan2(c, a) + offsetRotation;
|
||||
if (r > Math.PI)
|
||||
r -= Math.PI * 2;
|
||||
else if (r < -Math.PI) r += Math.PI * 2;
|
||||
r *= rotateMix;
|
||||
var cos:Number = Math.cos(r), sin:Number = Math.sin(r);
|
||||
bone.a = cos * a - sin * c;
|
||||
bone.b = cos * b - sin * d;
|
||||
bone.c = sin * a + cos * c;
|
||||
bone.d = sin * b + cos * d;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (translateMix != 0) {
|
||||
_temp[0] = data.offsetX;
|
||||
_temp[1] = data.offsetY;
|
||||
target.localToWorld(_temp);
|
||||
bone.worldX += (_temp[0] - bone.worldX) * translateMix;
|
||||
bone.worldY += (_temp[1] - bone.worldY) * translateMix;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (scaleMix > 0) {
|
||||
var s:Number = Math.sqrt(bone.a * bone.a + bone.c * bone.c);
|
||||
var ts:Number = Math.sqrt(ta * ta + tc * tc);
|
||||
if (s > 0.00001) s = (s + (ts - s + data.offsetScaleX) * scaleMix) / s;
|
||||
bone.a *= s;
|
||||
bone.c *= s;
|
||||
s = Math.sqrt(bone.b * bone.b + bone.d * bone.d);
|
||||
ts = Math.sqrt(tb * tb + td * td);
|
||||
if (s > 0.00001) s = (s + (ts - s + data.offsetScaleY) * scaleMix) / s;
|
||||
bone.b *= s;
|
||||
bone.d *= s;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (shearMix > 0) {
|
||||
b = bone.b, d = bone.d;
|
||||
var by:Number = Math.atan2(d, b);
|
||||
r = Math.atan2(td, tb) - Math.atan2(tc, ta) - (by - Math.atan2(bone.c, bone.a));
|
||||
if (r > Math.PI)
|
||||
r -= Math.PI * 2;
|
||||
else if (r < -Math.PI) r += Math.PI * 2;
|
||||
r = by + (r + offsetShearY) * shearMix;
|
||||
s = Math.sqrt(b * b + d * d);
|
||||
bone.b = Math.cos(r) * s;
|
||||
bone.d = Math.sin(r) * s;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (modified) bone.appliedValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
public function applyRelativeWorld () : void {
|
||||
var rotateMix:Number = this.rotateMix, translateMix:Number = this.translateMix, scaleMix:Number = this.scaleMix, shearMix:Number = this.shearMix;
|
||||
var target:Bone = this.target;
|
||||
var ta:Number = target.a, tb:Number = target.b, tc:Number = target.c, td:Number = target.d;
|
||||
var degRadReflect:Number = ta * td - tb * tc > 0 ? MathUtils.degRad : -MathUtils.degRad;
|
||||
var offsetRotation:Number = this.data.offsetRotation * degRadReflect, offsetShearY:Number = this.data.offsetShearY * degRadReflect;
|
||||
var bones:Vector.<Bone> = this.bones;
|
||||
for (var i:int = 0, n:int = bones.length; i < n; i++) {
|
||||
var bone:Bone = bones[i];
|
||||
var modified:Boolean = false;
|
||||
|
||||
if (rotateMix != 0) {
|
||||
var a:Number = bone.a, b:Number = bone.b, c:Number = bone.c, d:Number = bone.d;
|
||||
var r:Number = Math.atan2(tc, ta) + offsetRotation;
|
||||
if (r > MathUtils.PI)
|
||||
r -= MathUtils.PI2;
|
||||
else if (r < -MathUtils.PI) r += MathUtils.PI2;
|
||||
r *= rotateMix;
|
||||
var cos:Number = Math.cos(r), sin:Number = Math.sin(r);
|
||||
bone.a = cos * a - sin * c;
|
||||
bone.b = cos * b - sin * d;
|
||||
bone.c = sin * a + cos * c;
|
||||
bone.d = sin * b + cos * d;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (translateMix != 0) {
|
||||
var temp:Vector.<Number> = this._temp;
|
||||
temp[0] = this._data.offsetX;
|
||||
temp[1] = this._data.offsetY;
|
||||
target.localToWorld(temp);
|
||||
bone.worldX += temp[0] * translateMix;
|
||||
bone.worldY += temp[1] * translateMix;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (scaleMix > 0) {
|
||||
var s:Number = (Math.sqrt(ta * ta + tc * tc) - 1 + this.data.offsetScaleX) * scaleMix + 1;
|
||||
bone.a *= s;
|
||||
bone.c *= s;
|
||||
s = (Math.sqrt(tb * tb + td * td) - 1 + this.data.offsetScaleY) * scaleMix + 1;
|
||||
bone.b *= s;
|
||||
bone.d *= s;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (shearMix > 0) {
|
||||
r = Math.atan2(td, tb) - Math.atan2(tc, ta);
|
||||
if (r > MathUtils.PI)
|
||||
r -= MathUtils.PI2;
|
||||
else if (r < -MathUtils.PI) r += MathUtils.PI2;
|
||||
b = bone.b; d = bone.d;
|
||||
r = Math.atan2(d, b) + (r - MathUtils.PI / 2 + offsetShearY) * shearMix;
|
||||
s = Math.sqrt(b * b + d * d);
|
||||
bone.b = Math.cos(r) * s;
|
||||
bone.d = Math.sin(r) * s;
|
||||
modified = true;
|
||||
}
|
||||
|
||||
if (modified) bone.appliedValid = false;
|
||||
}
|
||||
}
|
||||
|
||||
public function applyAbsoluteLocal () : void {
|
||||
var rotateMix:Number = this.rotateMix, translateMix:Number = this.translateMix, scaleMix:Number = this.scaleMix, shearMix:Number = this.shearMix;
|
||||
var target:Bone = this.target;
|
||||
if (!target.appliedValid) target.updateAppliedTransform();
|
||||
var bones:Vector.<Bone> = this.bones;
|
||||
for (var i:int = 0, n:int = bones.length; i < n; i++) {
|
||||
var bone:Bone = bones[i];
|
||||
if (!bone.appliedValid) bone.updateAppliedTransform();
|
||||
|
||||
var rotation:Number = bone.arotation;
|
||||
if (rotateMix != 0) {
|
||||
var r:Number = target.arotation - rotation + this.data.offsetRotation;
|
||||
r -= (16384 - ((16384.499999999996 - r / 360) | 0)) * 360;
|
||||
rotation += r * rotateMix;
|
||||
}
|
||||
|
||||
var x:Number = bone.ax, y:Number = bone.ay;
|
||||
if (translateMix != 0) {
|
||||
x += (target.ax - x + this.data.offsetX) * translateMix;
|
||||
y += (target.ay - y + this.data.offsetY) * translateMix;
|
||||
}
|
||||
|
||||
var scaleX:Number = bone.ascaleX, scaleY:Number = bone.ascaleY;
|
||||
if (scaleMix > 0) {
|
||||
if (scaleX > 0.00001) scaleX = (scaleX + (target.ascaleX - scaleX + this.data.offsetScaleX) * scaleMix) / scaleX;
|
||||
if (scaleY > 0.00001) scaleY = (scaleY + (target.ascaleY - scaleY + this.data.offsetScaleY) * scaleMix) / scaleY;
|
||||
}
|
||||
|
||||
var shearY:Number = bone.ashearY;
|
||||
if (shearMix > 0) {
|
||||
r = target.ashearY - shearY + this.data.offsetShearY;
|
||||
r -= (16384 - ((16384.499999999996 - r / 360) | 0)) * 360;
|
||||
bone.shearY += r * shearMix;
|
||||
}
|
||||
|
||||
bone.updateWorldTransformWith(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY);
|
||||
}
|
||||
}
|
||||
|
||||
public function applyRelativeLocal () : void {
|
||||
var rotateMix:Number = this.rotateMix, translateMix:Number = this.translateMix, scaleMix:Number = this.scaleMix, shearMix:Number = this.shearMix;
|
||||
var target:Bone = this.target;
|
||||
if (!target.appliedValid) target.updateAppliedTransform();
|
||||
var bones:Vector.<Bone> = this.bones;
|
||||
for (var i:int = 0, n:int = bones.length; i < n; i++) {
|
||||
var bone:Bone = bones[i];
|
||||
if (!bone.appliedValid) bone.updateAppliedTransform();
|
||||
|
||||
var rotation:Number = bone.arotation;
|
||||
if (rotateMix != 0) rotation += (target.arotation + this.data.offsetRotation) * rotateMix;
|
||||
|
||||
var x:Number = bone.ax, y:Number = bone.ay;
|
||||
if (translateMix != 0) {
|
||||
x += (target.ax + this.data.offsetX) * translateMix;
|
||||
y += (target.ay + this.data.offsetY) * translateMix;
|
||||
}
|
||||
|
||||
var scaleX:Number = bone.ascaleX, scaleY:Number = bone.ascaleY;
|
||||
if (scaleMix > 0) {
|
||||
if (scaleX > 0.00001) scaleX *= ((target.ascaleX - 1 + this.data.offsetScaleX) * scaleMix) + 1;
|
||||
if (scaleY > 0.00001) scaleY *= ((target.ascaleY - 1 + this.data.offsetScaleY) * scaleMix) + 1;
|
||||
}
|
||||
|
||||
var shearY:Number = bone.ashearY;
|
||||
if (shearMix > 0) shearY += (target.ashearY + this.data.offsetShearY) * shearMix;
|
||||
|
||||
bone.updateWorldTransformWith(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
public function getOrder () : Number {
|
||||
return _data.order;
|
||||
}
|
||||
|
||||
public function get data () : TransformConstraintData {
|
||||
return _data;
|
||||
}
|
||||
|
||||
public function get bones () : Vector.<Bone> {
|
||||
return _bones;
|
||||
}
|
||||
|
||||
public function toString () : String {
|
||||
return _data._name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,41 +29,40 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
public class TransformConstraintData {
|
||||
internal var _name : String;
|
||||
public var order : Number;
|
||||
internal var _bones : Vector.<BoneData> = new Vector.<BoneData>();
|
||||
public var target : BoneData;
|
||||
public var rotateMix : Number;
|
||||
public var translateMix : Number;
|
||||
public var scaleMix : Number;
|
||||
public var shearMix : Number;
|
||||
public var offsetRotation : Number;
|
||||
public var offsetX : Number;
|
||||
public var offsetY : Number;
|
||||
public var offsetScaleX : Number;
|
||||
public var offsetScaleY : Number;
|
||||
public var offsetShearY : Number;
|
||||
public var relative : Boolean = false;
|
||||
public var local : Boolean = false;
|
||||
|
||||
public class TransformConstraintData {
|
||||
internal var _name:String;
|
||||
public var order:Number;
|
||||
internal var _bones:Vector.<BoneData> = new Vector.<BoneData>();
|
||||
public var target:BoneData;
|
||||
public var rotateMix:Number;
|
||||
public var translateMix:Number;
|
||||
public var scaleMix:Number;
|
||||
public var shearMix:Number;
|
||||
public var offsetRotation:Number;
|
||||
public var offsetX:Number;
|
||||
public var offsetY:Number;
|
||||
public var offsetScaleX:Number;
|
||||
public var offsetScaleY:Number;
|
||||
public var offsetShearY:Number;
|
||||
public var relative:Boolean = false;
|
||||
public var local:Boolean = false;
|
||||
public function TransformConstraintData(name : String) {
|
||||
if (name == null) throw new ArgumentError("name cannot be null.");
|
||||
_name = name;
|
||||
}
|
||||
|
||||
public function TransformConstraintData (name:String) {
|
||||
if (name == null) throw new ArgumentError("name cannot be null.");
|
||||
_name = name;
|
||||
public function get bones() : Vector.<BoneData> {
|
||||
;
|
||||
return _bones;
|
||||
}
|
||||
|
||||
public function get name() : String {
|
||||
return _name;
|
||||
}
|
||||
|
||||
public function toString() : String {
|
||||
return _name;
|
||||
}
|
||||
}
|
||||
|
||||
public function get bones () : Vector.<BoneData> {;
|
||||
return _bones;
|
||||
}
|
||||
|
||||
public function get name () : String {
|
||||
return _name;
|
||||
}
|
||||
|
||||
public function toString () : String {
|
||||
return _name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,13 +29,11 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
|
||||
public class TransformMode {
|
||||
public static const normal:TransformMode = new TransformMode();
|
||||
public static const onlyTranslation:TransformMode = new TransformMode();
|
||||
public static const noRotationOrReflection:TransformMode = new TransformMode();
|
||||
public static const noScale:TransformMode = new TransformMode();
|
||||
public static const noScaleOrReflection:TransformMode = new TransformMode();
|
||||
}
|
||||
|
||||
}
|
||||
public class TransformMode {
|
||||
public static const normal : TransformMode = new TransformMode();
|
||||
public static const onlyTranslation : TransformMode = new TransformMode();
|
||||
public static const noRotationOrReflection : TransformMode = new TransformMode();
|
||||
public static const noScale : TransformMode = new TransformMode();
|
||||
public static const noScaleOrReflection : TransformMode = new TransformMode();
|
||||
}
|
||||
}
|
||||
@ -29,9 +29,7 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine {
|
||||
|
||||
public interface Updatable {
|
||||
function update () : void;
|
||||
}
|
||||
|
||||
}
|
||||
public interface Updatable {
|
||||
function update() : void;
|
||||
}
|
||||
}
|
||||
@ -29,91 +29,90 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.animation {
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
|
||||
public class Animation {
|
||||
internal var _name:String;
|
||||
public var _timelines:Vector.<Timeline>;
|
||||
public var duration:Number;
|
||||
public class Animation {
|
||||
internal var _name : String;
|
||||
public var _timelines : Vector.<Timeline>;
|
||||
public var duration : Number;
|
||||
|
||||
public function Animation (name:String, timelines:Vector.<Timeline>, duration:Number) {
|
||||
if (name == null) throw new ArgumentError("name cannot be null.");
|
||||
if (timelines == null) throw new ArgumentError("timelines cannot be null.");
|
||||
_name = name;
|
||||
_timelines = timelines;
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
public function get timelines () : Vector.<Timeline> {
|
||||
return _timelines;
|
||||
}
|
||||
|
||||
/** Poses the skeleton at the specified time for this animation. */
|
||||
public function apply (skeleton:Skeleton, lastTime:Number, time:Number, loop:Boolean, events:Vector.<Event>, alpha:Number, setupPose:Boolean, mixingOut:Boolean) : void {
|
||||
if (skeleton == null) throw new ArgumentError("skeleton cannot be null.");
|
||||
|
||||
if (loop && duration != 0) {
|
||||
time %= duration;
|
||||
if (lastTime > 0) lastTime %= duration;
|
||||
public function Animation(name : String, timelines : Vector.<Timeline>, duration : Number) {
|
||||
if (name == null) throw new ArgumentError("name cannot be null.");
|
||||
if (timelines == null) throw new ArgumentError("timelines cannot be null.");
|
||||
_name = name;
|
||||
_timelines = timelines;
|
||||
this.duration = duration;
|
||||
}
|
||||
|
||||
for (var i:int = 0, n:int = timelines.length; i < n; i++)
|
||||
timelines[i].apply(skeleton, lastTime, time, events, alpha, setupPose, mixingOut);
|
||||
}
|
||||
|
||||
public function get name () : String {
|
||||
return _name;
|
||||
}
|
||||
|
||||
public function toString () : String {
|
||||
return _name;
|
||||
}
|
||||
|
||||
/** @param target After the first and before the last entry. */
|
||||
static public function binarySearch (values:Vector.<Number>, target:Number, step:int) : int {
|
||||
var low:int = 0;
|
||||
var high:int = values.length / step - 2;
|
||||
if (high == 0)
|
||||
return step;
|
||||
var current:int = high >>> 1;
|
||||
while (true) {
|
||||
if (values[int((current + 1) * step)] <= target)
|
||||
low = current + 1;
|
||||
else
|
||||
high = current;
|
||||
if (low == high)
|
||||
return (low + 1) * step;
|
||||
current = (low + high) >>> 1;
|
||||
public function get timelines() : Vector.<Timeline> {
|
||||
return _timelines;
|
||||
}
|
||||
return 0; // Can't happen.
|
||||
}
|
||||
|
||||
/** @param target After the first and before the last entry. */
|
||||
static public function binarySearch1 (values:Vector.<Number>, target:Number) : int {
|
||||
var low:int = 0;
|
||||
var high:int = values.length - 2;
|
||||
if (high == 0)
|
||||
return 1;
|
||||
var current:int = high >>> 1;
|
||||
while (true) {
|
||||
if (values[int(current + 1)] <= target)
|
||||
low = current + 1;
|
||||
else
|
||||
high = current;
|
||||
if (low == high)
|
||||
return low + 1;
|
||||
current = (low + high) >>> 1;
|
||||
/** Poses the skeleton at the specified time for this animation. */
|
||||
public function apply(skeleton : Skeleton, lastTime : Number, time : Number, loop : Boolean, events : Vector.<Event>, alpha : Number, setupPose : Boolean, mixingOut : Boolean) : void {
|
||||
if (skeleton == null) throw new ArgumentError("skeleton cannot be null.");
|
||||
|
||||
if (loop && duration != 0) {
|
||||
time %= duration;
|
||||
if (lastTime > 0) lastTime %= duration;
|
||||
}
|
||||
|
||||
for (var i : int = 0, n : int = timelines.length; i < n; i++)
|
||||
timelines[i].apply(skeleton, lastTime, time, events, alpha, setupPose, mixingOut);
|
||||
}
|
||||
return 0; // Can't happen.
|
||||
}
|
||||
|
||||
static public function linearSearch (values:Vector.<Number>, target:Number, step:int) : int {
|
||||
for (var i:int = 0, last:int = values.length - step; i <= last; i += step)
|
||||
if (values[i] > target)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
public function get name() : String {
|
||||
return _name;
|
||||
}
|
||||
|
||||
}
|
||||
public function toString() : String {
|
||||
return _name;
|
||||
}
|
||||
|
||||
/** @param target After the first and before the last entry. */
|
||||
static public function binarySearch(values : Vector.<Number>, target : Number, step : int) : int {
|
||||
var low : int = 0;
|
||||
var high : int = values.length / step - 2;
|
||||
if (high == 0)
|
||||
return step;
|
||||
var current : int = high >>> 1;
|
||||
while (true) {
|
||||
if (values[int((current + 1) * step)] <= target)
|
||||
low = current + 1;
|
||||
else
|
||||
high = current;
|
||||
if (low == high)
|
||||
return (low + 1) * step;
|
||||
current = (low + high) >>> 1;
|
||||
}
|
||||
return 0; // Can't happen.
|
||||
}
|
||||
|
||||
/** @param target After the first and before the last entry. */
|
||||
static public function binarySearch1(values : Vector.<Number>, target : Number) : int {
|
||||
var low : int = 0;
|
||||
var high : int = values.length - 2;
|
||||
if (high == 0)
|
||||
return 1;
|
||||
var current : int = high >>> 1;
|
||||
while (true) {
|
||||
if (values[int(current + 1)] <= target)
|
||||
low = current + 1;
|
||||
else
|
||||
high = current;
|
||||
if (low == high)
|
||||
return low + 1;
|
||||
current = (low + high) >>> 1;
|
||||
}
|
||||
return 0; // Can't happen.
|
||||
}
|
||||
|
||||
static public function linearSearch(values : Vector.<Number>, target : Number, step : int) : int {
|
||||
for (var i : int = 0, last : int = values.length - step; i <= last; i += step)
|
||||
if (values[i] > target)
|
||||
return i;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@ -29,40 +29,39 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.animation {
|
||||
import spine.SkeletonData;
|
||||
import spine.SkeletonData;
|
||||
|
||||
public class AnimationStateData {
|
||||
internal var _skeletonData:SkeletonData;
|
||||
private var animationToMixTime:Object = new Object();
|
||||
public var defaultMix:Number = 0;
|
||||
public class AnimationStateData {
|
||||
internal var _skeletonData : SkeletonData;
|
||||
private var animationToMixTime : Object = new Object();
|
||||
public var defaultMix : Number = 0;
|
||||
|
||||
public function AnimationStateData (skeletonData:SkeletonData) {
|
||||
_skeletonData = skeletonData;
|
||||
public function AnimationStateData(skeletonData : SkeletonData) {
|
||||
_skeletonData = skeletonData;
|
||||
}
|
||||
|
||||
public function get skeletonData() : SkeletonData {
|
||||
return _skeletonData;
|
||||
}
|
||||
|
||||
public function setMixByName(fromName : String, toName : String, duration : Number) : void {
|
||||
var from : Animation = _skeletonData.findAnimation(fromName);
|
||||
if (from == null) throw new ArgumentError("Animation not found: " + fromName);
|
||||
var to : Animation = _skeletonData.findAnimation(toName);
|
||||
if (to == null) throw new ArgumentError("Animation not found: " + toName);
|
||||
setMix(from, to, duration);
|
||||
}
|
||||
|
||||
public function setMix(from : Animation, to : Animation, duration : Number) : void {
|
||||
if (from == null) throw new ArgumentError("from cannot be null.");
|
||||
if (to == null) throw new ArgumentError("to cannot be null.");
|
||||
animationToMixTime[from.name + ":" + to.name] = duration;
|
||||
}
|
||||
|
||||
public function getMix(from : Animation, to : Animation) : Number {
|
||||
var time : Object = animationToMixTime[from.name + ":" + to.name];
|
||||
if (time == null) return defaultMix;
|
||||
return time as Number;
|
||||
}
|
||||
}
|
||||
|
||||
public function get skeletonData () : SkeletonData {
|
||||
return _skeletonData;
|
||||
}
|
||||
|
||||
public function setMixByName (fromName:String, toName:String, duration:Number) : void {
|
||||
var from:Animation = _skeletonData.findAnimation(fromName);
|
||||
if (from == null) throw new ArgumentError("Animation not found: " + fromName);
|
||||
var to:Animation = _skeletonData.findAnimation(toName);
|
||||
if (to == null) throw new ArgumentError("Animation not found: " + toName);
|
||||
setMix(from, to, duration);
|
||||
}
|
||||
|
||||
public function setMix (from:Animation, to:Animation, duration:Number) : void {
|
||||
if (from == null) throw new ArgumentError("from cannot be null.");
|
||||
if (to == null) throw new ArgumentError("to cannot be null.");
|
||||
animationToMixTime[from.name + ":" + to.name] = duration;
|
||||
}
|
||||
|
||||
public function getMix (from:Animation, to:Animation) : Number {
|
||||
var time:Object = animationToMixTime[from.name + ":" + to.name];
|
||||
if (time == null) return defaultMix;
|
||||
return time as Number;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,60 +29,59 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.animation {
|
||||
import spine.Slot;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
import spine.Slot;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
|
||||
public class AttachmentTimeline implements Timeline {
|
||||
public var slotIndex:int;
|
||||
public var frames:Vector.<Number>; // time, ...
|
||||
public var attachmentNames:Vector.<String>;
|
||||
public class AttachmentTimeline implements Timeline {
|
||||
public var slotIndex : int;
|
||||
public var frames : Vector.<Number>; // time, ...
|
||||
public var attachmentNames : Vector.<String>;
|
||||
|
||||
public function AttachmentTimeline (frameCount:int) {
|
||||
frames = new Vector.<Number>(frameCount, true);
|
||||
attachmentNames = new Vector.<String>(frameCount, true);
|
||||
}
|
||||
|
||||
public function get frameCount () : int {
|
||||
return frames.length;
|
||||
}
|
||||
|
||||
public function getPropertyId () : int {
|
||||
return (TimelineType.attachment.ordinal << 24) + slotIndex;
|
||||
}
|
||||
|
||||
/** Sets the time and value of the specified keyframe. */
|
||||
public function setFrame (frameIndex:int, time:Number, attachmentName:String) : void {
|
||||
frames[frameIndex] = time;
|
||||
attachmentNames[frameIndex] = attachmentName;
|
||||
}
|
||||
|
||||
public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector.<Event>, alpha:Number, setupPose:Boolean, mixingOut:Boolean) : void {
|
||||
var attachmentName:String;
|
||||
var slot:Slot = skeleton.slots[slotIndex];
|
||||
if (mixingOut && setupPose) {
|
||||
attachmentName = slot.data.attachmentName;
|
||||
slot.attachment = attachmentName == null ? null : skeleton.getAttachmentForSlotIndex(slotIndex, attachmentName);
|
||||
return;
|
||||
public function AttachmentTimeline(frameCount : int) {
|
||||
frames = new Vector.<Number>(frameCount, true);
|
||||
attachmentNames = new Vector.<String>(frameCount, true);
|
||||
}
|
||||
var frames:Vector.<Number> = this.frames;
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) {
|
||||
|
||||
public function get frameCount() : int {
|
||||
return frames.length;
|
||||
}
|
||||
|
||||
public function getPropertyId() : int {
|
||||
return (TimelineType.attachment.ordinal << 24) + slotIndex;
|
||||
}
|
||||
|
||||
/** Sets the time and value of the specified keyframe. */
|
||||
public function setFrame(frameIndex : int, time : Number, attachmentName : String) : void {
|
||||
frames[frameIndex] = time;
|
||||
attachmentNames[frameIndex] = attachmentName;
|
||||
}
|
||||
|
||||
public function apply(skeleton : Skeleton, lastTime : Number, time : Number, firedEvents : Vector.<Event>, alpha : Number, setupPose : Boolean, mixingOut : Boolean) : void {
|
||||
var attachmentName : String;
|
||||
var slot : Slot = skeleton.slots[slotIndex];
|
||||
if (mixingOut && setupPose) {
|
||||
attachmentName = slot.data.attachmentName;
|
||||
slot.attachment = attachmentName == null ? null : skeleton.getAttachmentForSlotIndex(slotIndex, attachmentName);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
var frames : Vector.<Number> = this.frames;
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) {
|
||||
attachmentName = slot.data.attachmentName;
|
||||
slot.attachment = attachmentName == null ? null : skeleton.getAttachmentForSlotIndex(slotIndex, attachmentName);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var frameIndex : int;
|
||||
if (time >= frames[frames.length - 1]) // Time is after last frame.
|
||||
frameIndex = frames.length - 1;
|
||||
else
|
||||
frameIndex = Animation.binarySearch(frames, time, 1) - 1;
|
||||
|
||||
attachmentName = attachmentNames[frameIndex];
|
||||
skeleton.slots[slotIndex].attachment = attachmentName == null ? null : skeleton.getAttachmentForSlotIndex(slotIndex, attachmentName);
|
||||
}
|
||||
|
||||
var frameIndex:int;
|
||||
if (time >= frames[frames.length - 1]) // Time is after last frame.
|
||||
frameIndex = frames.length - 1;
|
||||
else
|
||||
frameIndex = Animation.binarySearch(frames, time, 1) - 1;
|
||||
|
||||
attachmentName = attachmentNames[frameIndex];
|
||||
skeleton.slots[slotIndex].attachment = attachmentName == null ? null : skeleton.getAttachmentForSlotIndex(slotIndex, attachmentName);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,83 +29,80 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.animation {
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
import spine.Slot;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
import spine.Slot;
|
||||
|
||||
public class ColorTimeline extends CurveTimeline {
|
||||
static public const ENTRIES:int = 5;
|
||||
static internal const PREV_TIME:int = -5, PREV_R:int = -4, PREV_G:int = -3, PREV_B:int = -2, PREV_A:int = -1;
|
||||
static internal const R:int = 1, G:int = 2, B:int = 3, A:int = 4;
|
||||
public class ColorTimeline extends CurveTimeline {
|
||||
static public const ENTRIES : int = 5;
|
||||
static internal const PREV_TIME : int = -5, PREV_R : int = -4, PREV_G : int = -3, PREV_B : int = -2, PREV_A : int = -1;
|
||||
static internal const R : int = 1, G : int = 2, B : int = 3, A : int = 4;
|
||||
public var slotIndex : int;
|
||||
public var frames : Vector.<Number>; // time, r, g, b, a, ...
|
||||
|
||||
public var slotIndex:int;
|
||||
public var frames:Vector.<Number>; // time, r, g, b, a, ...
|
||||
|
||||
public function ColorTimeline (frameCount:int) {
|
||||
super(frameCount);
|
||||
frames = new Vector.<Number>(frameCount * 5, true);
|
||||
}
|
||||
|
||||
override public function getPropertyId () : int {
|
||||
return (TimelineType.color.ordinal << 24) + slotIndex;
|
||||
}
|
||||
|
||||
/** Sets the time and value of the specified keyframe. */
|
||||
public function setFrame (frameIndex:int, time:Number, r:Number, g:Number, b:Number, a:Number) : void {
|
||||
frameIndex *= ENTRIES;
|
||||
frames[frameIndex] = time;
|
||||
frames[int(frameIndex + R)] = r;
|
||||
frames[int(frameIndex + G)] = g;
|
||||
frames[int(frameIndex + B)] = b;
|
||||
frames[int(frameIndex + A)] = a;
|
||||
}
|
||||
|
||||
override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector.<Event>, alpha:Number, setupPose:Boolean, mixingOut:Boolean) : void {
|
||||
var frames:Vector.<Number> = this.frames;
|
||||
var slot:Slot = skeleton.slots[slotIndex];
|
||||
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) {
|
||||
slot.color.setFromColor(slot.data.color);
|
||||
}
|
||||
return;
|
||||
public function ColorTimeline(frameCount : int) {
|
||||
super(frameCount);
|
||||
frames = new Vector.<Number>(frameCount * 5, true);
|
||||
}
|
||||
|
||||
var r:Number, g:Number, b:Number, a:Number;
|
||||
if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame.
|
||||
var i:int = frames.length;
|
||||
r = frames[i + PREV_R];
|
||||
g = frames[i + PREV_G];
|
||||
b = frames[i + PREV_B];
|
||||
a = frames[i + PREV_A];
|
||||
} else {
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
var frame:int = Animation.binarySearch(frames, time, ENTRIES);
|
||||
r = frames[frame + PREV_R];
|
||||
g = frames[frame + PREV_G];
|
||||
b = frames[frame + PREV_B];
|
||||
a = frames[frame + PREV_A];
|
||||
var frameTime:Number = frames[frame];
|
||||
var percent:Number = getCurvePercent(frame / ENTRIES - 1,
|
||||
1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
override public function getPropertyId() : int {
|
||||
return (TimelineType.color.ordinal << 24) + slotIndex;
|
||||
}
|
||||
|
||||
r += (frames[frame + R] - r) * percent;
|
||||
g += (frames[frame + G] - g) * percent;
|
||||
b += (frames[frame + B] - b) * percent;
|
||||
a += (frames[frame + A] - a) * percent;
|
||||
}
|
||||
if (alpha == 1) {
|
||||
slot.color.setFrom(r, g, b, a);
|
||||
} else {
|
||||
if (setupPose) {
|
||||
slot.color.setFromColor(slot.data.color);
|
||||
/** Sets the time and value of the specified keyframe. */
|
||||
public function setFrame(frameIndex : int, time : Number, r : Number, g : Number, b : Number, a : Number) : void {
|
||||
frameIndex *= ENTRIES;
|
||||
frames[frameIndex] = time;
|
||||
frames[int(frameIndex + R)] = r;
|
||||
frames[int(frameIndex + G)] = g;
|
||||
frames[int(frameIndex + B)] = b;
|
||||
frames[int(frameIndex + A)] = a;
|
||||
}
|
||||
|
||||
override public function apply(skeleton : Skeleton, lastTime : Number, time : Number, firedEvents : Vector.<Event>, alpha : Number, setupPose : Boolean, mixingOut : Boolean) : void {
|
||||
var frames : Vector.<Number> = this.frames;
|
||||
var slot : Slot = skeleton.slots[slotIndex];
|
||||
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) {
|
||||
slot.color.setFromColor(slot.data.color);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var r : Number, g : Number, b : Number, a : Number;
|
||||
if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame.
|
||||
var i : int = frames.length;
|
||||
r = frames[i + PREV_R];
|
||||
g = frames[i + PREV_G];
|
||||
b = frames[i + PREV_B];
|
||||
a = frames[i + PREV_A];
|
||||
} else {
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
var frame : int = Animation.binarySearch(frames, time, ENTRIES);
|
||||
r = frames[frame + PREV_R];
|
||||
g = frames[frame + PREV_G];
|
||||
b = frames[frame + PREV_B];
|
||||
a = frames[frame + PREV_A];
|
||||
var frameTime : Number = frames[frame];
|
||||
var percent : Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
|
||||
r += (frames[frame + R] - r) * percent;
|
||||
g += (frames[frame + G] - g) * percent;
|
||||
b += (frames[frame + B] - b) * percent;
|
||||
a += (frames[frame + A] - a) * percent;
|
||||
}
|
||||
if (alpha == 1) {
|
||||
slot.color.setFrom(r, g, b, a);
|
||||
} else {
|
||||
if (setupPose) {
|
||||
slot.color.setFromColor(slot.data.color);
|
||||
}
|
||||
slot.color.r += (r - slot.color.r) * alpha;
|
||||
slot.color.g += (g - slot.color.g) * alpha;
|
||||
slot.color.b += (b - slot.color.b) * alpha;
|
||||
slot.color.a += (a - slot.color.a) * alpha;
|
||||
}
|
||||
slot.color.r += (r - slot.color.r) * alpha;
|
||||
slot.color.g += (g - slot.color.g) * alpha;
|
||||
slot.color.b += (b - slot.color.b) * alpha;
|
||||
slot.color.a += (a - slot.color.a) * alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -30,93 +30,91 @@
|
||||
|
||||
package spine.animation {
|
||||
import spine.MathUtils;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
|
||||
/** Base class for frames that use an interpolation bezier curve. */
|
||||
public class CurveTimeline implements Timeline {
|
||||
static private const LINEAR:Number = 0;
|
||||
static private const STEPPED:Number = 1;
|
||||
static private const BEZIER:Number = 2;
|
||||
static private const BEZIER_SIZE:int = 10 * 2 - 1;
|
||||
/** Base class for frames that use an interpolation bezier curve. */
|
||||
public class CurveTimeline implements Timeline {
|
||||
static private const LINEAR : Number = 0;
|
||||
static private const STEPPED : Number = 1;
|
||||
static private const BEZIER : Number = 2;
|
||||
static private const BEZIER_SIZE : int = 10 * 2 - 1;
|
||||
private var curves : Vector.<Number>; // type, x, y, ...
|
||||
|
||||
private var curves:Vector.<Number>; // type, x, y, ...
|
||||
|
||||
public function CurveTimeline (frameCount:int) {
|
||||
curves = new Vector.<Number>((frameCount - 1) * BEZIER_SIZE, true);
|
||||
}
|
||||
|
||||
public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector.<Event>, alpha:Number, setupPose:Boolean, mixingOut:Boolean) : void {
|
||||
}
|
||||
|
||||
public function getPropertyId () : int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function get frameCount () : int {
|
||||
return curves.length / BEZIER_SIZE + 1;
|
||||
}
|
||||
|
||||
public function setLinear (frameIndex:int) : void {
|
||||
curves[int(frameIndex * BEZIER_SIZE)] = LINEAR;
|
||||
}
|
||||
|
||||
public function setStepped (frameIndex:int) : void {
|
||||
curves[int(frameIndex * BEZIER_SIZE)] = STEPPED;
|
||||
}
|
||||
|
||||
/** Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next.
|
||||
* cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of
|
||||
* the difference between the keyframe's values. */
|
||||
public function setCurve (frameIndex:int, cx1:Number, cy1:Number, cx2:Number, cy2:Number) : void {
|
||||
var tmpx:Number = (-cx1 * 2 + cx2) * 0.03, tmpy:Number = (-cy1 * 2 + cy2) * 0.03;
|
||||
var dddfx:Number = ((cx1 - cx2) * 3 + 1) * 0.006, dddfy:Number = ((cy1 - cy2) * 3 + 1) * 0.006;
|
||||
var ddfx:Number = tmpx * 2 + dddfx, ddfy:Number = tmpy * 2 + dddfy;
|
||||
var dfx:Number = cx1 * 0.3 + tmpx + dddfx * 0.16666667, dfy:Number = cy1 * 0.3 + tmpy + dddfy * 0.16666667;
|
||||
|
||||
var i:int = frameIndex * BEZIER_SIZE;
|
||||
var curves:Vector.<Number> = this.curves;
|
||||
curves[int(i++)] = BEZIER;
|
||||
|
||||
var x:Number = dfx, y:Number = dfy;
|
||||
for (var n:int = i + BEZIER_SIZE - 1; i < n; i += 2) {
|
||||
curves[i] = x;
|
||||
curves[int(i + 1)] = y;
|
||||
dfx += ddfx;
|
||||
dfy += ddfy;
|
||||
ddfx += dddfx;
|
||||
ddfy += dddfy;
|
||||
x += dfx;
|
||||
y += dfy;
|
||||
public function CurveTimeline(frameCount : int) {
|
||||
curves = new Vector.<Number>((frameCount - 1) * BEZIER_SIZE, true);
|
||||
}
|
||||
}
|
||||
|
||||
public function getCurvePercent (frameIndex:int, percent:Number) : Number {
|
||||
percent = MathUtils.clamp(percent, 0, 1);
|
||||
var curves:Vector.<Number> = this.curves;
|
||||
var i:int = frameIndex * BEZIER_SIZE;
|
||||
var type:Number = curves[i];
|
||||
if (type == LINEAR) return percent;
|
||||
if (type == STEPPED) return 0;
|
||||
i++;
|
||||
var x:Number = 0;
|
||||
for (var start:int = i, n:int = i + BEZIER_SIZE - 1; i < n; i += 2) {
|
||||
x = curves[i];
|
||||
if (x >= percent) {
|
||||
var prevX:Number, prevY:Number;
|
||||
if (i == start) {
|
||||
prevX = 0;
|
||||
prevY = 0;
|
||||
} else {
|
||||
prevX = curves[int(i - 2)];
|
||||
prevY = curves[int(i - 1)];
|
||||
}
|
||||
return prevY + (curves[int(i + 1)] - prevY) * (percent - prevX) / (x - prevX);
|
||||
public function apply(skeleton : Skeleton, lastTime : Number, time : Number, firedEvents : Vector.<Event>, alpha : Number, setupPose : Boolean, mixingOut : Boolean) : void {
|
||||
}
|
||||
|
||||
public function getPropertyId() : int {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public function get frameCount() : int {
|
||||
return curves.length / BEZIER_SIZE + 1;
|
||||
}
|
||||
|
||||
public function setLinear(frameIndex : int) : void {
|
||||
curves[int(frameIndex * BEZIER_SIZE)] = LINEAR;
|
||||
}
|
||||
|
||||
public function setStepped(frameIndex : int) : void {
|
||||
curves[int(frameIndex * BEZIER_SIZE)] = STEPPED;
|
||||
}
|
||||
|
||||
/** Sets the control handle positions for an interpolation bezier curve used to transition from this keyframe to the next.
|
||||
* cx1 and cx2 are from 0 to 1, representing the percent of time between the two keyframes. cy1 and cy2 are the percent of
|
||||
* the difference between the keyframe's values. */
|
||||
public function setCurve(frameIndex : int, cx1 : Number, cy1 : Number, cx2 : Number, cy2 : Number) : void {
|
||||
var tmpx : Number = (-cx1 * 2 + cx2) * 0.03, tmpy : Number = (-cy1 * 2 + cy2) * 0.03;
|
||||
var dddfx : Number = ((cx1 - cx2) * 3 + 1) * 0.006, dddfy : Number = ((cy1 - cy2) * 3 + 1) * 0.006;
|
||||
var ddfx : Number = tmpx * 2 + dddfx, ddfy : Number = tmpy * 2 + dddfy;
|
||||
var dfx : Number = cx1 * 0.3 + tmpx + dddfx * 0.16666667, dfy : Number = cy1 * 0.3 + tmpy + dddfy * 0.16666667;
|
||||
|
||||
var i : int = frameIndex * BEZIER_SIZE;
|
||||
var curves : Vector.<Number> = this.curves;
|
||||
curves[int(i++)] = BEZIER;
|
||||
|
||||
var x : Number = dfx, y : Number = dfy;
|
||||
for (var n : int = i + BEZIER_SIZE - 1; i < n; i += 2) {
|
||||
curves[i] = x;
|
||||
curves[int(i + 1)] = y;
|
||||
dfx += ddfx;
|
||||
dfy += ddfy;
|
||||
ddfx += dddfx;
|
||||
ddfy += dddfy;
|
||||
x += dfx;
|
||||
y += dfy;
|
||||
}
|
||||
}
|
||||
var y:Number = curves[int(i - 1)];
|
||||
return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1.
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public function getCurvePercent(frameIndex : int, percent : Number) : Number {
|
||||
percent = MathUtils.clamp(percent, 0, 1);
|
||||
var curves : Vector.<Number> = this.curves;
|
||||
var i : int = frameIndex * BEZIER_SIZE;
|
||||
var type : Number = curves[i];
|
||||
if (type == LINEAR) return percent;
|
||||
if (type == STEPPED) return 0;
|
||||
i++;
|
||||
var x : Number = 0;
|
||||
for (var start : int = i, n : int = i + BEZIER_SIZE - 1; i < n; i += 2) {
|
||||
x = curves[i];
|
||||
if (x >= percent) {
|
||||
var prevX : Number, prevY : Number;
|
||||
if (i == start) {
|
||||
prevX = 0;
|
||||
prevY = 0;
|
||||
} else {
|
||||
prevX = curves[int(i - 2)];
|
||||
prevY = curves[int(i - 1)];
|
||||
}
|
||||
return prevY + (curves[int(i + 1)] - prevY) * (percent - prevX) / (x - prevX);
|
||||
}
|
||||
}
|
||||
var y : Number = curves[int(i - 1)];
|
||||
return y + (1 - y) * (percent - x) / (1 - x); // Last point is 1,1.
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -29,123 +29,122 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.animation {
|
||||
import spine.attachments.Attachment;
|
||||
import spine.attachments.VertexAttachment;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
import spine.Slot;
|
||||
import spine.attachments.Attachment;
|
||||
import spine.attachments.VertexAttachment;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
import spine.Slot;
|
||||
|
||||
public class DeformTimeline extends CurveTimeline {
|
||||
public var slotIndex:int;
|
||||
public var frames:Vector.<Number>;
|
||||
public var frameVertices:Vector.<Vector.<Number>>;
|
||||
public var attachment:VertexAttachment;
|
||||
public class DeformTimeline extends CurveTimeline {
|
||||
public var slotIndex : int;
|
||||
public var frames : Vector.<Number>;
|
||||
public var frameVertices : Vector.<Vector.<Number>>;
|
||||
public var attachment : VertexAttachment;
|
||||
|
||||
public function DeformTimeline (frameCount:int) {
|
||||
super(frameCount);
|
||||
frames = new Vector.<Number>(frameCount, true);
|
||||
frameVertices = new Vector.<Vector.<Number>>(frameCount, true);
|
||||
}
|
||||
|
||||
override public function getPropertyId () : int {
|
||||
return (TimelineType.deform.ordinal << 24) + slotIndex;
|
||||
}
|
||||
|
||||
/** Sets the time and value of the specified keyframe. */
|
||||
public function setFrame (frameIndex:int, time:Number, vertices:Vector.<Number>) : void {
|
||||
frames[frameIndex] = time;
|
||||
frameVertices[frameIndex] = vertices;
|
||||
}
|
||||
|
||||
override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector.<Event>, alpha:Number, setupPose:Boolean, mixingOut:Boolean) : void {
|
||||
var slot:Slot = skeleton.slots[slotIndex];
|
||||
var slotAttachment:Attachment = slot.attachment;
|
||||
if (!(slotAttachment is VertexAttachment) || !(VertexAttachment(slotAttachment)).applyDeform(attachment)) return;
|
||||
|
||||
var frames:Vector.<Number> = this.frames;
|
||||
var verticesArray:Vector.<Number> = slot.attachmentVertices;
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) verticesArray.length = 0;
|
||||
return;
|
||||
public function DeformTimeline(frameCount : int) {
|
||||
super(frameCount);
|
||||
frames = new Vector.<Number>(frameCount, true);
|
||||
frameVertices = new Vector.<Vector.<Number>>(frameCount, true);
|
||||
}
|
||||
|
||||
var frameVertices:Vector.<Vector.<Number>> = this.frameVertices;
|
||||
var vertexCount:int = frameVertices[0].length;
|
||||
|
||||
if (verticesArray.length != vertexCount) alpha = 1; // Don't mix from uninitialized slot vertices.
|
||||
verticesArray.length = vertexCount;
|
||||
var vertices:Vector.<Number> = verticesArray;
|
||||
override public function getPropertyId() : int {
|
||||
return (TimelineType.deform.ordinal << 24) + slotIndex;
|
||||
}
|
||||
|
||||
/** Sets the time and value of the specified keyframe. */
|
||||
public function setFrame(frameIndex : int, time : Number, vertices : Vector.<Number>) : void {
|
||||
frames[frameIndex] = time;
|
||||
frameVertices[frameIndex] = vertices;
|
||||
}
|
||||
|
||||
override public function apply(skeleton : Skeleton, lastTime : Number, time : Number, firedEvents : Vector.<Event>, alpha : Number, setupPose : Boolean, mixingOut : Boolean) : void {
|
||||
var slot : Slot = skeleton.slots[slotIndex];
|
||||
var slotAttachment : Attachment = slot.attachment;
|
||||
if (!(slotAttachment is VertexAttachment) || !(VertexAttachment(slotAttachment)).applyDeform(attachment)) return;
|
||||
|
||||
var frames : Vector.<Number> = this.frames;
|
||||
var verticesArray : Vector.<Number> = slot.attachmentVertices;
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) verticesArray.length = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
var frameVertices : Vector.<Vector.<Number>> = this.frameVertices;
|
||||
var vertexCount : int = frameVertices[0].length;
|
||||
|
||||
if (verticesArray.length != vertexCount) alpha = 1; // Don't mix from uninitialized slot vertices.
|
||||
verticesArray.length = vertexCount;
|
||||
var vertices : Vector.<Number> = verticesArray;
|
||||
|
||||
var i : int, n : int;
|
||||
var vertexAttachment : VertexAttachment;
|
||||
var setupVertices : Vector.<Number>;
|
||||
var setup : Number, prev : Number;
|
||||
if (time >= frames[frames.length - 1]) { // Time is after last frame.
|
||||
var lastVertices : Vector.<Number> = frameVertices[frames.length - 1];
|
||||
if (alpha == 1) {
|
||||
// Vertex positions or deform offsets, no alpha.
|
||||
for (i = 0, n = vertexCount; i < n; i++)
|
||||
vertices[i] = lastVertices[i];
|
||||
} else if (setupPose) {
|
||||
vertexAttachment = VertexAttachment(slotAttachment);
|
||||
if (vertexAttachment.bones == null) {
|
||||
// Unweighted vertex positions, with alpha.
|
||||
setupVertices = vertexAttachment.vertices;
|
||||
for (i = 0; i < vertexCount; i++) {
|
||||
setup = setupVertices[i];
|
||||
vertices[i] = setup + (lastVertices[i] - setup) * alpha;
|
||||
}
|
||||
} else {
|
||||
// Weighted deform offsets, with alpha.
|
||||
for (i = 0; i < vertexCount; i++)
|
||||
vertices[i] = lastVertices[i] * alpha;
|
||||
}
|
||||
} else {
|
||||
// Vertex positions or deform offsets, with alpha.
|
||||
for (i = 0; i < vertexCount; i++)
|
||||
vertices[i] += (lastVertices[i] - vertices[i]) * alpha;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
var frame : int = Animation.binarySearch1(frames, time);
|
||||
var prevVertices : Vector.<Number> = frameVertices[frame - 1];
|
||||
var nextVertices : Vector.<Number> = frameVertices[frame];
|
||||
var frameTime : Number = frames[frame];
|
||||
var percent : Number = getCurvePercent(frame - 1, 1 - (time - frameTime) / (frames[frame - 1] - frameTime));
|
||||
|
||||
var i:int, n:int;
|
||||
var vertexAttachment:VertexAttachment;
|
||||
var setupVertices:Vector.<Number>;
|
||||
var setup:Number, prev:Number;
|
||||
if (time >= frames[frames.length - 1]) { // Time is after last frame.
|
||||
var lastVertices:Vector.<Number> = frameVertices[frames.length - 1];
|
||||
if (alpha == 1) {
|
||||
// Vertex positions or deform offsets, no alpha.
|
||||
for (i = 0, n = vertexCount; i < n; i++)
|
||||
vertices[i] = lastVertices[i];
|
||||
for (i = 0; i < vertexCount; i++) {
|
||||
prev = prevVertices[i];
|
||||
vertices[i] = prev + (nextVertices[i] - prev) * percent;
|
||||
}
|
||||
} else if (setupPose) {
|
||||
vertexAttachment = VertexAttachment(slotAttachment);
|
||||
if (vertexAttachment.bones == null) {
|
||||
// Unweighted vertex positions, with alpha.
|
||||
setupVertices = vertexAttachment.vertices;
|
||||
for (i = 0; i < vertexCount; i++) {
|
||||
prev = prevVertices[i];
|
||||
setup = setupVertices[i];
|
||||
vertices[i] = setup + (lastVertices[i] - setup) * alpha;
|
||||
vertices[i] = setup + (prev + (nextVertices[i] - prev) * percent - setup) * alpha;
|
||||
}
|
||||
} else {
|
||||
// Weighted deform offsets, with alpha.
|
||||
for (i = 0; i < vertexCount; i++)
|
||||
vertices[i] = lastVertices[i] * alpha;
|
||||
for (i = 0; i < vertexCount; i++) {
|
||||
prev = prevVertices[i];
|
||||
vertices[i] = (prev + (nextVertices[i] - prev) * percent) * alpha;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Vertex positions or deform offsets, with alpha.
|
||||
for (i = 0; i < vertexCount; i++)
|
||||
vertices[i] += (lastVertices[i] - vertices[i]) * alpha;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
var frame:int = Animation.binarySearch1(frames, time);
|
||||
var prevVertices:Vector.<Number> = frameVertices[frame - 1];
|
||||
var nextVertices:Vector.<Number> = frameVertices[frame];
|
||||
var frameTime:Number = frames[frame];
|
||||
var percent:Number = getCurvePercent(frame - 1, 1 - (time - frameTime) / (frames[frame - 1] - frameTime));
|
||||
|
||||
if (alpha == 1) {
|
||||
// Vertex positions or deform offsets, no alpha.
|
||||
for (i = 0; i < vertexCount; i++) {
|
||||
prev = prevVertices[i];
|
||||
vertices[i] = prev + (nextVertices[i] - prev) * percent;
|
||||
}
|
||||
} else if (setupPose) {
|
||||
vertexAttachment = VertexAttachment(slotAttachment);
|
||||
if (vertexAttachment.bones == null) {
|
||||
// Unweighted vertex positions, with alpha.
|
||||
setupVertices = vertexAttachment.vertices;
|
||||
for (i = 0; i < vertexCount; i++) {
|
||||
prev = prevVertices[i];
|
||||
setup = setupVertices[i];
|
||||
vertices[i] = setup + (prev + (nextVertices[i] - prev) * percent - setup) * alpha;
|
||||
vertices[i] += (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha;
|
||||
}
|
||||
} else {
|
||||
// Weighted deform offsets, with alpha.
|
||||
for (i = 0; i < vertexCount; i++) {
|
||||
prev = prevVertices[i];
|
||||
vertices[i] = (prev + (nextVertices[i] - prev) * percent) * alpha;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Vertex positions or deform offsets, with alpha.
|
||||
for (i = 0; i < vertexCount; i++) {
|
||||
prev = prevVertices[i];
|
||||
vertices[i] += (prev + (nextVertices[i] - prev) * percent - vertices[i]) * alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,68 +29,67 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.animation {
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
import spine.Slot;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
import spine.Slot;
|
||||
|
||||
public class DrawOrderTimeline implements Timeline {
|
||||
public var frames:Vector.<Number>; // time, ...
|
||||
public var drawOrders:Vector.<Vector.<int>>;
|
||||
public class DrawOrderTimeline implements Timeline {
|
||||
public var frames : Vector.<Number>; // time, ...
|
||||
public var drawOrders : Vector.<Vector.<int>>;
|
||||
|
||||
public function DrawOrderTimeline (frameCount:int) {
|
||||
frames = new Vector.<Number>(frameCount, true);
|
||||
drawOrders = new Vector.<Vector.<int>>(frameCount, true);
|
||||
}
|
||||
|
||||
public function get frameCount () : int {
|
||||
return frames.length;
|
||||
}
|
||||
|
||||
public function getPropertyId () : int {
|
||||
return TimelineType.drawOrder.ordinal << 24;
|
||||
}
|
||||
|
||||
/** Sets the time and value of the specified keyframe. */
|
||||
public function setFrame (frameIndex:int, time:Number, drawOrder:Vector.<int>) : void {
|
||||
frames[frameIndex] = time;
|
||||
drawOrders[frameIndex] = drawOrder;
|
||||
}
|
||||
|
||||
public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector.<Event>, alpha:Number, setupPose:Boolean, mixingOut:Boolean) : void {
|
||||
if (mixingOut && setupPose) {
|
||||
for (var ii:int = 0, n:int = skeleton.slots.length; ii < n; ii++)
|
||||
skeleton.drawOrder[ii] = skeleton.slots[ii];
|
||||
return;
|
||||
public function DrawOrderTimeline(frameCount : int) {
|
||||
frames = new Vector.<Number>(frameCount, true);
|
||||
drawOrders = new Vector.<Vector.<int>>(frameCount, true);
|
||||
}
|
||||
|
||||
var drawOrder:Vector.<Slot> = skeleton.drawOrder;
|
||||
var slots:Vector.<Slot> = skeleton.slots;
|
||||
var slot:Slot;
|
||||
var i:int = 0;
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) {
|
||||
for each (slot in slots)
|
||||
drawOrder[i++] = slot;
|
||||
public function get frameCount() : int {
|
||||
return frames.length;
|
||||
}
|
||||
|
||||
public function getPropertyId() : int {
|
||||
return TimelineType.drawOrder.ordinal << 24;
|
||||
}
|
||||
|
||||
/** Sets the time and value of the specified keyframe. */
|
||||
public function setFrame(frameIndex : int, time : Number, drawOrder : Vector.<int>) : void {
|
||||
frames[frameIndex] = time;
|
||||
drawOrders[frameIndex] = drawOrder;
|
||||
}
|
||||
|
||||
public function apply(skeleton : Skeleton, lastTime : Number, time : Number, firedEvents : Vector.<Event>, alpha : Number, setupPose : Boolean, mixingOut : Boolean) : void {
|
||||
if (mixingOut && setupPose) {
|
||||
for (var ii : int = 0, n : int = skeleton.slots.length; ii < n; ii++)
|
||||
skeleton.drawOrder[ii] = skeleton.slots[ii];
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var frameIndex:int;
|
||||
if (time >= frames[int(frames.length - 1)]) // Time is after last frame.
|
||||
frameIndex = frames.length - 1;
|
||||
else
|
||||
frameIndex = Animation.binarySearch1(frames, time) - 1;
|
||||
var drawOrder : Vector.<Slot> = skeleton.drawOrder;
|
||||
var slots : Vector.<Slot> = skeleton.slots;
|
||||
var slot : Slot;
|
||||
var i : int = 0;
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) {
|
||||
for each (slot in slots)
|
||||
drawOrder[i++] = slot;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var drawOrderToSetupIndex:Vector.<int> = drawOrders[frameIndex];
|
||||
i = 0;
|
||||
if (!drawOrderToSetupIndex) {
|
||||
for each (slot in slots)
|
||||
drawOrder[i++] = slot;
|
||||
} else {
|
||||
for each (var setupIndex:int in drawOrderToSetupIndex)
|
||||
drawOrder[i++] = slots[setupIndex];
|
||||
var frameIndex : int;
|
||||
if (time >= frames[int(frames.length - 1)]) // Time is after last frame.
|
||||
frameIndex = frames.length - 1;
|
||||
else
|
||||
frameIndex = Animation.binarySearch1(frames, time) - 1;
|
||||
|
||||
var drawOrderToSetupIndex : Vector.<int> = drawOrders[frameIndex];
|
||||
i = 0;
|
||||
if (!drawOrderToSetupIndex) {
|
||||
for each (slot in slots)
|
||||
drawOrder[i++] = slot;
|
||||
} else {
|
||||
for each (var setupIndex : int in drawOrderToSetupIndex)
|
||||
drawOrder[i++] = slots[setupIndex];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,94 +29,94 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.animation {
|
||||
import spine.Event;
|
||||
import spine.Event;
|
||||
|
||||
public class EventQueue {
|
||||
internal var objects:Vector.<Object> = new Vector.<Object>();
|
||||
internal var animationState:AnimationState;
|
||||
public var drainDisabled:Boolean;
|
||||
public class EventQueue {
|
||||
internal var objects : Vector.<Object> = new Vector.<Object>();
|
||||
internal var animationState : AnimationState;
|
||||
public var drainDisabled : Boolean;
|
||||
|
||||
public function EventQueue(animationState:AnimationState) {
|
||||
this.animationState = animationState;
|
||||
}
|
||||
|
||||
public function start (entry:TrackEntry):void {
|
||||
objects.push(EventType.start);
|
||||
objects.push(entry);
|
||||
animationState.animationsChanged = true;
|
||||
}
|
||||
|
||||
public function interrupt (entry:TrackEntry):void {
|
||||
objects.push(EventType.interrupt);
|
||||
objects.push(entry);
|
||||
}
|
||||
|
||||
public function end (entry:TrackEntry):void {
|
||||
objects.push(EventType.end);
|
||||
objects.push(entry);
|
||||
animationState.animationsChanged = true;
|
||||
}
|
||||
|
||||
public function dispose (entry:TrackEntry):void {
|
||||
objects.push(EventType.dispose);
|
||||
objects.push(entry);
|
||||
}
|
||||
|
||||
public function complete (entry:TrackEntry):void {
|
||||
objects.push(EventType.complete);
|
||||
objects.push(entry);
|
||||
}
|
||||
|
||||
public function event (entry:TrackEntry, event:Event):void {
|
||||
objects.push(EventType.event);
|
||||
objects.push(entry);
|
||||
objects.push(event);
|
||||
}
|
||||
|
||||
public function drain ():void {
|
||||
if (drainDisabled) return; // Not reentrant.
|
||||
drainDisabled = true;
|
||||
|
||||
var objects:Vector.<Object> = this.objects;
|
||||
for (var i:int = 0; i < objects.length; i += 2) {
|
||||
var type:EventType = EventType(objects[i]);
|
||||
var entry:TrackEntry = TrackEntry(objects[i + 1]);
|
||||
switch (type) {
|
||||
case EventType.start:
|
||||
entry.onStart.invoke(entry);
|
||||
animationState.onStart.invoke(entry);
|
||||
break;
|
||||
case EventType.interrupt:
|
||||
entry.onInterrupt.invoke(entry);
|
||||
animationState.onInterrupt.invoke(entry);
|
||||
break;
|
||||
case EventType.end:
|
||||
entry.onEnd.invoke(entry);
|
||||
animationState.onEnd.invoke(entry);
|
||||
// Fall through.
|
||||
case EventType.dispose:
|
||||
entry.onDispose.invoke(entry);
|
||||
animationState.onDispose.invoke(entry);
|
||||
animationState.trackEntryPool.free(entry);
|
||||
break;
|
||||
case EventType.complete:
|
||||
entry.onComplete.invoke(entry);
|
||||
animationState.onComplete.invoke(entry);
|
||||
break;
|
||||
case EventType.event:
|
||||
var event:Event = Event(objects[i++ + 2]);
|
||||
entry.onEvent.invoke(entry, event);
|
||||
animationState.onEvent.invoke(entry, event);
|
||||
break;
|
||||
}
|
||||
public function EventQueue(animationState : AnimationState) {
|
||||
this.animationState = animationState;
|
||||
}
|
||||
clear();
|
||||
|
||||
drainDisabled = false;
|
||||
}
|
||||
public function start(entry : TrackEntry) : void {
|
||||
objects.push(EventType.start);
|
||||
objects.push(entry);
|
||||
animationState.animationsChanged = true;
|
||||
}
|
||||
|
||||
public function clear ():void {
|
||||
objects.length = 0;
|
||||
public function interrupt(entry : TrackEntry) : void {
|
||||
objects.push(EventType.interrupt);
|
||||
objects.push(entry);
|
||||
}
|
||||
|
||||
public function end(entry : TrackEntry) : void {
|
||||
objects.push(EventType.end);
|
||||
objects.push(entry);
|
||||
animationState.animationsChanged = true;
|
||||
}
|
||||
|
||||
public function dispose(entry : TrackEntry) : void {
|
||||
objects.push(EventType.dispose);
|
||||
objects.push(entry);
|
||||
}
|
||||
|
||||
public function complete(entry : TrackEntry) : void {
|
||||
objects.push(EventType.complete);
|
||||
objects.push(entry);
|
||||
}
|
||||
|
||||
public function event(entry : TrackEntry, event : Event) : void {
|
||||
objects.push(EventType.event);
|
||||
objects.push(entry);
|
||||
objects.push(event);
|
||||
}
|
||||
|
||||
public function drain() : void {
|
||||
if (drainDisabled) return; // Not reentrant.
|
||||
drainDisabled = true;
|
||||
|
||||
var objects : Vector.<Object> = this.objects;
|
||||
for (var i : int = 0; i < objects.length; i += 2) {
|
||||
var type : EventType = EventType(objects[i]);
|
||||
var entry : TrackEntry = TrackEntry(objects[i + 1]);
|
||||
switch (type) {
|
||||
case EventType.start:
|
||||
entry.onStart.invoke(entry);
|
||||
animationState.onStart.invoke(entry);
|
||||
break;
|
||||
case EventType.interrupt:
|
||||
entry.onInterrupt.invoke(entry);
|
||||
animationState.onInterrupt.invoke(entry);
|
||||
break;
|
||||
case EventType.end:
|
||||
entry.onEnd.invoke(entry);
|
||||
animationState.onEnd.invoke(entry);
|
||||
// Fall through.
|
||||
case EventType.dispose:
|
||||
entry.onDispose.invoke(entry);
|
||||
animationState.onDispose.invoke(entry);
|
||||
animationState.trackEntryPool.free(entry);
|
||||
break;
|
||||
case EventType.complete:
|
||||
entry.onComplete.invoke(entry);
|
||||
animationState.onComplete.invoke(entry);
|
||||
break;
|
||||
case EventType.event:
|
||||
var event : Event = Event(objects[i++ + 2]);
|
||||
entry.onEvent.invoke(entry, event);
|
||||
animationState.onEvent.invoke(entry, event);
|
||||
break;
|
||||
}
|
||||
}
|
||||
clear();
|
||||
|
||||
drainDisabled = false;
|
||||
}
|
||||
|
||||
public function clear() : void {
|
||||
objects.length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -29,57 +29,56 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.animation {
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
|
||||
public class EventTimeline implements Timeline {
|
||||
public var frames:Vector.<Number>; // time, ...
|
||||
public var events:Vector.<Event>;
|
||||
public class EventTimeline implements Timeline {
|
||||
public var frames : Vector.<Number>; // time, ...
|
||||
public var events : Vector.<Event>;
|
||||
|
||||
public function EventTimeline (frameCount:int) {
|
||||
frames = new Vector.<Number>(frameCount, true);
|
||||
events = new Vector.<Event>(frameCount, true);
|
||||
}
|
||||
|
||||
public function get frameCount () : int {
|
||||
return frames.length;
|
||||
}
|
||||
|
||||
public function getPropertyId () : int {
|
||||
return TimelineType.event.ordinal << 24;
|
||||
}
|
||||
|
||||
/** Sets the time and value of the specified keyframe. */
|
||||
public function setFrame (frameIndex:int, event:Event) : void {
|
||||
frames[frameIndex] = event.time;
|
||||
events[frameIndex] = event;
|
||||
}
|
||||
|
||||
/** Fires events for frames > lastTime and <= time. */
|
||||
public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector.<Event>, alpha:Number, setupPose:Boolean, mixingOut:Boolean) : void {
|
||||
if (!firedEvents) return;
|
||||
|
||||
if (lastTime > time) { // Fire events after last time for looped animations.
|
||||
apply(skeleton, lastTime, int.MAX_VALUE, firedEvents, alpha, setupPose, mixingOut);
|
||||
lastTime = -1;
|
||||
} else if (lastTime >= frames[int(frameCount - 1)]) // Last time is after last frame.
|
||||
return;
|
||||
if (time < frames[0]) return; // Time is before first frame.
|
||||
|
||||
var frame:int;
|
||||
if (lastTime < frames[0])
|
||||
frame = 0;
|
||||
else {
|
||||
frame = Animation.binarySearch1(frames, lastTime);
|
||||
var frameTime:Number = frames[frame];
|
||||
while (frame > 0) { // Fire multiple events with the same frame.
|
||||
if (frames[int(frame - 1)] != frameTime) break;
|
||||
frame--;
|
||||
}
|
||||
public function EventTimeline(frameCount : int) {
|
||||
frames = new Vector.<Number>(frameCount, true);
|
||||
events = new Vector.<Event>(frameCount, true);
|
||||
}
|
||||
for (; frame < frameCount && time >= frames[frame]; frame++)
|
||||
firedEvents[firedEvents.length] = events[frame];
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
public function get frameCount() : int {
|
||||
return frames.length;
|
||||
}
|
||||
|
||||
public function getPropertyId() : int {
|
||||
return TimelineType.event.ordinal << 24;
|
||||
}
|
||||
|
||||
/** Sets the time and value of the specified keyframe. */
|
||||
public function setFrame(frameIndex : int, event : Event) : void {
|
||||
frames[frameIndex] = event.time;
|
||||
events[frameIndex] = event;
|
||||
}
|
||||
|
||||
/** Fires events for frames > lastTime and <= time. */
|
||||
public function apply(skeleton : Skeleton, lastTime : Number, time : Number, firedEvents : Vector.<Event>, alpha : Number, setupPose : Boolean, mixingOut : Boolean) : void {
|
||||
if (!firedEvents) return;
|
||||
|
||||
if (lastTime > time) { // Fire events after last time for looped animations.
|
||||
apply(skeleton, lastTime, int.MAX_VALUE, firedEvents, alpha, setupPose, mixingOut);
|
||||
lastTime = -1;
|
||||
} else if (lastTime >= frames[int(frameCount - 1)]) // Last time is after last frame.
|
||||
return;
|
||||
if (time < frames[0]) return; // Time is before first frame.
|
||||
|
||||
var frame : int;
|
||||
if (lastTime < frames[0])
|
||||
frame = 0;
|
||||
else {
|
||||
frame = Animation.binarySearch1(frames, lastTime);
|
||||
var frameTime : Number = frames[frame];
|
||||
while (frame > 0) { // Fire multiple events with the same frame.
|
||||
if (frames[int(frame - 1)] != frameTime) break;
|
||||
frame--;
|
||||
}
|
||||
}
|
||||
for (; frame < frameCount && time >= frames[frame]; frame++)
|
||||
firedEvents[firedEvents.length] = events[frame];
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -29,13 +29,12 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.animation {
|
||||
|
||||
public class EventType {
|
||||
public static const start:EventType = new EventType();
|
||||
public static const interrupt:EventType = new EventType();
|
||||
public static const end:EventType = new EventType();
|
||||
public static const dispose:EventType = new EventType();
|
||||
public static const complete:EventType = new EventType();
|
||||
public static const event:EventType = new EventType();
|
||||
}
|
||||
}
|
||||
public class EventType {
|
||||
public static const start : EventType = new EventType();
|
||||
public static const interrupt : EventType = new EventType();
|
||||
public static const end : EventType = new EventType();
|
||||
public static const dispose : EventType = new EventType();
|
||||
public static const complete : EventType = new EventType();
|
||||
public static const event : EventType = new EventType();
|
||||
}
|
||||
}
|
||||
@ -29,71 +29,68 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.animation {
|
||||
import spine.Event;
|
||||
import spine.IkConstraint;
|
||||
import spine.Skeleton;
|
||||
import spine.Event;
|
||||
import spine.IkConstraint;
|
||||
import spine.Skeleton;
|
||||
|
||||
public class IkConstraintTimeline extends CurveTimeline {
|
||||
static public const ENTRIES:int = 3;
|
||||
static internal const PREV_TIME:int = -3, PREV_MIX:int = -2, PREV_BEND_DIRECTION:int = -1;
|
||||
static internal const MIX:int = 1, BEND_DIRECTION:int = 2;
|
||||
public class IkConstraintTimeline extends CurveTimeline {
|
||||
static public const ENTRIES : int = 3;
|
||||
static internal const PREV_TIME : int = -3, PREV_MIX : int = -2, PREV_BEND_DIRECTION : int = -1;
|
||||
static internal const MIX : int = 1, BEND_DIRECTION : int = 2;
|
||||
public var ikConstraintIndex : int;
|
||||
public var frames : Vector.<Number>; // time, mix, bendDirection, ...
|
||||
|
||||
public var ikConstraintIndex:int;
|
||||
public var frames:Vector.<Number>; // time, mix, bendDirection, ...
|
||||
|
||||
public function IkConstraintTimeline (frameCount:int) {
|
||||
super(frameCount);
|
||||
frames = new Vector.<Number>(frameCount * ENTRIES, true);
|
||||
}
|
||||
|
||||
override public function getPropertyId () : int {
|
||||
return (TimelineType.ikConstraint.ordinal << 24) + ikConstraintIndex;
|
||||
}
|
||||
|
||||
/** Sets the time, mix and bend direction of the specified keyframe. */
|
||||
public function setFrame (frameIndex:int, time:Number, mix:Number, bendDirection:int) : void {
|
||||
frameIndex *= ENTRIES;
|
||||
frames[frameIndex] = time;
|
||||
frames[int(frameIndex + MIX)] = mix;
|
||||
frames[int(frameIndex + BEND_DIRECTION)] = bendDirection;
|
||||
}
|
||||
|
||||
override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector.<Event>, alpha:Number, setupPose:Boolean, mixingOut:Boolean) : void {
|
||||
var constraint:IkConstraint = skeleton.ikConstraints[ikConstraintIndex];
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) {
|
||||
constraint.mix = constraint.data.mix;
|
||||
constraint.bendDirection = constraint.data.bendDirection;
|
||||
}
|
||||
return;
|
||||
public function IkConstraintTimeline(frameCount : int) {
|
||||
super(frameCount);
|
||||
frames = new Vector.<Number>(frameCount * ENTRIES, true);
|
||||
}
|
||||
|
||||
if (time >= frames[int(frames.length - ENTRIES)]) { // Time is after last frame.
|
||||
override public function getPropertyId() : int {
|
||||
return (TimelineType.ikConstraint.ordinal << 24) + ikConstraintIndex;
|
||||
}
|
||||
|
||||
/** Sets the time, mix and bend direction of the specified keyframe. */
|
||||
public function setFrame(frameIndex : int, time : Number, mix : Number, bendDirection : int) : void {
|
||||
frameIndex *= ENTRIES;
|
||||
frames[frameIndex] = time;
|
||||
frames[int(frameIndex + MIX)] = mix;
|
||||
frames[int(frameIndex + BEND_DIRECTION)] = bendDirection;
|
||||
}
|
||||
|
||||
override public function apply(skeleton : Skeleton, lastTime : Number, time : Number, firedEvents : Vector.<Event>, alpha : Number, setupPose : Boolean, mixingOut : Boolean) : void {
|
||||
var constraint : IkConstraint = skeleton.ikConstraints[ikConstraintIndex];
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) {
|
||||
constraint.mix = constraint.data.mix;
|
||||
constraint.bendDirection = constraint.data.bendDirection;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (time >= frames[int(frames.length - ENTRIES)]) { // Time is after last frame.
|
||||
if (setupPose) {
|
||||
constraint.mix = constraint.data.mix + (frames[frames.length + PREV_MIX] - constraint.data.mix) * alpha;
|
||||
constraint.bendDirection = mixingOut ? constraint.data.bendDirection : int(frames[frames.length + PREV_BEND_DIRECTION]);
|
||||
} else {
|
||||
constraint.mix += (frames[frames.length + PREV_MIX] - constraint.mix) * alpha;
|
||||
if (!mixingOut) constraint.bendDirection = int(frames[frames.length + PREV_BEND_DIRECTION]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
var frame : int = Animation.binarySearch(frames, time, ENTRIES);
|
||||
var mix : Number = frames[int(frame + PREV_MIX)];
|
||||
var frameTime : Number = frames[frame];
|
||||
var percent : Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
|
||||
if (setupPose) {
|
||||
constraint.mix = constraint.data.mix + (frames[frames.length + PREV_MIX] - constraint.data.mix) * alpha;
|
||||
constraint.bendDirection = mixingOut ? constraint.data.bendDirection
|
||||
: int(frames[frames.length + PREV_BEND_DIRECTION]);
|
||||
constraint.mix = constraint.data.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.data.mix) * alpha;
|
||||
constraint.bendDirection = mixingOut ? constraint.data.bendDirection : int(frames[frame + PREV_BEND_DIRECTION]);
|
||||
} else {
|
||||
constraint.mix += (frames[frames.length + PREV_MIX] - constraint.mix) * alpha;
|
||||
if (!mixingOut) constraint.bendDirection = int(frames[frames.length + PREV_BEND_DIRECTION]);
|
||||
constraint.mix += (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha;
|
||||
if (!mixingOut) constraint.bendDirection = int(frames[frame + PREV_BEND_DIRECTION]);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
var frame:int = Animation.binarySearch(frames, time, ENTRIES);
|
||||
var mix:Number = frames[int(frame + PREV_MIX)];
|
||||
var frameTime:Number = frames[frame];
|
||||
var percent:Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
|
||||
if (setupPose) {
|
||||
constraint.mix = constraint.data.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.data.mix) * alpha;
|
||||
constraint.bendDirection = mixingOut ? constraint.data.bendDirection : int(frames[frame + PREV_BEND_DIRECTION]);
|
||||
} else {
|
||||
constraint.mix += (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha;
|
||||
if (!mixingOut) constraint.bendDirection = int(frames[frame + PREV_BEND_DIRECTION]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -30,34 +30,34 @@
|
||||
|
||||
package spine.animation {
|
||||
public class Listeners {
|
||||
private var _listeners:Vector.<Function> = new Vector.<Function>();
|
||||
private var _listeners : Vector.<Function> = new Vector.<Function>();
|
||||
|
||||
public function Listeners () {
|
||||
public function Listeners() {
|
||||
}
|
||||
|
||||
public function get listeners () : Vector.<Function> {
|
||||
public function get listeners() : Vector.<Function> {
|
||||
return _listeners;
|
||||
}
|
||||
|
||||
public function add (listener:Function) : void {
|
||||
public function add(listener : Function) : void {
|
||||
if (listener == null)
|
||||
throw new ArgumentError("listener cannot be null.");
|
||||
var indexOf:int = _listeners.indexOf(listener);
|
||||
var indexOf : int = _listeners.indexOf(listener);
|
||||
if (indexOf == -1)
|
||||
_listeners[_listeners.length] = listener;
|
||||
}
|
||||
|
||||
public function remove (listener:Function) : void {
|
||||
public function remove(listener : Function) : void {
|
||||
if (listener == null)
|
||||
throw new ArgumentError("listener cannot be null.");
|
||||
var indexOf:int = _listeners.indexOf(listener);
|
||||
var indexOf : int = _listeners.indexOf(listener);
|
||||
if (indexOf != -1)
|
||||
_listeners.splice(_listeners.indexOf(listener), 1);
|
||||
}
|
||||
|
||||
public function invoke (... args:*) : void {
|
||||
for each (var listener:Function in _listeners)
|
||||
public function invoke(... args : *) : void {
|
||||
for each (var listener : Function in _listeners)
|
||||
listener.apply(null, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -29,70 +29,67 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.animation {
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
import spine.PathConstraint;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
import spine.PathConstraint;
|
||||
|
||||
public class PathConstraintMixTimeline extends CurveTimeline {
|
||||
static public const ENTRIES:int = 3;
|
||||
static internal const PREV_TIME:int = -3, PREV_ROTATE:int = -2, PREV_TRANSLATE:int = -1;
|
||||
static internal const ROTATE:int = 1, TRANSLATE:int = 2;
|
||||
public class PathConstraintMixTimeline extends CurveTimeline {
|
||||
static public const ENTRIES : int = 3;
|
||||
static internal const PREV_TIME : int = -3, PREV_ROTATE : int = -2, PREV_TRANSLATE : int = -1;
|
||||
static internal const ROTATE : int = 1, TRANSLATE : int = 2;
|
||||
public var pathConstraintIndex : int;
|
||||
public var frames : Vector.<Number>; // time, rotate mix, translate mix, ...
|
||||
|
||||
public var pathConstraintIndex:int;
|
||||
public function PathConstraintMixTimeline(frameCount : int) {
|
||||
super(frameCount);
|
||||
frames = new Vector.<Number>(frameCount * ENTRIES, true);
|
||||
}
|
||||
|
||||
public var frames:Vector.<Number>; // time, rotate mix, translate mix, ...
|
||||
override public function getPropertyId() : int {
|
||||
return (TimelineType.pathConstraintMix.ordinal << 24) + pathConstraintIndex;
|
||||
}
|
||||
|
||||
public function PathConstraintMixTimeline (frameCount:int) {
|
||||
super(frameCount);
|
||||
frames = new Vector.<Number>(frameCount * ENTRIES, true);
|
||||
}
|
||||
|
||||
override public function getPropertyId () : int {
|
||||
return (TimelineType.pathConstraintMix.ordinal << 24) + pathConstraintIndex;
|
||||
}
|
||||
/** Sets the time and mixes of the specified keyframe. */
|
||||
public function setFrame(frameIndex : int, time : Number, rotateMix : Number, translateMix : Number) : void {
|
||||
frameIndex *= ENTRIES;
|
||||
frames[frameIndex] = time;
|
||||
frames[frameIndex + ROTATE] = rotateMix;
|
||||
frames[frameIndex + TRANSLATE] = translateMix;
|
||||
}
|
||||
|
||||
/** Sets the time and mixes of the specified keyframe. */
|
||||
public function setFrame (frameIndex:int, time:Number, rotateMix:Number, translateMix:Number) : void {
|
||||
frameIndex *= ENTRIES;
|
||||
frames[frameIndex] = time;
|
||||
frames[frameIndex + ROTATE] = rotateMix;
|
||||
frames[frameIndex + TRANSLATE] = translateMix;
|
||||
}
|
||||
|
||||
override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector.<Event>, alpha:Number, setupPose:Boolean, mixingOut:Boolean) : void {
|
||||
var constraint:PathConstraint = skeleton.pathConstraints[pathConstraintIndex];
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) {
|
||||
constraint.rotateMix = constraint.data.rotateMix;
|
||||
constraint.translateMix = constraint.data.translateMix;
|
||||
override public function apply(skeleton : Skeleton, lastTime : Number, time : Number, firedEvents : Vector.<Event>, alpha : Number, setupPose : Boolean, mixingOut : Boolean) : void {
|
||||
var constraint : PathConstraint = skeleton.pathConstraints[pathConstraintIndex];
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) {
|
||||
constraint.rotateMix = constraint.data.rotateMix;
|
||||
constraint.translateMix = constraint.data.translateMix;
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var rotate:Number, translate:Number;
|
||||
if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame.
|
||||
rotate = frames[frames.length + PREV_ROTATE];
|
||||
translate = frames[frames.length + PREV_TRANSLATE];
|
||||
} else {
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
var frame:int = Animation.binarySearch(frames, time, ENTRIES);
|
||||
rotate = frames[frame + PREV_ROTATE];
|
||||
translate = frames[frame + PREV_TRANSLATE];
|
||||
var frameTime:Number = frames[frame];
|
||||
var percent:Number = getCurvePercent(frame / ENTRIES - 1,
|
||||
1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
var rotate : Number, translate : Number;
|
||||
if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame.
|
||||
rotate = frames[frames.length + PREV_ROTATE];
|
||||
translate = frames[frames.length + PREV_TRANSLATE];
|
||||
} else {
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
var frame : int = Animation.binarySearch(frames, time, ENTRIES);
|
||||
rotate = frames[frame + PREV_ROTATE];
|
||||
translate = frames[frame + PREV_TRANSLATE];
|
||||
var frameTime : Number = frames[frame];
|
||||
var percent : Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
|
||||
rotate += (frames[frame + ROTATE] - rotate) * percent;
|
||||
translate += (frames[frame + TRANSLATE] - translate) * percent;
|
||||
}
|
||||
rotate += (frames[frame + ROTATE] - rotate) * percent;
|
||||
translate += (frames[frame + TRANSLATE] - translate) * percent;
|
||||
}
|
||||
|
||||
if (setupPose) {
|
||||
constraint.rotateMix = constraint.data.rotateMix + (rotate - constraint.data.rotateMix) * alpha;
|
||||
constraint.translateMix = constraint.data.translateMix + (translate - constraint.data.translateMix) * alpha;
|
||||
} else {
|
||||
constraint.rotateMix += (rotate - constraint.rotateMix) * alpha;
|
||||
constraint.translateMix += (translate - constraint.translateMix) * alpha;
|
||||
if (setupPose) {
|
||||
constraint.rotateMix = constraint.data.rotateMix + (rotate - constraint.data.rotateMix) * alpha;
|
||||
constraint.translateMix = constraint.data.translateMix + (translate - constraint.data.translateMix) * alpha;
|
||||
} else {
|
||||
constraint.rotateMix += (rotate - constraint.rotateMix) * alpha;
|
||||
constraint.translateMix += (translate - constraint.translateMix) * alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -29,59 +29,56 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.animation {
|
||||
import spine.PathConstraint;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
import spine.PathConstraint;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
|
||||
public class PathConstraintPositionTimeline extends CurveTimeline {
|
||||
static public const ENTRIES:int = 2;
|
||||
static internal const PREV_TIME:int = -2, PREV_VALUE:int = -1;
|
||||
static internal const VALUE:int = 1;
|
||||
public class PathConstraintPositionTimeline extends CurveTimeline {
|
||||
static public const ENTRIES : int = 2;
|
||||
static internal const PREV_TIME : int = -2, PREV_VALUE : int = -1;
|
||||
static internal const VALUE : int = 1;
|
||||
public var pathConstraintIndex : int;
|
||||
public var frames : Vector.<Number>; // time, position, ...
|
||||
|
||||
public var pathConstraintIndex:int;
|
||||
|
||||
public var frames:Vector.<Number>; // time, position, ...
|
||||
|
||||
public function PathConstraintPositionTimeline (frameCount:int) {
|
||||
super(frameCount);
|
||||
frames = new Vector.<Number>(frameCount * ENTRIES, true);
|
||||
}
|
||||
|
||||
override public function getPropertyId () : int {
|
||||
return (TimelineType.pathConstraintPosition.ordinal << 24) + pathConstraintIndex;
|
||||
}
|
||||
|
||||
/** Sets the time and value of the specified keyframe. */
|
||||
public function setFrame (frameIndex:int, time:Number, value:Number) : void {
|
||||
frameIndex *= ENTRIES;
|
||||
frames[frameIndex] = time;
|
||||
frames[frameIndex + VALUE] = value;
|
||||
}
|
||||
|
||||
override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector.<Event>, alpha:Number, setupPose:Boolean, mixingOut:Boolean) : void {
|
||||
var constraint:PathConstraint = skeleton.pathConstraints[pathConstraintIndex];
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) constraint.position = constraint.data.position;
|
||||
return;
|
||||
public function PathConstraintPositionTimeline(frameCount : int) {
|
||||
super(frameCount);
|
||||
frames = new Vector.<Number>(frameCount * ENTRIES, true);
|
||||
}
|
||||
|
||||
var position:Number;
|
||||
if (time >= frames[frames.length - ENTRIES]) // Time is after last frame.
|
||||
position = frames[frames.length + PREV_VALUE];
|
||||
else {
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
var frame:int = Animation.binarySearch(frames, time, ENTRIES);
|
||||
position = frames[frame + PREV_VALUE];
|
||||
var frameTime:Number = frames[frame];
|
||||
var percent:Number = getCurvePercent(frame / ENTRIES - 1,
|
||||
1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
|
||||
position += (frames[frame + VALUE] - position) * percent;
|
||||
override public function getPropertyId() : int {
|
||||
return (TimelineType.pathConstraintPosition.ordinal << 24) + pathConstraintIndex;
|
||||
}
|
||||
|
||||
/** Sets the time and value of the specified keyframe. */
|
||||
public function setFrame(frameIndex : int, time : Number, value : Number) : void {
|
||||
frameIndex *= ENTRIES;
|
||||
frames[frameIndex] = time;
|
||||
frames[frameIndex + VALUE] = value;
|
||||
}
|
||||
|
||||
override public function apply(skeleton : Skeleton, lastTime : Number, time : Number, firedEvents : Vector.<Event>, alpha : Number, setupPose : Boolean, mixingOut : Boolean) : void {
|
||||
var constraint : PathConstraint = skeleton.pathConstraints[pathConstraintIndex];
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) constraint.position = constraint.data.position;
|
||||
return;
|
||||
}
|
||||
|
||||
var position : Number;
|
||||
if (time >= frames[frames.length - ENTRIES]) // Time is after last frame.
|
||||
position = frames[frames.length + PREV_VALUE];
|
||||
else {
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
var frame : int = Animation.binarySearch(frames, time, ENTRIES);
|
||||
position = frames[frame + PREV_VALUE];
|
||||
var frameTime : Number = frames[frame];
|
||||
var percent : Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
|
||||
position += (frames[frame + VALUE] - position) * percent;
|
||||
}
|
||||
if (setupPose)
|
||||
constraint.position = constraint.data.position + (position - constraint.data.position) * alpha;
|
||||
else
|
||||
constraint.position += (position - constraint.position) * alpha;
|
||||
}
|
||||
if (setupPose)
|
||||
constraint.position = constraint.data.position + (position - constraint.data.position) * alpha;
|
||||
else
|
||||
constraint.position += (position - constraint.position) * alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -29,44 +29,43 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.animation {
|
||||
import spine.Skeleton;
|
||||
import spine.Event;
|
||||
import spine.PathConstraint;
|
||||
import spine.Skeleton;
|
||||
import spine.Event;
|
||||
import spine.PathConstraint;
|
||||
|
||||
public class PathConstraintSpacingTimeline extends PathConstraintPositionTimeline {
|
||||
public function PathConstraintSpacingTimeline (frameCount:int) {
|
||||
super(frameCount);
|
||||
}
|
||||
|
||||
override public function getPropertyId () : int {
|
||||
return (TimelineType.pathConstraintSpacing.ordinal << 24) + pathConstraintIndex;
|
||||
}
|
||||
|
||||
override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector.<Event>, alpha:Number, setupPose:Boolean, mixingOut:Boolean) : void {
|
||||
var constraint:PathConstraint = skeleton.pathConstraints[pathConstraintIndex];
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) constraint.spacing = constraint.data.spacing;
|
||||
return;
|
||||
public class PathConstraintSpacingTimeline extends PathConstraintPositionTimeline {
|
||||
public function PathConstraintSpacingTimeline(frameCount : int) {
|
||||
super(frameCount);
|
||||
}
|
||||
|
||||
var spacing:Number;
|
||||
if (time >= frames[frames.length - ENTRIES]) // Time is after last frame.
|
||||
spacing = frames[frames.length + PREV_VALUE];
|
||||
else {
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
var frame:int = Animation.binarySearch(frames, time, ENTRIES);
|
||||
spacing = frames[frame + PREV_VALUE];
|
||||
var frameTime:Number = frames[frame];
|
||||
var percent:Number = getCurvePercent(frame / ENTRIES - 1,
|
||||
1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
|
||||
spacing += (frames[frame + VALUE] - spacing) * percent;
|
||||
override public function getPropertyId() : int {
|
||||
return (TimelineType.pathConstraintSpacing.ordinal << 24) + pathConstraintIndex;
|
||||
}
|
||||
|
||||
if (setupPose)
|
||||
constraint.spacing = constraint.data.spacing + (spacing - constraint.data.spacing) * alpha;
|
||||
else
|
||||
constraint.spacing += (spacing - constraint.spacing) * alpha;
|
||||
override public function apply(skeleton : Skeleton, lastTime : Number, time : Number, firedEvents : Vector.<Event>, alpha : Number, setupPose : Boolean, mixingOut : Boolean) : void {
|
||||
var constraint : PathConstraint = skeleton.pathConstraints[pathConstraintIndex];
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) constraint.spacing = constraint.data.spacing;
|
||||
return;
|
||||
}
|
||||
|
||||
var spacing : Number;
|
||||
if (time >= frames[frames.length - ENTRIES]) // Time is after last frame.
|
||||
spacing = frames[frames.length + PREV_VALUE];
|
||||
else {
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
var frame : int = Animation.binarySearch(frames, time, ENTRIES);
|
||||
spacing = frames[frame + PREV_VALUE];
|
||||
var frameTime : Number = frames[frame];
|
||||
var percent : Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
|
||||
spacing += (frames[frame + VALUE] - spacing) * percent;
|
||||
}
|
||||
|
||||
if (setupPose)
|
||||
constraint.spacing = constraint.data.spacing + (spacing - constraint.data.spacing) * alpha;
|
||||
else
|
||||
constraint.spacing += (spacing - constraint.spacing) * alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -29,73 +29,71 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.animation {
|
||||
import spine.Bone;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
import spine.Bone;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
|
||||
public class RotateTimeline extends CurveTimeline {
|
||||
static public const ENTRIES:int = 2;
|
||||
static public const PREV_TIME:int = -2, PREV_ROTATION:int = -1;
|
||||
static public const ROTATION:int = 1;
|
||||
public class RotateTimeline extends CurveTimeline {
|
||||
static public const ENTRIES : int = 2;
|
||||
static public const PREV_TIME : int = -2, PREV_ROTATION : int = -1;
|
||||
static public const ROTATION : int = 1;
|
||||
public var boneIndex : int;
|
||||
public var frames : Vector.<Number>; // time, value, ...
|
||||
|
||||
public var boneIndex:int;
|
||||
public var frames:Vector.<Number>; // time, value, ...
|
||||
|
||||
public function RotateTimeline (frameCount:int) {
|
||||
super(frameCount);
|
||||
frames = new Vector.<Number>(frameCount * 2, true);
|
||||
}
|
||||
|
||||
override public function getPropertyId () : int {
|
||||
return (TimelineType.rotate.ordinal << 24) + boneIndex;
|
||||
}
|
||||
|
||||
/** Sets the time and angle of the specified keyframe. */
|
||||
public function setFrame (frameIndex:int, time:Number, degrees:Number) : void {
|
||||
frameIndex <<= 1;
|
||||
frames[frameIndex] = time;
|
||||
frames[int(frameIndex + ROTATION)] = degrees;
|
||||
}
|
||||
|
||||
override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector.<Event>, alpha:Number, setupPose:Boolean, mixingOut:Boolean) : void {
|
||||
var frames:Vector.<Number> = this.frames;
|
||||
|
||||
var bone:Bone = skeleton.bones[boneIndex];
|
||||
var r:Number;
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) bone.rotation = bone.data.rotation;
|
||||
return;
|
||||
public function RotateTimeline(frameCount : int) {
|
||||
super(frameCount);
|
||||
frames = new Vector.<Number>(frameCount * 2, true);
|
||||
}
|
||||
|
||||
if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame.
|
||||
if (setupPose)
|
||||
bone.rotation = bone.data.rotation + frames[frames.length + PREV_ROTATION] * alpha;
|
||||
else {
|
||||
r = bone.data.rotation + frames[frames.length + PREV_ROTATION] - bone.rotation;
|
||||
r -= (16384 - int((16384.499999999996 - r / 360))) * 360; // Wrap within -180 and 180.
|
||||
override public function getPropertyId() : int {
|
||||
return (TimelineType.rotate.ordinal << 24) + boneIndex;
|
||||
}
|
||||
|
||||
/** Sets the time and angle of the specified keyframe. */
|
||||
public function setFrame(frameIndex : int, time : Number, degrees : Number) : void {
|
||||
frameIndex <<= 1;
|
||||
frames[frameIndex] = time;
|
||||
frames[int(frameIndex + ROTATION)] = degrees;
|
||||
}
|
||||
|
||||
override public function apply(skeleton : Skeleton, lastTime : Number, time : Number, firedEvents : Vector.<Event>, alpha : Number, setupPose : Boolean, mixingOut : Boolean) : void {
|
||||
var frames : Vector.<Number> = this.frames;
|
||||
|
||||
var bone : Bone = skeleton.bones[boneIndex];
|
||||
var r : Number;
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) bone.rotation = bone.data.rotation;
|
||||
return;
|
||||
}
|
||||
|
||||
if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame.
|
||||
if (setupPose)
|
||||
bone.rotation = bone.data.rotation + frames[frames.length + PREV_ROTATION] * alpha;
|
||||
else {
|
||||
r = bone.data.rotation + frames[frames.length + PREV_ROTATION] - bone.rotation;
|
||||
r -= (16384 - int((16384.499999999996 - r / 360))) * 360; // Wrap within -180 and 180.
|
||||
bone.rotation += r * alpha;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
var frame : int = Animation.binarySearch(frames, time, ENTRIES);
|
||||
var prevRotation : Number = frames[frame + PREV_ROTATION];
|
||||
var frameTime : Number = frames[frame];
|
||||
var percent : Number = getCurvePercent((frame >> 1) - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
|
||||
r = frames[frame + ROTATION] - prevRotation;
|
||||
r -= (16384 - int((16384.499999999996 - r / 360))) * 360;
|
||||
r = prevRotation + r * percent;
|
||||
if (setupPose) {
|
||||
r -= (16384 - int((16384.499999999996 - r / 360))) * 360;
|
||||
bone.rotation = bone.data.rotation + r * alpha;
|
||||
} else {
|
||||
r = bone.data.rotation + r - bone.rotation;
|
||||
r -= (16384 - int((16384.499999999996 - r / 360))) * 360;
|
||||
bone.rotation += r * alpha;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
var frame:int = Animation.binarySearch(frames, time, ENTRIES);
|
||||
var prevRotation:Number = frames[frame + PREV_ROTATION];
|
||||
var frameTime:Number = frames[frame];
|
||||
var percent:Number = getCurvePercent((frame >> 1) - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
|
||||
r = frames[frame + ROTATION] - prevRotation;
|
||||
r -= (16384 - int((16384.499999999996 - r / 360))) * 360;
|
||||
r = prevRotation + r * percent;
|
||||
if (setupPose) {
|
||||
r -= (16384 - int((16384.499999999996 - r / 360))) * 360;
|
||||
bone.rotation = bone.data.rotation + r * alpha;
|
||||
} else {
|
||||
r = bone.data.rotation + r - bone.rotation;
|
||||
r -= (16384 - int((16384.499999999996 - r / 360))) * 360;
|
||||
bone.rotation += r * alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,72 +29,70 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.animation {
|
||||
import spine.MathUtils;
|
||||
import spine.Bone;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
import spine.MathUtils;
|
||||
import spine.Bone;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
|
||||
public class ScaleTimeline extends TranslateTimeline {
|
||||
public function ScaleTimeline (frameCount:int) {
|
||||
super(frameCount);
|
||||
}
|
||||
|
||||
override public function getPropertyId () : int {
|
||||
return (TimelineType.scale.ordinal << 24) + boneIndex;
|
||||
}
|
||||
public class ScaleTimeline extends TranslateTimeline {
|
||||
public function ScaleTimeline(frameCount : int) {
|
||||
super(frameCount);
|
||||
}
|
||||
|
||||
override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector.<Event>, alpha:Number, setupPose:Boolean, mixingOut:Boolean) : void {
|
||||
var frames:Vector.<Number> = this.frames;
|
||||
var bone:Bone = skeleton.bones[boneIndex];
|
||||
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) {
|
||||
bone.scaleX = bone.data.scaleX;
|
||||
bone.scaleY = bone.data.scaleY;
|
||||
override public function getPropertyId() : int {
|
||||
return (TimelineType.scale.ordinal << 24) + boneIndex;
|
||||
}
|
||||
|
||||
override public function apply(skeleton : Skeleton, lastTime : Number, time : Number, firedEvents : Vector.<Event>, alpha : Number, setupPose : Boolean, mixingOut : Boolean) : void {
|
||||
var frames : Vector.<Number> = this.frames;
|
||||
var bone : Bone = skeleton.bones[boneIndex];
|
||||
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) {
|
||||
bone.scaleX = bone.data.scaleX;
|
||||
bone.scaleY = bone.data.scaleY;
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var x:Number, y:Number;
|
||||
if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame.
|
||||
x = frames[frames.length + PREV_X] * bone.data.scaleX;
|
||||
y = frames[frames.length + PREV_Y] * bone.data.scaleY;
|
||||
} else {
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
var frame:int = Animation.binarySearch(frames, time, ENTRIES);
|
||||
x = frames[frame + PREV_X];
|
||||
y = frames[frame + PREV_Y];
|
||||
var frameTime:Number = frames[frame];
|
||||
var percent:Number = getCurvePercent(frame / ENTRIES - 1,
|
||||
1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
|
||||
x = (x + (frames[frame + X] - x) * percent) * bone.data.scaleX;
|
||||
y = (y + (frames[frame + Y] - y) * percent) * bone.data.scaleY;
|
||||
}
|
||||
if (alpha == 1) {
|
||||
bone.scaleX = x;
|
||||
bone.scaleY = y;
|
||||
} else {
|
||||
var bx:Number, by:Number;
|
||||
if (setupPose) {
|
||||
bx = bone.data.scaleX;
|
||||
by = bone.data.scaleY;
|
||||
var x : Number, y : Number;
|
||||
if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame.
|
||||
x = frames[frames.length + PREV_X] * bone.data.scaleX;
|
||||
y = frames[frames.length + PREV_Y] * bone.data.scaleY;
|
||||
} else {
|
||||
bx = bone.scaleX;
|
||||
by = bone.scaleY;
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
var frame : int = Animation.binarySearch(frames, time, ENTRIES);
|
||||
x = frames[frame + PREV_X];
|
||||
y = frames[frame + PREV_Y];
|
||||
var frameTime : Number = frames[frame];
|
||||
var percent : Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
|
||||
x = (x + (frames[frame + X] - x) * percent) * bone.data.scaleX;
|
||||
y = (y + (frames[frame + Y] - y) * percent) * bone.data.scaleY;
|
||||
}
|
||||
// Mixing out uses sign of setup or current pose, else use sign of key.
|
||||
if (mixingOut) {
|
||||
x = Math.abs(x) * MathUtils.signum(bx);
|
||||
y = Math.abs(y) * MathUtils.signum(by);
|
||||
if (alpha == 1) {
|
||||
bone.scaleX = x;
|
||||
bone.scaleY = y;
|
||||
} else {
|
||||
bx = Math.abs(bx) * MathUtils.signum(x);
|
||||
by = Math.abs(by) * MathUtils.signum(y);
|
||||
var bx : Number, by : Number;
|
||||
if (setupPose) {
|
||||
bx = bone.data.scaleX;
|
||||
by = bone.data.scaleY;
|
||||
} else {
|
||||
bx = bone.scaleX;
|
||||
by = bone.scaleY;
|
||||
}
|
||||
// Mixing out uses sign of setup or current pose, else use sign of key.
|
||||
if (mixingOut) {
|
||||
x = Math.abs(x) * MathUtils.signum(bx);
|
||||
y = Math.abs(y) * MathUtils.signum(by);
|
||||
} else {
|
||||
bx = Math.abs(bx) * MathUtils.signum(x);
|
||||
by = Math.abs(by) * MathUtils.signum(y);
|
||||
}
|
||||
bone.scaleX = bx + (x - bx) * alpha;
|
||||
bone.scaleY = by + (y - by) * alpha;
|
||||
}
|
||||
bone.scaleX = bx + (x - bx) * alpha;
|
||||
bone.scaleY = by + (y - by) * alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,55 +29,53 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.animation {
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
import spine.Bone;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
import spine.Bone;
|
||||
|
||||
public class ShearTimeline extends TranslateTimeline {
|
||||
public function ShearTimeline (frameCount:int) {
|
||||
super(frameCount);
|
||||
}
|
||||
|
||||
override public function getPropertyId () : int {
|
||||
return (TimelineType.shear.ordinal << 24) + boneIndex;
|
||||
}
|
||||
public class ShearTimeline extends TranslateTimeline {
|
||||
public function ShearTimeline(frameCount : int) {
|
||||
super(frameCount);
|
||||
}
|
||||
|
||||
override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector.<Event>, alpha:Number, setupPose:Boolean, mixingOut:Boolean) : void {
|
||||
var frames:Vector.<Number> = this.frames;
|
||||
var bone:Bone = skeleton.bones[boneIndex];
|
||||
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) {
|
||||
bone.shearX = bone.data.shearX;
|
||||
bone.shearY = bone.data.shearY;
|
||||
override public function getPropertyId() : int {
|
||||
return (TimelineType.shear.ordinal << 24) + boneIndex;
|
||||
}
|
||||
|
||||
override public function apply(skeleton : Skeleton, lastTime : Number, time : Number, firedEvents : Vector.<Event>, alpha : Number, setupPose : Boolean, mixingOut : Boolean) : void {
|
||||
var frames : Vector.<Number> = this.frames;
|
||||
var bone : Bone = skeleton.bones[boneIndex];
|
||||
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) {
|
||||
bone.shearX = bone.data.shearX;
|
||||
bone.shearY = bone.data.shearY;
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var x:Number, y:Number;
|
||||
if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame.
|
||||
x = frames[frames.length + PREV_X];
|
||||
y = frames[frames.length + PREV_Y];
|
||||
} else {
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
var frame:int = Animation.binarySearch(frames, time, ENTRIES);
|
||||
x = frames[frame + PREV_X];
|
||||
y = frames[frame + PREV_Y];
|
||||
var frameTime:Number = frames[frame];
|
||||
var percent:Number = getCurvePercent(frame / ENTRIES - 1,
|
||||
1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
var x : Number, y : Number;
|
||||
if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame.
|
||||
x = frames[frames.length + PREV_X];
|
||||
y = frames[frames.length + PREV_Y];
|
||||
} else {
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
var frame : int = Animation.binarySearch(frames, time, ENTRIES);
|
||||
x = frames[frame + PREV_X];
|
||||
y = frames[frame + PREV_Y];
|
||||
var frameTime : Number = frames[frame];
|
||||
var percent : Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
|
||||
x = x + (frames[frame + X] - x) * percent;
|
||||
y = y + (frames[frame + Y] - y) * percent;
|
||||
}
|
||||
if (setupPose) {
|
||||
bone.shearX = bone.data.shearX + x * alpha;
|
||||
bone.shearY = bone.data.shearY + y * alpha;
|
||||
} else {
|
||||
bone.shearX += (bone.data.shearX + x - bone.shearX) * alpha;
|
||||
bone.shearY += (bone.data.shearY + y - bone.shearY) * alpha;
|
||||
x = x + (frames[frame + X] - x) * percent;
|
||||
y = y + (frames[frame + Y] - y) * percent;
|
||||
}
|
||||
if (setupPose) {
|
||||
bone.shearX = bone.data.shearX + x * alpha;
|
||||
bone.shearY = bone.data.shearY + y * alpha;
|
||||
} else {
|
||||
bone.shearX += (bone.data.shearX + x - bone.shearX) * alpha;
|
||||
bone.shearY += (bone.data.shearY + y - bone.shearY) * alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,14 +29,13 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.animation {
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
|
||||
public interface Timeline {
|
||||
/** Sets the value(s) for the specified time. */
|
||||
function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector.<Event>, alpha:Number, setupPose:Boolean, mixingOut:Boolean) : void;
|
||||
|
||||
function getPropertyId() : int;
|
||||
}
|
||||
public interface Timeline {
|
||||
/** Sets the value(s) for the specified time. */
|
||||
function apply(skeleton : Skeleton, lastTime : Number, time : Number, firedEvents : Vector.<Event>, alpha : Number, setupPose : Boolean, mixingOut : Boolean) : void;
|
||||
|
||||
}
|
||||
function getPropertyId() : int;
|
||||
}
|
||||
}
|
||||
@ -29,29 +29,27 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.animation {
|
||||
public class TimelineType {
|
||||
public var ordinal : int;
|
||||
|
||||
public class TimelineType {
|
||||
public var ordinal:int;
|
||||
|
||||
public function TimelineType(order:int) {
|
||||
this.ordinal = order;
|
||||
public function TimelineType(order : int) {
|
||||
this.ordinal = order;
|
||||
}
|
||||
|
||||
public static const rotate : TimelineType = new TimelineType(0);
|
||||
public static const translate : TimelineType = new TimelineType(1);
|
||||
public static const scale : TimelineType = new TimelineType(2);
|
||||
public static const shear : TimelineType = new TimelineType(3);
|
||||
public static const attachment : TimelineType = new TimelineType(4);
|
||||
public static const color : TimelineType = new TimelineType(5);
|
||||
public static const deform : TimelineType = new TimelineType(6);
|
||||
public static const event : TimelineType = new TimelineType(7);
|
||||
public static const drawOrder : TimelineType = new TimelineType(8);
|
||||
public static const ikConstraint : TimelineType = new TimelineType(9);
|
||||
public static const transformConstraint : TimelineType = new TimelineType(10);
|
||||
public static const pathConstraintPosition : TimelineType = new TimelineType(11);
|
||||
public static const pathConstraintSpacing : TimelineType = new TimelineType(12);
|
||||
public static const pathConstraintMix : TimelineType = new TimelineType(13);
|
||||
public static const twoColor : TimelineType = new TimelineType(14);
|
||||
}
|
||||
|
||||
public static const rotate:TimelineType = new TimelineType(0);
|
||||
public static const translate:TimelineType = new TimelineType(1);
|
||||
public static const scale:TimelineType = new TimelineType(2);
|
||||
public static const shear:TimelineType = new TimelineType(3);
|
||||
public static const attachment:TimelineType = new TimelineType(4);
|
||||
public static const color:TimelineType = new TimelineType(5);
|
||||
public static const deform:TimelineType = new TimelineType(6);
|
||||
public static const event:TimelineType = new TimelineType(7);
|
||||
public static const drawOrder:TimelineType = new TimelineType(8);
|
||||
public static const ikConstraint:TimelineType = new TimelineType(9);
|
||||
public static const transformConstraint:TimelineType = new TimelineType(10);
|
||||
public static const pathConstraintPosition:TimelineType = new TimelineType(11);
|
||||
public static const pathConstraintSpacing:TimelineType = new TimelineType(12);
|
||||
public static const pathConstraintMix:TimelineType = new TimelineType(13);
|
||||
public static const twoColor:TimelineType = new TimelineType(14);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,54 +29,54 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.animation {
|
||||
import spine.Poolable;
|
||||
import spine.Poolable;
|
||||
|
||||
public class TrackEntry implements Poolable {
|
||||
public var animation:Animation;
|
||||
public var next:TrackEntry, mixingFrom:TrackEntry;
|
||||
public var onStart:Listeners = new Listeners();
|
||||
public var onInterrupt:Listeners = new Listeners();
|
||||
public var onEnd:Listeners = new Listeners();
|
||||
public var onDispose:Listeners = new Listeners();
|
||||
public var onComplete:Listeners = new Listeners();
|
||||
public var onEvent:Listeners = new Listeners();
|
||||
public var trackIndex:int;
|
||||
public var loop:Boolean;
|
||||
public var eventThreshold:Number, attachmentThreshold:Number, drawOrderThreshold:Number;
|
||||
public var animationStart:Number, animationEnd:Number, animationLast:Number, nextAnimationLast:Number;
|
||||
public var delay:Number, trackTime:Number, trackLast:Number, nextTrackLast:Number, trackEnd:Number, timeScale:Number;
|
||||
public var alpha:Number, mixTime:Number, mixDuration:Number, mixAlpha:Number;
|
||||
public var timelinesFirst:Vector.<Boolean> = new Vector.<Boolean>();
|
||||
public var timelinesRotation:Vector.<Number> = new Vector.<Number>();
|
||||
|
||||
public function TrackEntry () {
|
||||
}
|
||||
|
||||
public function getAnimationTime():Number {
|
||||
if (loop) {
|
||||
var duration:Number = animationEnd - animationStart;
|
||||
if (duration == 0) return animationStart;
|
||||
return (trackTime % duration) + animationStart;
|
||||
public class TrackEntry implements Poolable {
|
||||
public var animation : Animation;
|
||||
public var next : TrackEntry, mixingFrom : TrackEntry;
|
||||
public var onStart : Listeners = new Listeners();
|
||||
public var onInterrupt : Listeners = new Listeners();
|
||||
public var onEnd : Listeners = new Listeners();
|
||||
public var onDispose : Listeners = new Listeners();
|
||||
public var onComplete : Listeners = new Listeners();
|
||||
public var onEvent : Listeners = new Listeners();
|
||||
public var trackIndex : int;
|
||||
public var loop : Boolean;
|
||||
public var eventThreshold : Number, attachmentThreshold : Number, drawOrderThreshold : Number;
|
||||
public var animationStart : Number, animationEnd : Number, animationLast : Number, nextAnimationLast : Number;
|
||||
public var delay : Number, trackTime : Number, trackLast : Number, nextTrackLast : Number, trackEnd : Number, timeScale : Number;
|
||||
public var alpha : Number, mixTime : Number, mixDuration : Number, mixAlpha : Number;
|
||||
public var timelinesFirst : Vector.<Boolean> = new Vector.<Boolean>();
|
||||
public var timelinesRotation : Vector.<Number> = new Vector.<Number>();
|
||||
|
||||
public function TrackEntry() {
|
||||
}
|
||||
|
||||
public function getAnimationTime() : Number {
|
||||
if (loop) {
|
||||
var duration : Number = animationEnd - animationStart;
|
||||
if (duration == 0) return animationStart;
|
||||
return (trackTime % duration) + animationStart;
|
||||
}
|
||||
return Math.min(trackTime + animationStart, animationEnd);
|
||||
}
|
||||
|
||||
public function reset() : void {
|
||||
next = null;
|
||||
mixingFrom = null;
|
||||
animation = null;
|
||||
onStart.listeners.length = 0;
|
||||
onInterrupt.listeners.length = 0;
|
||||
onEnd.listeners.length = 0;
|
||||
onDispose.listeners.length = 0;
|
||||
onComplete.listeners.length = 0;
|
||||
onEvent.listeners.length = 0;
|
||||
timelinesFirst.length = 0;
|
||||
timelinesRotation.length = 0;
|
||||
}
|
||||
|
||||
public function resetRotationDirection() : void {
|
||||
timelinesRotation.length = 0;
|
||||
}
|
||||
return Math.min(trackTime + animationStart, animationEnd);
|
||||
}
|
||||
|
||||
public function reset ():void {
|
||||
next = null;
|
||||
mixingFrom = null;
|
||||
animation = null;
|
||||
onStart.listeners.length = 0;
|
||||
onInterrupt.listeners.length = 0;
|
||||
onEnd.listeners.length = 0;
|
||||
onDispose.listeners.length = 0;
|
||||
onComplete.listeners.length = 0;
|
||||
onEvent.listeners.length = 0;
|
||||
timelinesFirst.length = 0;
|
||||
timelinesRotation.length = 0;
|
||||
}
|
||||
|
||||
public function resetRotationDirection ():void {
|
||||
timelinesRotation.length = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -29,89 +29,87 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.animation {
|
||||
import spine.TransformConstraintData;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
import spine.TransformConstraint;
|
||||
import spine.TransformConstraintData;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
import spine.TransformConstraint;
|
||||
|
||||
public class TransformConstraintTimeline extends CurveTimeline {
|
||||
static public const ENTRIES:int = 5;
|
||||
static internal const PREV_TIME:int = -5, PREV_ROTATE:int = -4, PREV_TRANSLATE:int = -3, PREV_SCALE:int = -2, PREV_SHEAR:int = -1;
|
||||
static internal const ROTATE:int = 1, TRANSLATE:int = 2, SCALE:int = 3, SHEAR:int = 4;
|
||||
public class TransformConstraintTimeline extends CurveTimeline {
|
||||
static public const ENTRIES : int = 5;
|
||||
static internal const PREV_TIME : int = -5, PREV_ROTATE : int = -4, PREV_TRANSLATE : int = -3, PREV_SCALE : int = -2, PREV_SHEAR : int = -1;
|
||||
static internal const ROTATE : int = 1, TRANSLATE : int = 2, SCALE : int = 3, SHEAR : int = 4;
|
||||
public var transformConstraintIndex : int;
|
||||
public var frames : Vector.<Number>; // time, rotate mix, translate mix, scale mix, shear mix, ...
|
||||
|
||||
public var transformConstraintIndex:int;
|
||||
public var frames:Vector.<Number>; // time, rotate mix, translate mix, scale mix, shear mix, ...
|
||||
public function TransformConstraintTimeline(frameCount : int) {
|
||||
super(frameCount);
|
||||
frames = new Vector.<Number>(frameCount * ENTRIES, true);
|
||||
}
|
||||
|
||||
public function TransformConstraintTimeline (frameCount:int) {
|
||||
super(frameCount);
|
||||
frames = new Vector.<Number>(frameCount * ENTRIES, true);
|
||||
}
|
||||
|
||||
override public function getPropertyId () : int {
|
||||
return (TimelineType.transformConstraint.ordinal << 24) + transformConstraintIndex;
|
||||
}
|
||||
override public function getPropertyId() : int {
|
||||
return (TimelineType.transformConstraint.ordinal << 24) + transformConstraintIndex;
|
||||
}
|
||||
|
||||
/** Sets the time and mixes of the specified keyframe. */
|
||||
public function setFrame (frameIndex:int, time:Number, rotateMix:Number, translateMix:Number, scaleMix:Number, shearMix:Number) : void {
|
||||
frameIndex *= ENTRIES;
|
||||
frames[frameIndex] = time;
|
||||
frames[frameIndex + ROTATE] = rotateMix;
|
||||
frames[frameIndex + TRANSLATE] = translateMix;
|
||||
frames[frameIndex + SCALE] = scaleMix;
|
||||
frames[frameIndex + SHEAR] = shearMix;
|
||||
}
|
||||
/** Sets the time and mixes of the specified keyframe. */
|
||||
public function setFrame(frameIndex : int, time : Number, rotateMix : Number, translateMix : Number, scaleMix : Number, shearMix : Number) : void {
|
||||
frameIndex *= ENTRIES;
|
||||
frames[frameIndex] = time;
|
||||
frames[frameIndex + ROTATE] = rotateMix;
|
||||
frames[frameIndex + TRANSLATE] = translateMix;
|
||||
frames[frameIndex + SCALE] = scaleMix;
|
||||
frames[frameIndex + SHEAR] = shearMix;
|
||||
}
|
||||
|
||||
override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector.<Event>, alpha:Number, setupPose:Boolean, mixingOut:Boolean) : void {
|
||||
var frames:Vector.<Number> = this.frames;
|
||||
override public function apply(skeleton : Skeleton, lastTime : Number, time : Number, firedEvents : Vector.<Event>, alpha : Number, setupPose : Boolean, mixingOut : Boolean) : void {
|
||||
var frames : Vector.<Number> = this.frames;
|
||||
|
||||
var constraint:TransformConstraint = skeleton.transformConstraints[transformConstraintIndex];
|
||||
var data:TransformConstraintData;
|
||||
if (time < frames[0]) {
|
||||
var constraint : TransformConstraint = skeleton.transformConstraints[transformConstraintIndex];
|
||||
var data : TransformConstraintData;
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) {
|
||||
data = constraint.data;
|
||||
constraint.rotateMix = constraint.data.rotateMix;
|
||||
constraint.translateMix = constraint.data.translateMix;
|
||||
constraint.scaleMix = constraint.data.scaleMix;
|
||||
constraint.shearMix = constraint.data.shearMix;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var rotate : Number, translate : Number, scale : Number, shear : Number;
|
||||
if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame.
|
||||
var i : int = frames.length;
|
||||
rotate = frames[i + PREV_ROTATE];
|
||||
translate = frames[i + PREV_TRANSLATE];
|
||||
scale = frames[i + PREV_SCALE];
|
||||
shear = frames[i + PREV_SHEAR];
|
||||
} else {
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
var frame : int = Animation.binarySearch(frames, time, ENTRIES);
|
||||
rotate = frames[frame + PREV_ROTATE];
|
||||
translate = frames[frame + PREV_TRANSLATE];
|
||||
scale = frames[frame + PREV_SCALE];
|
||||
shear = frames[frame + PREV_SHEAR];
|
||||
var frameTime : Number = frames[frame];
|
||||
var percent : Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
|
||||
rotate += (frames[frame + ROTATE] - rotate) * percent;
|
||||
translate += (frames[frame + TRANSLATE] - translate) * percent;
|
||||
scale += (frames[frame + SCALE] - scale) * percent;
|
||||
shear += (frames[frame + SHEAR] - shear) * percent;
|
||||
}
|
||||
if (setupPose) {
|
||||
data = constraint.data;
|
||||
constraint.rotateMix = constraint.data.rotateMix;
|
||||
constraint.translateMix = constraint.data.translateMix;
|
||||
constraint.scaleMix = constraint.data.scaleMix;
|
||||
constraint.shearMix = constraint.data.shearMix;
|
||||
constraint.rotateMix = data.rotateMix + (rotate - data.rotateMix) * alpha;
|
||||
constraint.translateMix = data.translateMix + (translate - data.translateMix) * alpha;
|
||||
constraint.scaleMix = data.scaleMix + (scale - data.scaleMix) * alpha;
|
||||
constraint.shearMix = data.shearMix + (shear - data.shearMix) * alpha;
|
||||
} else {
|
||||
constraint.rotateMix += (rotate - constraint.rotateMix) * alpha;
|
||||
constraint.translateMix += (translate - constraint.translateMix) * alpha;
|
||||
constraint.scaleMix += (scale - constraint.scaleMix) * alpha;
|
||||
constraint.shearMix += (shear - constraint.shearMix) * alpha;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var rotate:Number, translate:Number, scale:Number, shear:Number;
|
||||
if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame.
|
||||
var i:int = frames.length;
|
||||
rotate = frames[i + PREV_ROTATE];
|
||||
translate = frames[i + PREV_TRANSLATE];
|
||||
scale = frames[i + PREV_SCALE];
|
||||
shear = frames[i + PREV_SHEAR];
|
||||
} else {
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
var frame:int = Animation.binarySearch(frames, time, ENTRIES);
|
||||
rotate = frames[frame + PREV_ROTATE];
|
||||
translate = frames[frame + PREV_TRANSLATE];
|
||||
scale = frames[frame + PREV_SCALE];
|
||||
shear = frames[frame + PREV_SHEAR];
|
||||
var frameTime:Number = frames[frame];
|
||||
var percent:Number = getCurvePercent(frame / ENTRIES - 1,
|
||||
1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
|
||||
rotate += (frames[frame + ROTATE] - rotate) * percent;
|
||||
translate += (frames[frame + TRANSLATE] - translate) * percent;
|
||||
scale += (frames[frame + SCALE] - scale) * percent;
|
||||
shear += (frames[frame + SHEAR] - shear) * percent;
|
||||
}
|
||||
if (setupPose) {
|
||||
data = constraint.data;
|
||||
constraint.rotateMix = data.rotateMix + (rotate - data.rotateMix) * alpha;
|
||||
constraint.translateMix = data.translateMix + (translate - data.translateMix) * alpha;
|
||||
constraint.scaleMix = data.scaleMix + (scale - data.scaleMix) * alpha;
|
||||
constraint.shearMix = data.shearMix + (shear - data.shearMix) * alpha;
|
||||
} else {
|
||||
constraint.rotateMix += (rotate - constraint.rotateMix) * alpha;
|
||||
constraint.translateMix += (translate - constraint.translateMix) * alpha;
|
||||
constraint.scaleMix += (scale - constraint.scaleMix) * alpha;
|
||||
constraint.shearMix += (shear - constraint.shearMix) * alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -29,71 +29,68 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.animation {
|
||||
import spine.Bone;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
import spine.Bone;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
|
||||
public class TranslateTimeline extends CurveTimeline {
|
||||
static public const ENTRIES:int = 3;
|
||||
static internal const PREV_TIME:int = -3, PREV_X:int = -2, PREV_Y:int = -1;
|
||||
static internal const X:int = 1, Y:int = 2;
|
||||
public class TranslateTimeline extends CurveTimeline {
|
||||
static public const ENTRIES : int = 3;
|
||||
static internal const PREV_TIME : int = -3, PREV_X : int = -2, PREV_Y : int = -1;
|
||||
static internal const X : int = 1, Y : int = 2;
|
||||
public var boneIndex : int;
|
||||
public var frames : Vector.<Number>; // time, value, value, ...
|
||||
|
||||
public var boneIndex:int;
|
||||
public var frames:Vector.<Number>; // time, value, value, ...
|
||||
public function TranslateTimeline(frameCount : int) {
|
||||
super(frameCount);
|
||||
frames = new Vector.<Number>(frameCount * ENTRIES, true);
|
||||
}
|
||||
|
||||
public function TranslateTimeline (frameCount:int) {
|
||||
super(frameCount);
|
||||
frames = new Vector.<Number>(frameCount * ENTRIES, true);
|
||||
}
|
||||
|
||||
override public function getPropertyId () : int {
|
||||
return (TimelineType.translate.ordinal << 24) + boneIndex;
|
||||
}
|
||||
override public function getPropertyId() : int {
|
||||
return (TimelineType.translate.ordinal << 24) + boneIndex;
|
||||
}
|
||||
|
||||
/** Sets the time and value of the specified keyframe. */
|
||||
public function setFrame (frameIndex:int, time:Number, x:Number, y:Number) : void {
|
||||
frameIndex *= ENTRIES;
|
||||
frames[frameIndex] = time;
|
||||
frames[int(frameIndex + X)] = x;
|
||||
frames[int(frameIndex + Y)] = y;
|
||||
}
|
||||
/** Sets the time and value of the specified keyframe. */
|
||||
public function setFrame(frameIndex : int, time : Number, x : Number, y : Number) : void {
|
||||
frameIndex *= ENTRIES;
|
||||
frames[frameIndex] = time;
|
||||
frames[int(frameIndex + X)] = x;
|
||||
frames[int(frameIndex + Y)] = y;
|
||||
}
|
||||
|
||||
override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector.<Event>, alpha:Number, setupPose:Boolean, mixingOut:Boolean) : void {
|
||||
var frames:Vector.<Number> = this.frames;
|
||||
override public function apply(skeleton : Skeleton, lastTime : Number, time : Number, firedEvents : Vector.<Event>, alpha : Number, setupPose : Boolean, mixingOut : Boolean) : void {
|
||||
var frames : Vector.<Number> = this.frames;
|
||||
|
||||
var bone:Bone = skeleton.bones[boneIndex];
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) {
|
||||
bone.x = bone.data.x;
|
||||
bone.y = bone.data.y;
|
||||
var bone : Bone = skeleton.bones[boneIndex];
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) {
|
||||
bone.x = bone.data.x;
|
||||
bone.y = bone.data.y;
|
||||
}
|
||||
return;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var x:Number, y:Number;
|
||||
if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame.
|
||||
x = frames[frames.length + PREV_X];
|
||||
y = frames[frames.length + PREV_Y];
|
||||
} else {
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
var frame:int = Animation.binarySearch(frames, time, ENTRIES);
|
||||
x = frames[frame + PREV_X];
|
||||
y = frames[frame + PREV_Y];
|
||||
var frameTime:Number = frames[frame];
|
||||
var percent:Number = getCurvePercent(frame / ENTRIES - 1,
|
||||
1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
var x : Number, y : Number;
|
||||
if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame.
|
||||
x = frames[frames.length + PREV_X];
|
||||
y = frames[frames.length + PREV_Y];
|
||||
} else {
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
var frame : int = Animation.binarySearch(frames, time, ENTRIES);
|
||||
x = frames[frame + PREV_X];
|
||||
y = frames[frame + PREV_Y];
|
||||
var frameTime : Number = frames[frame];
|
||||
var percent : Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
|
||||
x += (frames[frame + X] - x) * percent;
|
||||
y += (frames[frame + Y] - y) * percent;
|
||||
}
|
||||
if (setupPose) {
|
||||
bone.x = bone.data.x + x * alpha;
|
||||
bone.y = bone.data.y + y * alpha;
|
||||
} else {
|
||||
bone.x += (bone.data.x + x - bone.x) * alpha;
|
||||
bone.y += (bone.data.y + y - bone.y) * alpha;
|
||||
x += (frames[frame + X] - x) * percent;
|
||||
y += (frames[frame + Y] - y) * percent;
|
||||
}
|
||||
if (setupPose) {
|
||||
bone.x = bone.data.x + x * alpha;
|
||||
bone.y = bone.data.y + y * alpha;
|
||||
} else {
|
||||
bone.x += (bone.data.x + x - bone.x) * alpha;
|
||||
bone.y += (bone.data.y + y - bone.y) * alpha;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -30,99 +30,96 @@
|
||||
|
||||
package spine.animation {
|
||||
import spine.Color;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
import spine.Slot;
|
||||
import spine.Event;
|
||||
import spine.Skeleton;
|
||||
import spine.Slot;
|
||||
|
||||
public class TwoColorTimeline extends CurveTimeline {
|
||||
static public const ENTRIES:int = 8;
|
||||
static internal const PREV_TIME:int = -8, PREV_R:int = -7, PREV_G:int = -6, PREV_B:int = -5, PREV_A:int = -4;
|
||||
static internal const PREV_R2:int = -3, PREV_G2:int = -2, PREV_B2:int = -1;
|
||||
static internal const R:int = 1, G:int = 2, B:int = 3, A:int = 4, R2:int = 5, G2:int = 6, B2:int = 7;
|
||||
public class TwoColorTimeline extends CurveTimeline {
|
||||
static public const ENTRIES : int = 8;
|
||||
static internal const PREV_TIME : int = -8, PREV_R : int = -7, PREV_G : int = -6, PREV_B : int = -5, PREV_A : int = -4;
|
||||
static internal const PREV_R2 : int = -3, PREV_G2 : int = -2, PREV_B2 : int = -1;
|
||||
static internal const R : int = 1, G : int = 2, B : int = 3, A : int = 4, R2 : int = 5, G2 : int = 6, B2 : int = 7;
|
||||
public var slotIndex : int;
|
||||
public var frames : Vector.<Number>; // time, r, g, b, a, ...
|
||||
|
||||
public var slotIndex:int;
|
||||
public var frames:Vector.<Number>; // time, r, g, b, a, ...
|
||||
|
||||
public function TwoColorTimeline (frameCount:int) {
|
||||
super(frameCount);
|
||||
frames = new Vector.<Number>(frameCount * ENTRIES, true);
|
||||
}
|
||||
|
||||
override public function getPropertyId () : int {
|
||||
return (TimelineType.twoColor.ordinal << 24) + slotIndex;
|
||||
}
|
||||
|
||||
/** Sets the time and value of the specified keyframe. */
|
||||
public function setFrame (frameIndex:int, time:Number, r:Number, g:Number, b:Number, a:Number, r2:Number, g2:Number, b2:Number) : void {
|
||||
frameIndex *= TwoColorTimeline.ENTRIES;
|
||||
this.frames[frameIndex] = time;
|
||||
this.frames[frameIndex + TwoColorTimeline.R] = r;
|
||||
this.frames[frameIndex + TwoColorTimeline.G] = g;
|
||||
this.frames[frameIndex + TwoColorTimeline.B] = b;
|
||||
this.frames[frameIndex + TwoColorTimeline.A] = a;
|
||||
this.frames[frameIndex + TwoColorTimeline.R2] = r2;
|
||||
this.frames[frameIndex + TwoColorTimeline.G2] = g2;
|
||||
this.frames[frameIndex + TwoColorTimeline.B2] = b2;
|
||||
}
|
||||
|
||||
override public function apply (skeleton:Skeleton, lastTime:Number, time:Number, firedEvents:Vector.<Event>, alpha:Number, setupPose:Boolean, mixingOut:Boolean) : void {
|
||||
var frames:Vector.<Number> = this.frames;
|
||||
var slot:Slot = skeleton.slots[slotIndex];
|
||||
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) {
|
||||
slot.color.setFromColor(slot.data.color);
|
||||
slot.darkColor.setFromColor(slot.data.darkColor);
|
||||
}
|
||||
return;
|
||||
public function TwoColorTimeline(frameCount : int) {
|
||||
super(frameCount);
|
||||
frames = new Vector.<Number>(frameCount * ENTRIES, true);
|
||||
}
|
||||
|
||||
var r:Number, g:Number, b:Number, a:Number, r2:Number, g2:Number, b2:Number;
|
||||
if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame.
|
||||
var i:int = frames.length;
|
||||
r = frames[i + PREV_R];
|
||||
g = frames[i + PREV_G];
|
||||
b = frames[i + PREV_B];
|
||||
a = frames[i + PREV_A];
|
||||
r2 = frames[i + PREV_R2];
|
||||
g2 = frames[i + PREV_G2];
|
||||
b2 = frames[i + PREV_B2];
|
||||
} else {
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
var frame:int = Animation.binarySearch(frames, time, ENTRIES);
|
||||
r = frames[frame + PREV_R];
|
||||
g = frames[frame + PREV_G];
|
||||
b = frames[frame + PREV_B];
|
||||
a = frames[frame + PREV_A];
|
||||
r2 = frames[frame + PREV_R2];
|
||||
g2 = frames[frame + PREV_G2];
|
||||
b2 = frames[frame + PREV_B2];
|
||||
var frameTime:Number = frames[frame];
|
||||
var percent:Number = getCurvePercent(frame / ENTRIES - 1,
|
||||
1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
override public function getPropertyId() : int {
|
||||
return (TimelineType.twoColor.ordinal << 24) + slotIndex;
|
||||
}
|
||||
|
||||
r += (frames[frame + R] - r) * percent;
|
||||
g += (frames[frame + G] - g) * percent;
|
||||
b += (frames[frame + B] - b) * percent;
|
||||
a += (frames[frame + A] - a) * percent;
|
||||
r2 += (frames[frame + R2] - a) * percent;
|
||||
g2 += (frames[frame + G2] - a) * percent;
|
||||
b2 += (frames[frame + B2] - a) * percent;
|
||||
}
|
||||
if (alpha == 1) {
|
||||
slot.color.setFrom(r, g, b, a);
|
||||
slot.darkColor.setFrom(r2, g2, b2, 1);
|
||||
} else {
|
||||
var light:Color = slot.color;
|
||||
var dark:Color = slot.darkColor;
|
||||
if (setupPose) {
|
||||
light.setFromColor(slot.data.color);
|
||||
dark.setFromColor(slot.data.darkColor);
|
||||
/** Sets the time and value of the specified keyframe. */
|
||||
public function setFrame(frameIndex : int, time : Number, r : Number, g : Number, b : Number, a : Number, r2 : Number, g2 : Number, b2 : Number) : void {
|
||||
frameIndex *= TwoColorTimeline.ENTRIES;
|
||||
this.frames[frameIndex] = time;
|
||||
this.frames[frameIndex + TwoColorTimeline.R] = r;
|
||||
this.frames[frameIndex + TwoColorTimeline.G] = g;
|
||||
this.frames[frameIndex + TwoColorTimeline.B] = b;
|
||||
this.frames[frameIndex + TwoColorTimeline.A] = a;
|
||||
this.frames[frameIndex + TwoColorTimeline.R2] = r2;
|
||||
this.frames[frameIndex + TwoColorTimeline.G2] = g2;
|
||||
this.frames[frameIndex + TwoColorTimeline.B2] = b2;
|
||||
}
|
||||
|
||||
override public function apply(skeleton : Skeleton, lastTime : Number, time : Number, firedEvents : Vector.<Event>, alpha : Number, setupPose : Boolean, mixingOut : Boolean) : void {
|
||||
var frames : Vector.<Number> = this.frames;
|
||||
var slot : Slot = skeleton.slots[slotIndex];
|
||||
|
||||
if (time < frames[0]) {
|
||||
if (setupPose) {
|
||||
slot.color.setFromColor(slot.data.color);
|
||||
slot.darkColor.setFromColor(slot.data.darkColor);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
var r : Number, g : Number, b : Number, a : Number, r2 : Number, g2 : Number, b2 : Number;
|
||||
if (time >= frames[frames.length - ENTRIES]) { // Time is after last frame.
|
||||
var i : int = frames.length;
|
||||
r = frames[i + PREV_R];
|
||||
g = frames[i + PREV_G];
|
||||
b = frames[i + PREV_B];
|
||||
a = frames[i + PREV_A];
|
||||
r2 = frames[i + PREV_R2];
|
||||
g2 = frames[i + PREV_G2];
|
||||
b2 = frames[i + PREV_B2];
|
||||
} else {
|
||||
// Interpolate between the previous frame and the current frame.
|
||||
var frame : int = Animation.binarySearch(frames, time, ENTRIES);
|
||||
r = frames[frame + PREV_R];
|
||||
g = frames[frame + PREV_G];
|
||||
b = frames[frame + PREV_B];
|
||||
a = frames[frame + PREV_A];
|
||||
r2 = frames[frame + PREV_R2];
|
||||
g2 = frames[frame + PREV_G2];
|
||||
b2 = frames[frame + PREV_B2];
|
||||
var frameTime : Number = frames[frame];
|
||||
var percent : Number = getCurvePercent(frame / ENTRIES - 1, 1 - (time - frameTime) / (frames[frame + PREV_TIME] - frameTime));
|
||||
|
||||
r += (frames[frame + R] - r) * percent;
|
||||
g += (frames[frame + G] - g) * percent;
|
||||
b += (frames[frame + B] - b) * percent;
|
||||
a += (frames[frame + A] - a) * percent;
|
||||
r2 += (frames[frame + R2] - r2) * percent;
|
||||
g2 += (frames[frame + G2] - g2) * percent;
|
||||
b2 += (frames[frame + B2] - b2) * percent;
|
||||
}
|
||||
if (alpha == 1) {
|
||||
slot.color.setFrom(r, g, b, a);
|
||||
slot.darkColor.setFrom(r2, g2, b2, 1);
|
||||
} else {
|
||||
var light : Color = slot.color;
|
||||
var dark : Color = slot.darkColor;
|
||||
if (setupPose) {
|
||||
light.setFromColor(slot.data.color);
|
||||
dark.setFromColor(slot.data.darkColor);
|
||||
}
|
||||
light.add((r - light.r) * alpha, (g - light.g) * alpha, (b - light.b) * alpha, (a - light.a) * alpha);
|
||||
dark.add((r2 - dark.r) * alpha, (g2 - dark.g) * alpha, (b2 - dark.b) * alpha, 0);
|
||||
}
|
||||
light.add((r - light.r) * alpha, (g - light.g) * alpha, (b - light.b) * alpha, (a - light.a) * alpha);
|
||||
dark.add((r2 - dark.r) * alpha, (g2 - dark.g) * alpha, (b2 - dark.b) * alpha, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,177 +29,175 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.atlas {
|
||||
import flash.utils.ByteArray;
|
||||
import flash.utils.ByteArray;
|
||||
|
||||
public class Atlas {
|
||||
private var pages:Vector.<AtlasPage> = new Vector.<AtlasPage>();
|
||||
private var regions:Vector.<AtlasRegion> = new Vector.<AtlasRegion>();
|
||||
private var textureLoader:TextureLoader;
|
||||
public class Atlas {
|
||||
private var pages : Vector.<AtlasPage> = new Vector.<AtlasPage>();
|
||||
private var regions : Vector.<AtlasRegion> = new Vector.<AtlasRegion>();
|
||||
private var textureLoader : TextureLoader;
|
||||
|
||||
/** @param object A String or ByteArray. */
|
||||
public function Atlas (object:*, textureLoader:TextureLoader) {
|
||||
if (!object)
|
||||
return;
|
||||
if (object is String)
|
||||
load(String(object), textureLoader);
|
||||
else if (object is ByteArray)
|
||||
load(ByteArray(object).readUTFBytes(ByteArray(object).length), textureLoader);
|
||||
else
|
||||
throw new ArgumentError("object must be a TextureAtlas or AttachmentLoader.");
|
||||
}
|
||||
/** @param object A String or ByteArray. */
|
||||
public function Atlas(object : *, textureLoader : TextureLoader) {
|
||||
if (!object)
|
||||
return;
|
||||
if (object is String)
|
||||
load(String(object), textureLoader);
|
||||
else if (object is ByteArray)
|
||||
load(ByteArray(object).readUTFBytes(ByteArray(object).length), textureLoader);
|
||||
else
|
||||
throw new ArgumentError("object must be a TextureAtlas or AttachmentLoader.");
|
||||
}
|
||||
|
||||
protected function load (atlasText:String, textureLoader:TextureLoader) : void {
|
||||
if (textureLoader == null)
|
||||
throw new ArgumentError("textureLoader cannot be null.");
|
||||
this.textureLoader = textureLoader;
|
||||
protected function load(atlasText : String, textureLoader : TextureLoader) : void {
|
||||
if (textureLoader == null)
|
||||
throw new ArgumentError("textureLoader cannot be null.");
|
||||
this.textureLoader = textureLoader;
|
||||
|
||||
var reader:Reader = new Reader(atlasText);
|
||||
var tuple:Array = new Array();
|
||||
tuple.length = 4;
|
||||
var page:AtlasPage = null;
|
||||
while (true) {
|
||||
var line:String = reader.readLine();
|
||||
if (line == null)
|
||||
break;
|
||||
line = reader.trim(line);
|
||||
if (line.length == 0)
|
||||
page = null;
|
||||
else if (!page) {
|
||||
page = new AtlasPage();
|
||||
page.name = line;
|
||||
|
||||
if (reader.readTuple(tuple) == 2) { // size is only optional for an atlas packed with an old TexturePacker.
|
||||
page.width = parseInt(tuple[0]);
|
||||
page.height = parseInt(tuple[1]);
|
||||
reader.readTuple(tuple);
|
||||
}
|
||||
page.format = Format[tuple[0]];
|
||||
|
||||
reader.readTuple(tuple);
|
||||
page.minFilter = TextureFilter[tuple[0]];
|
||||
page.magFilter = TextureFilter[tuple[1]];
|
||||
|
||||
var direction:String = reader.readValue();
|
||||
page.uWrap = TextureWrap.clampToEdge;
|
||||
page.vWrap = TextureWrap.clampToEdge;
|
||||
if (direction == "x")
|
||||
page.uWrap = TextureWrap.repeat;
|
||||
else if (direction == "y")
|
||||
page.vWrap = TextureWrap.repeat;
|
||||
else if (direction == "xy")
|
||||
page.uWrap = page.vWrap = TextureWrap.repeat;
|
||||
|
||||
textureLoader.loadPage(page, line);
|
||||
|
||||
pages[pages.length] = page;
|
||||
|
||||
} else {
|
||||
var region:AtlasRegion = new AtlasRegion();
|
||||
region.name = line;
|
||||
region.page = page;
|
||||
|
||||
region.rotate = reader.readValue() == "true";
|
||||
|
||||
reader.readTuple(tuple);
|
||||
var x:int = parseInt(tuple[0]);
|
||||
var y:int = parseInt(tuple[1]);
|
||||
|
||||
reader.readTuple(tuple);
|
||||
var width:int = parseInt(tuple[0]);
|
||||
var height:int = parseInt(tuple[1]);
|
||||
|
||||
region.u = x / page.width;
|
||||
region.v = y / page.height;
|
||||
if (region.rotate) {
|
||||
region.u2 = (x + height) / page.width;
|
||||
region.v2 = (y + width) / page.height;
|
||||
} else {
|
||||
region.u2 = (x + width) / page.width;
|
||||
region.v2 = (y + height) / page.height;
|
||||
}
|
||||
region.x = x;
|
||||
region.y = y;
|
||||
region.width = Math.abs(width);
|
||||
region.height = Math.abs(height);
|
||||
|
||||
if (reader.readTuple(tuple) == 4) { // split is optional
|
||||
region.splits = new Vector.<int>(parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3]));
|
||||
|
||||
if (reader.readTuple(tuple) == 4) { // pad is optional, but only present with splits
|
||||
region.pads = new Vector.<int>(parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3]));
|
||||
var reader : Reader = new Reader(atlasText);
|
||||
var tuple : Array = new Array();
|
||||
tuple.length = 4;
|
||||
var page : AtlasPage = null;
|
||||
while (true) {
|
||||
var line : String = reader.readLine();
|
||||
if (line == null)
|
||||
break;
|
||||
line = reader.trim(line);
|
||||
if (line.length == 0)
|
||||
page = null;
|
||||
else if (!page) {
|
||||
page = new AtlasPage();
|
||||
page.name = line;
|
||||
|
||||
if (reader.readTuple(tuple) == 2) { // size is only optional for an atlas packed with an old TexturePacker.
|
||||
page.width = parseInt(tuple[0]);
|
||||
page.height = parseInt(tuple[1]);
|
||||
reader.readTuple(tuple);
|
||||
}
|
||||
page.format = Format[tuple[0]];
|
||||
|
||||
reader.readTuple(tuple);
|
||||
page.minFilter = TextureFilter[tuple[0]];
|
||||
page.magFilter = TextureFilter[tuple[1]];
|
||||
|
||||
var direction : String = reader.readValue();
|
||||
page.uWrap = TextureWrap.clampToEdge;
|
||||
page.vWrap = TextureWrap.clampToEdge;
|
||||
if (direction == "x")
|
||||
page.uWrap = TextureWrap.repeat;
|
||||
else if (direction == "y")
|
||||
page.vWrap = TextureWrap.repeat;
|
||||
else if (direction == "xy")
|
||||
page.uWrap = page.vWrap = TextureWrap.repeat;
|
||||
|
||||
textureLoader.loadPage(page, line);
|
||||
|
||||
pages[pages.length] = page;
|
||||
} else {
|
||||
var region : AtlasRegion = new AtlasRegion();
|
||||
region.name = line;
|
||||
region.page = page;
|
||||
|
||||
region.rotate = reader.readValue() == "true";
|
||||
|
||||
reader.readTuple(tuple);
|
||||
var x : int = parseInt(tuple[0]);
|
||||
var y : int = parseInt(tuple[1]);
|
||||
|
||||
reader.readTuple(tuple);
|
||||
var width : int = parseInt(tuple[0]);
|
||||
var height : int = parseInt(tuple[1]);
|
||||
|
||||
region.u = x / page.width;
|
||||
region.v = y / page.height;
|
||||
if (region.rotate) {
|
||||
region.u2 = (x + height) / page.width;
|
||||
region.v2 = (y + width) / page.height;
|
||||
} else {
|
||||
region.u2 = (x + width) / page.width;
|
||||
region.v2 = (y + height) / page.height;
|
||||
}
|
||||
region.x = x;
|
||||
region.y = y;
|
||||
region.width = Math.abs(width);
|
||||
region.height = Math.abs(height);
|
||||
|
||||
if (reader.readTuple(tuple) == 4) { // split is optional
|
||||
region.splits = new Vector.<int>(parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3]));
|
||||
|
||||
if (reader.readTuple(tuple) == 4) { // pad is optional, but only present with splits
|
||||
region.pads = new Vector.<int>(parseInt(tuple[0]), parseInt(tuple[1]), parseInt(tuple[2]), parseInt(tuple[3]));
|
||||
|
||||
reader.readTuple(tuple);
|
||||
}
|
||||
}
|
||||
|
||||
region.originalWidth = parseInt(tuple[0]);
|
||||
region.originalHeight = parseInt(tuple[1]);
|
||||
|
||||
reader.readTuple(tuple);
|
||||
region.offsetX = parseInt(tuple[0]);
|
||||
region.offsetY = parseInt(tuple[1]);
|
||||
|
||||
region.index = parseInt(reader.readValue());
|
||||
|
||||
textureLoader.loadRegion(region);
|
||||
regions[regions.length] = region;
|
||||
}
|
||||
|
||||
region.originalWidth = parseInt(tuple[0]);
|
||||
region.originalHeight = parseInt(tuple[1]);
|
||||
|
||||
reader.readTuple(tuple);
|
||||
region.offsetX = parseInt(tuple[0]);
|
||||
region.offsetY = parseInt(tuple[1]);
|
||||
|
||||
region.index = parseInt(reader.readValue());
|
||||
|
||||
textureLoader.loadRegion(region);
|
||||
regions[regions.length] = region;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns the first region found with the specified name. This method uses string comparison to find the region, so the result
|
||||
* should be cached rather than calling this method multiple times.
|
||||
* @return The region, or null. */
|
||||
public function findRegion (name:String) : AtlasRegion {
|
||||
for (var i:int = 0, n:int = regions.length; i < n; i++)
|
||||
if (regions[i].name == name)
|
||||
return regions[i];
|
||||
return null;
|
||||
}
|
||||
/** Returns the first region found with the specified name. This method uses string comparison to find the region, so the result
|
||||
* should be cached rather than calling this method multiple times.
|
||||
* @return The region, or null. */
|
||||
public function findRegion(name : String) : AtlasRegion {
|
||||
for (var i : int = 0, n : int = regions.length; i < n; i++)
|
||||
if (regions[i].name == name)
|
||||
return regions[i];
|
||||
return null;
|
||||
}
|
||||
|
||||
public function dispose () : void {
|
||||
for (var i:int = 0, n:int = pages.length; i < n; i++)
|
||||
textureLoader.unloadPage(pages[i]);
|
||||
public function dispose() : void {
|
||||
for (var i : int = 0, n : int = pages.length; i < n; i++)
|
||||
textureLoader.unloadPage(pages[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class Reader {
|
||||
private var lines:Array;
|
||||
private var index:int;
|
||||
private var lines : Array;
|
||||
private var index : int;
|
||||
|
||||
public function Reader (text:String) {
|
||||
public function Reader(text : String) {
|
||||
lines = text.split(/\r\n|\r|\n/);
|
||||
}
|
||||
|
||||
public function trim (value:String) : String {
|
||||
public function trim(value : String) : String {
|
||||
return value.replace(/^\s+|\s+$/gs, "");
|
||||
}
|
||||
|
||||
public function readLine () : String {
|
||||
public function readLine() : String {
|
||||
if (index >= lines.length)
|
||||
return null;
|
||||
return lines[index++];
|
||||
}
|
||||
|
||||
public function readValue () : String {
|
||||
var line:String = readLine();
|
||||
var colon:int = line.indexOf(":");
|
||||
public function readValue() : String {
|
||||
var line : String = readLine();
|
||||
var colon : int = line.indexOf(":");
|
||||
if (colon == -1)
|
||||
throw new Error("Invalid line: " + line);
|
||||
return trim(line.substring(colon + 1));
|
||||
}
|
||||
|
||||
/** Returns the number of tuple values read (1, 2 or 4). */
|
||||
public function readTuple (tuple:Array) : int {
|
||||
var line:String = readLine();
|
||||
var colon:int = line.indexOf(":");
|
||||
public function readTuple(tuple : Array) : int {
|
||||
var line : String = readLine();
|
||||
var colon : int = line.indexOf(":");
|
||||
if (colon == -1)
|
||||
throw new Error("Invalid line: " + line);
|
||||
var i:int = 0, lastMatch:int = colon + 1;
|
||||
var i : int = 0, lastMatch : int = colon + 1;
|
||||
for (; i < 3; i++) {
|
||||
var comma:int = line.indexOf(",", lastMatch);
|
||||
var comma : int = line.indexOf(",", lastMatch);
|
||||
if (comma == -1) break;
|
||||
tuple[i] = trim(line.substr(lastMatch, comma - lastMatch));
|
||||
lastMatch = comma + 1;
|
||||
@ -207,4 +205,4 @@ class Reader {
|
||||
tuple[i] = trim(line.substring(lastMatch));
|
||||
return i + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -29,20 +29,18 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.atlas {
|
||||
public class AtlasPage {
|
||||
public var name : String;
|
||||
public var format : Format;
|
||||
public var minFilter : TextureFilter;
|
||||
public var magFilter : TextureFilter;
|
||||
public var uWrap : TextureWrap;
|
||||
public var vWrap : TextureWrap;
|
||||
public var rendererObject : Object;
|
||||
public var width : int;
|
||||
public var height : int;
|
||||
|
||||
public class AtlasPage {
|
||||
public var name:String;
|
||||
public var format:Format;
|
||||
public var minFilter:TextureFilter;
|
||||
public var magFilter:TextureFilter;
|
||||
public var uWrap:TextureWrap;
|
||||
public var vWrap:TextureWrap;
|
||||
public var rendererObject:Object;
|
||||
public var width:int;
|
||||
public var height:int;
|
||||
|
||||
public function AtlasPage () {
|
||||
public function AtlasPage() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,30 +29,28 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.atlas {
|
||||
public class AtlasRegion {
|
||||
public var page : AtlasPage;
|
||||
public var name : String;
|
||||
public var x : int;
|
||||
public var y : int;
|
||||
public var width : int;
|
||||
public var height : int;
|
||||
public var u : Number;
|
||||
public var v : Number;
|
||||
public var u2 : Number;
|
||||
public var v2 : Number;
|
||||
public var offsetX : Number;
|
||||
public var offsetY : Number;
|
||||
public var originalWidth : int;
|
||||
public var originalHeight : int;
|
||||
public var index : int;
|
||||
public var rotate : Boolean;
|
||||
public var splits : Vector.<int>;
|
||||
public var pads : Vector.<int>;
|
||||
public var rendererObject : Object;
|
||||
|
||||
public class AtlasRegion {
|
||||
public var page:AtlasPage;
|
||||
public var name:String;
|
||||
public var x:int;
|
||||
public var y:int;
|
||||
public var width:int;
|
||||
public var height:int;
|
||||
public var u:Number;
|
||||
public var v:Number;
|
||||
public var u2:Number;
|
||||
public var v2:Number;
|
||||
public var offsetX:Number;
|
||||
public var offsetY:Number;
|
||||
public var originalWidth:int;
|
||||
public var originalHeight:int;
|
||||
public var index:int;
|
||||
public var rotate:Boolean;
|
||||
public var splits:Vector.<int>;
|
||||
public var pads:Vector.<int>;
|
||||
public var rendererObject:Object;
|
||||
|
||||
public function AtlasRegion () {
|
||||
public function AtlasRegion() {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,23 +29,20 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.atlas {
|
||||
public class Format {
|
||||
public static const alpha : Format = new Format(0, "alpha");
|
||||
public static const intensity : Format = new Format(1, "intensity");
|
||||
public static const luminanceAlpha : Format = new Format(2, "luminanceAlpha");
|
||||
public static const rgb565 : Format = new Format(3, "rgb565");
|
||||
public static const rgba4444 : Format = new Format(4, "rgba4444");
|
||||
public static const rgb888 : Format = new Format(5, "rgb888");
|
||||
public static const rgba8888 : Format = new Format(6, "rgba8888");
|
||||
public var ordinal : int;
|
||||
public var name : String;
|
||||
|
||||
public class Format {
|
||||
public static const alpha:Format = new Format(0, "alpha");
|
||||
public static const intensity:Format = new Format(1, "intensity");
|
||||
public static const luminanceAlpha:Format = new Format(2, "luminanceAlpha");
|
||||
public static const rgb565:Format = new Format(3, "rgb565");
|
||||
public static const rgba4444:Format = new Format(4, "rgba4444");
|
||||
public static const rgb888:Format = new Format(5, "rgb888");
|
||||
public static const rgba8888:Format = new Format(6, "rgba8888");
|
||||
|
||||
public var ordinal:int;
|
||||
public var name:String;
|
||||
|
||||
public function Format (ordinal:int, name:String) {
|
||||
this.ordinal = ordinal;
|
||||
this.name = name;
|
||||
public function Format(ordinal : int, name : String) {
|
||||
this.ordinal = ordinal;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,23 +29,20 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.atlas {
|
||||
public class TextureFilter {
|
||||
public static const nearest : TextureFilter = new TextureFilter(0, "nearest");
|
||||
public static const linear : TextureFilter = new TextureFilter(1, "linear");
|
||||
public static const mipMap : TextureFilter = new TextureFilter(2, "mipMap");
|
||||
public static const mipMapNearestNearest : TextureFilter = new TextureFilter(3, "mipMapNearestNearest");
|
||||
public static const mipMapLinearNearest : TextureFilter = new TextureFilter(4, "mipMapLinearNearest");
|
||||
public static const mipMapNearestLinear : TextureFilter = new TextureFilter(5, "mipMapNearestLinear");
|
||||
public static const mipMapLinearLinear : TextureFilter = new TextureFilter(6, "mipMapLinearLinear");
|
||||
public var ordinal : int;
|
||||
public var name : String;
|
||||
|
||||
public class TextureFilter {
|
||||
public static const nearest:TextureFilter = new TextureFilter(0, "nearest");
|
||||
public static const linear:TextureFilter = new TextureFilter(1, "linear");
|
||||
public static const mipMap:TextureFilter = new TextureFilter(2, "mipMap");
|
||||
public static const mipMapNearestNearest:TextureFilter = new TextureFilter(3, "mipMapNearestNearest");
|
||||
public static const mipMapLinearNearest:TextureFilter = new TextureFilter(4, "mipMapLinearNearest");
|
||||
public static const mipMapNearestLinear:TextureFilter = new TextureFilter(5, "mipMapNearestLinear");
|
||||
public static const mipMapLinearLinear:TextureFilter = new TextureFilter(6, "mipMapLinearLinear");
|
||||
|
||||
public var ordinal:int;
|
||||
public var name:String;
|
||||
|
||||
public function TextureFilter (ordinal:int, name:String) {
|
||||
this.ordinal = ordinal;
|
||||
this.name = name;
|
||||
public function TextureFilter(ordinal : int, name : String) {
|
||||
this.ordinal = ordinal;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,11 +29,11 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.atlas {
|
||||
public interface TextureLoader {
|
||||
function loadPage(page : AtlasPage, path : String) : void;
|
||||
|
||||
public interface TextureLoader {
|
||||
function loadPage (page:AtlasPage, path:String) : void;
|
||||
function loadRegion (region:AtlasRegion) : void;
|
||||
function unloadPage (page:AtlasPage) : void;
|
||||
}
|
||||
function loadRegion(region : AtlasRegion) : void;
|
||||
|
||||
}
|
||||
function unloadPage(page : AtlasPage) : void;
|
||||
}
|
||||
}
|
||||
@ -29,19 +29,16 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.atlas {
|
||||
public class TextureWrap {
|
||||
public static const mirroredRepeat : TextureWrap = new TextureWrap(0, "mirroredRepeat");
|
||||
public static const clampToEdge : TextureWrap = new TextureWrap(1, "clampToEdge");
|
||||
public static const repeat : TextureWrap = new TextureWrap(2, "repeat");
|
||||
public var ordinal : int;
|
||||
public var name : String;
|
||||
|
||||
public class TextureWrap {
|
||||
public static const mirroredRepeat:TextureWrap = new TextureWrap(0, "mirroredRepeat");
|
||||
public static const clampToEdge:TextureWrap = new TextureWrap(1, "clampToEdge");
|
||||
public static const repeat:TextureWrap = new TextureWrap(2, "repeat");
|
||||
|
||||
public var ordinal:int;
|
||||
public var name:String;
|
||||
|
||||
public function TextureWrap (ordinal:int, name:String) {
|
||||
this.ordinal = ordinal;
|
||||
this.name = name;
|
||||
public function TextureWrap(ordinal : int, name : String) {
|
||||
this.ordinal = ordinal;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,80 +29,79 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.attachments {
|
||||
import spine.Skin;
|
||||
import spine.atlas.Atlas;
|
||||
import spine.atlas.AtlasRegion;
|
||||
import spine.Skin;
|
||||
import spine.atlas.Atlas;
|
||||
import spine.atlas.AtlasRegion;
|
||||
|
||||
public class AtlasAttachmentLoader implements AttachmentLoader {
|
||||
private var atlas:Atlas;
|
||||
public class AtlasAttachmentLoader implements AttachmentLoader {
|
||||
private var atlas : Atlas;
|
||||
|
||||
public function AtlasAttachmentLoader (atlas:Atlas) {
|
||||
if (atlas == null)
|
||||
throw new ArgumentError("atlas cannot be null.");
|
||||
this.atlas = atlas;
|
||||
}
|
||||
|
||||
public function newRegionAttachment (skin:Skin, name:String, path:String) : RegionAttachment {
|
||||
var region:AtlasRegion = atlas.findRegion(path);
|
||||
if (region == null)
|
||||
throw new Error("Region not found in atlas: " + path + " (region attachment: " + name + ")");
|
||||
var attachment:RegionAttachment = new RegionAttachment(name);
|
||||
attachment.rendererObject = region;
|
||||
var scaleX:Number = region.page.width / nextPOT(region.page.width);
|
||||
var scaleY:Number = region.page.height / nextPOT(region.page.height);
|
||||
attachment.setUVs(region.u * scaleX, region.v * scaleY, region.u2 * scaleX, region.v2 * scaleY, region.rotate);
|
||||
attachment.regionOffsetX = region.offsetX;
|
||||
attachment.regionOffsetY = region.offsetY;
|
||||
attachment.regionWidth = region.width;
|
||||
attachment.regionHeight = region.height;
|
||||
attachment.regionOriginalWidth = region.originalWidth;
|
||||
attachment.regionOriginalHeight = region.originalHeight;
|
||||
return attachment;
|
||||
}
|
||||
|
||||
public function newMeshAttachment (skin:Skin, name:String, path:String) : MeshAttachment {
|
||||
var region:AtlasRegion = atlas.findRegion(path);
|
||||
if (region == null)
|
||||
throw new Error("Region not found in atlas: " + path + " (mesh attachment: " + name + ")");
|
||||
var attachment:MeshAttachment = new MeshAttachment(name);
|
||||
attachment.rendererObject = region;
|
||||
var scaleX:Number = region.page.width / nextPOT(region.page.width);
|
||||
var scaleY:Number = region.page.height / nextPOT(region.page.height);
|
||||
attachment.regionU = region.u * scaleX;
|
||||
attachment.regionV = region.v * scaleY;
|
||||
attachment.regionU2 = region.u2 * scaleX;
|
||||
attachment.regionV2 = region.v2 * scaleY;
|
||||
attachment.regionRotate = region.rotate;
|
||||
attachment.regionOffsetX = region.offsetX;
|
||||
attachment.regionOffsetY = region.offsetY;
|
||||
attachment.regionWidth = region.width;
|
||||
attachment.regionHeight = region.height;
|
||||
attachment.regionOriginalWidth = region.originalWidth;
|
||||
attachment.regionOriginalHeight = region.originalHeight;
|
||||
return attachment;
|
||||
}
|
||||
public function AtlasAttachmentLoader(atlas : Atlas) {
|
||||
if (atlas == null)
|
||||
throw new ArgumentError("atlas cannot be null.");
|
||||
this.atlas = atlas;
|
||||
}
|
||||
|
||||
public function newBoundingBoxAttachment (skin:Skin, name:String) : BoundingBoxAttachment {
|
||||
return new BoundingBoxAttachment(name);
|
||||
}
|
||||
|
||||
public function newPathAttachment(skin:Skin, name:String) : PathAttachment {
|
||||
return new PathAttachment(name);
|
||||
}
|
||||
|
||||
public function newPointAttachment(skin:Skin, name:String) : PointAttachment {
|
||||
return new PointAttachment(name);
|
||||
}
|
||||
public function newRegionAttachment(skin : Skin, name : String, path : String) : RegionAttachment {
|
||||
var region : AtlasRegion = atlas.findRegion(path);
|
||||
if (region == null)
|
||||
throw new Error("Region not found in atlas: " + path + " (region attachment: " + name + ")");
|
||||
var attachment : RegionAttachment = new RegionAttachment(name);
|
||||
attachment.rendererObject = region;
|
||||
var scaleX : Number = region.page.width / nextPOT(region.page.width);
|
||||
var scaleY : Number = region.page.height / nextPOT(region.page.height);
|
||||
attachment.setUVs(region.u * scaleX, region.v * scaleY, region.u2 * scaleX, region.v2 * scaleY, region.rotate);
|
||||
attachment.regionOffsetX = region.offsetX;
|
||||
attachment.regionOffsetY = region.offsetY;
|
||||
attachment.regionWidth = region.width;
|
||||
attachment.regionHeight = region.height;
|
||||
attachment.regionOriginalWidth = region.originalWidth;
|
||||
attachment.regionOriginalHeight = region.originalHeight;
|
||||
return attachment;
|
||||
}
|
||||
|
||||
static public function nextPOT (value:int) : int {
|
||||
value--;
|
||||
value |= value >> 1;
|
||||
value |= value >> 2;
|
||||
value |= value >> 4;
|
||||
value |= value >> 8;
|
||||
value |= value >> 16;
|
||||
return value + 1;
|
||||
}
|
||||
}
|
||||
public function newMeshAttachment(skin : Skin, name : String, path : String) : MeshAttachment {
|
||||
var region : AtlasRegion = atlas.findRegion(path);
|
||||
if (region == null)
|
||||
throw new Error("Region not found in atlas: " + path + " (mesh attachment: " + name + ")");
|
||||
var attachment : MeshAttachment = new MeshAttachment(name);
|
||||
attachment.rendererObject = region;
|
||||
var scaleX : Number = region.page.width / nextPOT(region.page.width);
|
||||
var scaleY : Number = region.page.height / nextPOT(region.page.height);
|
||||
attachment.regionU = region.u * scaleX;
|
||||
attachment.regionV = region.v * scaleY;
|
||||
attachment.regionU2 = region.u2 * scaleX;
|
||||
attachment.regionV2 = region.v2 * scaleY;
|
||||
attachment.regionRotate = region.rotate;
|
||||
attachment.regionOffsetX = region.offsetX;
|
||||
attachment.regionOffsetY = region.offsetY;
|
||||
attachment.regionWidth = region.width;
|
||||
attachment.regionHeight = region.height;
|
||||
attachment.regionOriginalWidth = region.originalWidth;
|
||||
attachment.regionOriginalHeight = region.originalHeight;
|
||||
return attachment;
|
||||
}
|
||||
|
||||
}
|
||||
public function newBoundingBoxAttachment(skin : Skin, name : String) : BoundingBoxAttachment {
|
||||
return new BoundingBoxAttachment(name);
|
||||
}
|
||||
|
||||
public function newPathAttachment(skin : Skin, name : String) : PathAttachment {
|
||||
return new PathAttachment(name);
|
||||
}
|
||||
|
||||
public function newPointAttachment(skin : Skin, name : String) : PointAttachment {
|
||||
return new PointAttachment(name);
|
||||
}
|
||||
|
||||
static public function nextPOT(value : int) : int {
|
||||
value--;
|
||||
value |= value >> 1;
|
||||
value |= value >> 2;
|
||||
value |= value >> 4;
|
||||
value |= value >> 8;
|
||||
value |= value >> 16;
|
||||
return value + 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -29,23 +29,21 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.attachments {
|
||||
public class Attachment {
|
||||
internal var _name : String;
|
||||
|
||||
public class Attachment {
|
||||
internal var _name:String;
|
||||
public function Attachment(name : String) {
|
||||
if (name == null)
|
||||
throw new ArgumentError("name cannot be null.");
|
||||
_name = name;
|
||||
}
|
||||
|
||||
public function Attachment (name:String) {
|
||||
if (name == null)
|
||||
throw new ArgumentError("name cannot be null.");
|
||||
_name = name;
|
||||
public function get name() : String {
|
||||
return _name;
|
||||
}
|
||||
|
||||
public function toString() : String {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
public function get name () : String {
|
||||
return _name;
|
||||
}
|
||||
|
||||
public function toString () : String {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,23 +29,22 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.attachments {
|
||||
import spine.Skin;
|
||||
import spine.Skin;
|
||||
|
||||
public interface AttachmentLoader {
|
||||
/** @return May be null to not load an attachment. */
|
||||
function newRegionAttachment (skin:Skin, name:String, path:String) : RegionAttachment;
|
||||
public interface AttachmentLoader {
|
||||
/** @return May be null to not load an attachment. */
|
||||
function newRegionAttachment(skin : Skin, name : String, path : String) : RegionAttachment;
|
||||
|
||||
/** @return May be null to not load an attachment. */
|
||||
function newMeshAttachment (skin:Skin, name:String, path:String) : MeshAttachment;
|
||||
/** @return May be null to not load an attachment. */
|
||||
function newMeshAttachment(skin : Skin, name : String, path : String) : MeshAttachment;
|
||||
|
||||
/** @return May be null to not load an attachment. */
|
||||
function newBoundingBoxAttachment (skin:Skin, name:String) : BoundingBoxAttachment;
|
||||
|
||||
/** @return May be null to not load an attachment */
|
||||
function newPathAttachment(skin:Skin, name:String): PathAttachment;
|
||||
|
||||
/** @return May be null to not load an attachment */
|
||||
function newPointAttachment(skin:Skin, name:String): PointAttachment;
|
||||
}
|
||||
/** @return May be null to not load an attachment. */
|
||||
function newBoundingBoxAttachment(skin : Skin, name : String) : BoundingBoxAttachment;
|
||||
|
||||
}
|
||||
/** @return May be null to not load an attachment */
|
||||
function newPathAttachment(skin : Skin, name : String) : PathAttachment;
|
||||
|
||||
/** @return May be null to not load an attachment */
|
||||
function newPointAttachment(skin : Skin, name : String) : PointAttachment;
|
||||
}
|
||||
}
|
||||
@ -29,23 +29,20 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.attachments {
|
||||
public class AttachmentType {
|
||||
public static const region : AttachmentType = new AttachmentType(0, "region");
|
||||
public static const regionsequence : AttachmentType = new AttachmentType(1, "regionsequence");
|
||||
public static const boundingbox : AttachmentType = new AttachmentType(2, "boundingbox");
|
||||
public static const mesh : AttachmentType = new AttachmentType(3, "mesh");
|
||||
public static const linkedmesh : AttachmentType = new AttachmentType(3, "linkedmesh");
|
||||
public static const path : AttachmentType = new AttachmentType(4, "path");
|
||||
public static const point : AttachmentType = new AttachmentType(5, "point");
|
||||
public var ordinal : int;
|
||||
public var name : String;
|
||||
|
||||
public class AttachmentType {
|
||||
public static const region:AttachmentType = new AttachmentType(0, "region");
|
||||
public static const regionsequence:AttachmentType = new AttachmentType(1, "regionsequence");
|
||||
public static const boundingbox:AttachmentType = new AttachmentType(2, "boundingbox");
|
||||
public static const mesh:AttachmentType = new AttachmentType(3, "mesh");
|
||||
public static const linkedmesh:AttachmentType = new AttachmentType(3, "linkedmesh");
|
||||
public static const path:AttachmentType = new AttachmentType(4, "path");
|
||||
public static const point:AttachmentType = new AttachmentType(5, "point");
|
||||
|
||||
public var ordinal:int;
|
||||
public var name:String;
|
||||
|
||||
public function AttachmentType (ordinal:int, name:String) {
|
||||
this.ordinal = ordinal;
|
||||
this.name = name;
|
||||
public function AttachmentType(ordinal : int, name : String) {
|
||||
this.ordinal = ordinal;
|
||||
this.name = name;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,10 +29,9 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.attachments {
|
||||
|
||||
public dynamic class BoundingBoxAttachment extends VertexAttachment {
|
||||
public function BoundingBoxAttachment (name:String) {
|
||||
super(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
public dynamic class BoundingBoxAttachment extends VertexAttachment {
|
||||
public function BoundingBoxAttachment(name : String) {
|
||||
super(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -29,79 +29,76 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.attachments {
|
||||
import spine.Color;
|
||||
import spine.Color;
|
||||
|
||||
public dynamic class MeshAttachment extends VertexAttachment {
|
||||
public var uvs:Vector.<Number>;
|
||||
public var regionUVs:Vector.<Number>;
|
||||
public var triangles:Vector.<uint>;
|
||||
public var color:Color = new Color(1, 1, 1, 1);
|
||||
public var hullLength:int;
|
||||
private var _parentMesh:MeshAttachment;
|
||||
public var inheritDeform:Boolean;
|
||||
public dynamic class MeshAttachment extends VertexAttachment {
|
||||
public var uvs : Vector.<Number>;
|
||||
public var regionUVs : Vector.<Number>;
|
||||
public var triangles : Vector.<uint>;
|
||||
public var color : Color = new Color(1, 1, 1, 1);
|
||||
public var hullLength : int;
|
||||
private var _parentMesh : MeshAttachment;
|
||||
public var inheritDeform : Boolean;
|
||||
public var path : String;
|
||||
public var rendererObject : Object;
|
||||
public var regionU : Number;
|
||||
public var regionV : Number;
|
||||
public var regionU2 : Number;
|
||||
public var regionV2 : Number;
|
||||
public var regionRotate : Boolean;
|
||||
public var regionOffsetX : Number; // Pixels stripped from the bottom left, unrotated.
|
||||
public var regionOffsetY : Number;
|
||||
public var regionWidth : Number; // Unrotated, stripped size.
|
||||
public var regionHeight : Number;
|
||||
public var regionOriginalWidth : Number; // Unrotated, unstripped size.
|
||||
public var regionOriginalHeight : Number;
|
||||
// Nonessential.
|
||||
public var edges : Vector.<int>;
|
||||
public var width : Number;
|
||||
public var height : Number;
|
||||
|
||||
public var path:String;
|
||||
public var rendererObject:Object;
|
||||
public var regionU:Number;
|
||||
public var regionV:Number;
|
||||
public var regionU2:Number;
|
||||
public var regionV2:Number;
|
||||
public var regionRotate:Boolean;
|
||||
public var regionOffsetX:Number; // Pixels stripped from the bottom left, unrotated.
|
||||
public var regionOffsetY:Number;
|
||||
public var regionWidth:Number; // Unrotated, stripped size.
|
||||
public var regionHeight:Number;
|
||||
public var regionOriginalWidth:Number; // Unrotated, unstripped size.
|
||||
public var regionOriginalHeight:Number;
|
||||
public function MeshAttachment(name : String) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
// Nonessential.
|
||||
public var edges:Vector.<int>;
|
||||
public var width:Number;
|
||||
public var height:Number;
|
||||
|
||||
public function MeshAttachment (name:String) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public function updateUVs () : void {
|
||||
var width:Number = regionU2 - regionU, height:Number = regionV2 - regionV;
|
||||
var i:int, n:int = regionUVs.length;
|
||||
if (!uvs || uvs.length != n) uvs = new Vector.<Number>(n, true);
|
||||
if (regionRotate) {
|
||||
for (i = 0; i < n; i += 2) {
|
||||
uvs[i] = regionU + regionUVs[int(i + 1)] * width;
|
||||
uvs[int(i + 1)] = regionV + height - regionUVs[i] * height;
|
||||
public function updateUVs() : void {
|
||||
var width : Number = regionU2 - regionU, height : Number = regionV2 - regionV;
|
||||
var i : int, n : int = regionUVs.length;
|
||||
if (!uvs || uvs.length != n) uvs = new Vector.<Number>(n, true);
|
||||
if (regionRotate) {
|
||||
for (i = 0; i < n; i += 2) {
|
||||
uvs[i] = regionU + regionUVs[int(i + 1)] * width;
|
||||
uvs[int(i + 1)] = regionV + height - regionUVs[i] * height;
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < n; i += 2) {
|
||||
uvs[i] = regionU + regionUVs[i] * width;
|
||||
uvs[int(i + 1)] = regionV + regionUVs[int(i + 1)] * height;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (i = 0; i < n; i += 2) {
|
||||
uvs[i] = regionU + regionUVs[i] * width;
|
||||
uvs[int(i + 1)] = regionV + regionUVs[int(i + 1)] * height;
|
||||
}
|
||||
|
||||
override public function applyDeform(sourceAttachment : VertexAttachment) : Boolean {
|
||||
return this == sourceAttachment || (inheritDeform && _parentMesh == sourceAttachment);
|
||||
}
|
||||
|
||||
public function get parentMesh() : MeshAttachment {
|
||||
return _parentMesh;
|
||||
}
|
||||
|
||||
public function set parentMesh(parentMesh : MeshAttachment) : void {
|
||||
_parentMesh = parentMesh;
|
||||
if (parentMesh != null) {
|
||||
bones = parentMesh.bones;
|
||||
vertices = parentMesh.vertices;
|
||||
worldVerticesLength = parentMesh.worldVerticesLength;
|
||||
regionUVs = parentMesh.regionUVs;
|
||||
triangles = parentMesh.triangles;
|
||||
hullLength = parentMesh.hullLength;
|
||||
edges = parentMesh.edges;
|
||||
width = parentMesh.width;
|
||||
height = parentMesh.height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override public function applyDeform (sourceAttachment:VertexAttachment) : Boolean {
|
||||
return this == sourceAttachment || (inheritDeform && _parentMesh == sourceAttachment);
|
||||
}
|
||||
|
||||
public function get parentMesh () : MeshAttachment {
|
||||
return _parentMesh;
|
||||
}
|
||||
|
||||
public function set parentMesh (parentMesh:MeshAttachment) : void {
|
||||
_parentMesh = parentMesh;
|
||||
if (parentMesh != null) {
|
||||
bones = parentMesh.bones;
|
||||
vertices = parentMesh.vertices;
|
||||
worldVerticesLength = parentMesh.worldVerticesLength;
|
||||
regionUVs = parentMesh.regionUVs;
|
||||
triangles = parentMesh.triangles;
|
||||
hullLength = parentMesh.hullLength;
|
||||
edges = parentMesh.edges;
|
||||
width = parentMesh.width;
|
||||
height = parentMesh.height;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,14 +29,12 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.attachments {
|
||||
public dynamic class PathAttachment extends VertexAttachment {
|
||||
public var lengths : Vector.<Number>;
|
||||
public var closed : Boolean, constantSpeed : Boolean;
|
||||
|
||||
public dynamic class PathAttachment extends VertexAttachment {
|
||||
public var lengths:Vector.<Number>;
|
||||
public var closed:Boolean, constantSpeed:Boolean;
|
||||
|
||||
public function PathAttachment (name:String) {
|
||||
super(name);
|
||||
public function PathAttachment(name : String) {
|
||||
super(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,29 +29,29 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.attachments {
|
||||
import spine.Color;
|
||||
import spine.MathUtils;
|
||||
import spine.Bone;
|
||||
import spine.Color;
|
||||
import spine.MathUtils;
|
||||
import spine.Bone;
|
||||
|
||||
public dynamic class PointAttachment extends VertexAttachment {
|
||||
public var x: Number, y: Number, rotation: Number;
|
||||
public var color:Color = new Color(0.38, 0.94, 0, 1);
|
||||
|
||||
public function PointAttachment (name:String) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public function computeWorldPosition (bone: Bone, point: Vector.<Number>): Vector.<Number> {
|
||||
point[0] = this.x * bone.a + this.y * bone.b + bone.worldX;
|
||||
point[1] = this.x * bone.c + this.y * bone.d + bone.worldY;
|
||||
return point;
|
||||
}
|
||||
public dynamic class PointAttachment extends VertexAttachment {
|
||||
public var x : Number, y : Number, rotation : Number;
|
||||
public var color : Color = new Color(0.38, 0.94, 0, 1);
|
||||
|
||||
public function computeWorldRotation (bone: Bone): Number {
|
||||
var cos:Number = MathUtils.cosDeg(this.rotation), sin: Number = MathUtils.sinDeg(this.rotation);
|
||||
var x:Number = cos * bone.a + sin * bone.b;
|
||||
var y:Number = cos * bone.c + sin * bone.d;
|
||||
return Math.atan2(y, x) * MathUtils.radDeg;
|
||||
}
|
||||
}
|
||||
}
|
||||
public function PointAttachment(name : String) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public function computeWorldPosition(bone : Bone, point : Vector.<Number>) : Vector.<Number> {
|
||||
point[0] = this.x * bone.a + this.y * bone.b + bone.worldX;
|
||||
point[1] = this.x * bone.c + this.y * bone.d + bone.worldY;
|
||||
return point;
|
||||
}
|
||||
|
||||
public function computeWorldRotation(bone : Bone) : Number {
|
||||
var cos : Number = MathUtils.cosDeg(this.rotation), sin : Number = MathUtils.sinDeg(this.rotation);
|
||||
var x : Number = cos * bone.a + sin * bone.b;
|
||||
var y : Number = cos * bone.c + sin * bone.d;
|
||||
return Math.atan2(y, x) * MathUtils.radDeg;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -29,126 +29,122 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.attachments {
|
||||
import spine.Color;
|
||||
import spine.Bone;
|
||||
import spine.Color;
|
||||
import spine.Bone;
|
||||
|
||||
public dynamic class RegionAttachment extends Attachment {
|
||||
public const X1:int = 0;
|
||||
public const Y1:int = 1;
|
||||
public const X2:int = 2;
|
||||
public const Y2:int = 3;
|
||||
public const X3:int = 4;
|
||||
public const Y3:int = 5;
|
||||
public const X4:int = 6;
|
||||
public const Y4:int = 7;
|
||||
public dynamic class RegionAttachment extends Attachment {
|
||||
public const X1 : int = 0;
|
||||
public const Y1 : int = 1;
|
||||
public const X2 : int = 2;
|
||||
public const Y2 : int = 3;
|
||||
public const X3 : int = 4;
|
||||
public const Y3 : int = 5;
|
||||
public const X4 : int = 6;
|
||||
public const Y4 : int = 7;
|
||||
public var x : Number;
|
||||
public var y : Number;
|
||||
public var scaleX : Number = 1;
|
||||
public var scaleY : Number = 1;
|
||||
public var rotation : Number;
|
||||
public var width : Number;
|
||||
public var height : Number;
|
||||
public var color : Color = new Color(1, 1, 1, 1);
|
||||
public var path : String;
|
||||
public var rendererObject : Object;
|
||||
public var regionOffsetX : Number; // Pixels stripped from the bottom left, unrotated.
|
||||
public var regionOffsetY : Number;
|
||||
public var regionWidth : Number; // Unrotated, stripped size.
|
||||
public var regionHeight : Number;
|
||||
public var regionOriginalWidth : Number; // Unrotated, unstripped size.
|
||||
public var regionOriginalHeight : Number;
|
||||
public var offset : Vector.<Number> = new Vector.<Number>();
|
||||
public var uvs : Vector.<Number> = new Vector.<Number>();
|
||||
|
||||
public var x:Number;
|
||||
public var y:Number;
|
||||
public var scaleX:Number = 1;
|
||||
public var scaleY:Number = 1;
|
||||
public var rotation:Number;
|
||||
public var width:Number;
|
||||
public var height:Number;
|
||||
public var color:Color = new Color(1, 1, 1, 1);
|
||||
public function RegionAttachment(name : String) {
|
||||
super(name);
|
||||
offset.length = 8;
|
||||
uvs.length = 8;
|
||||
}
|
||||
|
||||
public var path:String;
|
||||
public var rendererObject:Object;
|
||||
public var regionOffsetX:Number; // Pixels stripped from the bottom left, unrotated.
|
||||
public var regionOffsetY:Number;
|
||||
public var regionWidth:Number; // Unrotated, stripped size.
|
||||
public var regionHeight:Number;
|
||||
public var regionOriginalWidth:Number; // Unrotated, unstripped size.
|
||||
public var regionOriginalHeight:Number;
|
||||
public function updateOffset() : void {
|
||||
var regionScaleX : Number = width / regionOriginalWidth * scaleX;
|
||||
var regionScaleY : Number = height / regionOriginalHeight * scaleY;
|
||||
var localX : Number = -width / 2 * scaleX + regionOffsetX * regionScaleX;
|
||||
var localY : Number = -height / 2 * scaleY + regionOffsetY * regionScaleY;
|
||||
var localX2 : Number = localX + regionWidth * regionScaleX;
|
||||
var localY2 : Number = localY + regionHeight * regionScaleY;
|
||||
var radians : Number = rotation * Math.PI / 180;
|
||||
var cos : Number = Math.cos(radians);
|
||||
var sin : Number = Math.sin(radians);
|
||||
var localXCos : Number = localX * cos + x;
|
||||
var localXSin : Number = localX * sin;
|
||||
var localYCos : Number = localY * cos + y;
|
||||
var localYSin : Number = localY * sin;
|
||||
var localX2Cos : Number = localX2 * cos + x;
|
||||
var localX2Sin : Number = localX2 * sin;
|
||||
var localY2Cos : Number = localY2 * cos + y;
|
||||
var localY2Sin : Number = localY2 * sin;
|
||||
offset[X1] = localXCos - localYSin;
|
||||
offset[Y1] = localYCos + localXSin;
|
||||
offset[X2] = localXCos - localY2Sin;
|
||||
offset[Y2] = localY2Cos + localXSin;
|
||||
offset[X3] = localX2Cos - localY2Sin;
|
||||
offset[Y3] = localY2Cos + localX2Sin;
|
||||
offset[X4] = localX2Cos - localYSin;
|
||||
offset[Y4] = localYCos + localX2Sin;
|
||||
}
|
||||
|
||||
public var offset:Vector.<Number> = new Vector.<Number>();
|
||||
public var uvs:Vector.<Number> = new Vector.<Number>();
|
||||
public function setUVs(u : Number, v : Number, u2 : Number, v2 : Number, rotate : Boolean) : void {
|
||||
var uvs : Vector.<Number> = this.uvs;
|
||||
if (rotate) {
|
||||
uvs[X2] = u;
|
||||
uvs[Y2] = v2;
|
||||
uvs[X3] = u;
|
||||
uvs[Y3] = v;
|
||||
uvs[X4] = u2;
|
||||
uvs[Y4] = v;
|
||||
uvs[X1] = u2;
|
||||
uvs[Y1] = v2;
|
||||
} else {
|
||||
uvs[X1] = u;
|
||||
uvs[Y1] = v2;
|
||||
uvs[X2] = u;
|
||||
uvs[Y2] = v;
|
||||
uvs[X3] = u2;
|
||||
uvs[Y3] = v;
|
||||
uvs[X4] = u2;
|
||||
uvs[Y4] = v2;
|
||||
}
|
||||
}
|
||||
|
||||
public function RegionAttachment (name:String) {
|
||||
super(name);
|
||||
offset.length = 8;
|
||||
uvs.length = 8;
|
||||
}
|
||||
public function computeWorldVertices(bone : Bone, worldVertices : Vector.<Number>, offset : int, stride : int) : void {
|
||||
var vertexOffset : Vector.<Number> = this.offset;
|
||||
var x : Number = bone.worldX, y : Number = bone.worldY;
|
||||
var a : Number = bone.a, b : Number = bone.b, c : Number = bone.c, d : Number = bone.d;
|
||||
var offsetX : Number = 0, offsetY : Number = 0;
|
||||
|
||||
public function updateOffset () : void {
|
||||
var regionScaleX:Number = width / regionOriginalWidth * scaleX;
|
||||
var regionScaleY:Number = height / regionOriginalHeight * scaleY;
|
||||
var localX:Number = -width / 2 * scaleX + regionOffsetX * regionScaleX;
|
||||
var localY:Number = -height / 2 * scaleY + regionOffsetY * regionScaleY;
|
||||
var localX2:Number = localX + regionWidth * regionScaleX;
|
||||
var localY2:Number = localY + regionHeight * regionScaleY;
|
||||
var radians:Number = rotation * Math.PI / 180;
|
||||
var cos:Number = Math.cos(radians);
|
||||
var sin:Number = Math.sin(radians);
|
||||
var localXCos:Number = localX * cos + x;
|
||||
var localXSin:Number = localX * sin;
|
||||
var localYCos:Number = localY * cos + y;
|
||||
var localYSin:Number = localY * sin;
|
||||
var localX2Cos:Number = localX2 * cos + x;
|
||||
var localX2Sin:Number = localX2 * sin;
|
||||
var localY2Cos:Number = localY2 * cos + y;
|
||||
var localY2Sin:Number = localY2 * sin;
|
||||
offset[X1] = localXCos - localYSin;
|
||||
offset[Y1] = localYCos + localXSin;
|
||||
offset[X2] = localXCos - localY2Sin;
|
||||
offset[Y2] = localY2Cos + localXSin;
|
||||
offset[X3] = localX2Cos - localY2Sin;
|
||||
offset[Y3] = localY2Cos + localX2Sin;
|
||||
offset[X4] = localX2Cos - localYSin;
|
||||
offset[Y4] = localYCos + localX2Sin;
|
||||
}
|
||||
|
||||
public function setUVs (u:Number, v:Number, u2:Number, v2:Number, rotate:Boolean) : void {
|
||||
var uvs:Vector.<Number> = this.uvs;
|
||||
if (rotate) {
|
||||
uvs[X2] = u;
|
||||
uvs[Y2] = v2;
|
||||
uvs[X3] = u;
|
||||
uvs[Y3] = v;
|
||||
uvs[X4] = u2;
|
||||
uvs[Y4] = v;
|
||||
uvs[X1] = u2;
|
||||
uvs[Y1] = v2;
|
||||
} else {
|
||||
uvs[X1] = u;
|
||||
uvs[Y1] = v2;
|
||||
uvs[X2] = u;
|
||||
uvs[Y2] = v;
|
||||
uvs[X3] = u2;
|
||||
uvs[Y3] = v;
|
||||
uvs[X4] = u2;
|
||||
uvs[Y4] = v2;
|
||||
offsetX = vertexOffset[X1];
|
||||
offsetY = vertexOffset[Y1];
|
||||
worldVertices[offset] = offsetX * a + offsetY * b + x; // br
|
||||
worldVertices[offset + 1] = offsetX * c + offsetY * d + y;
|
||||
offset += stride;
|
||||
|
||||
offsetX = vertexOffset[X2];
|
||||
offsetY = vertexOffset[Y2];
|
||||
worldVertices[offset] = offsetX * a + offsetY * b + x; // bl
|
||||
worldVertices[offset + 1] = offsetX * c + offsetY * d + y;
|
||||
offset += stride;
|
||||
|
||||
offsetX = vertexOffset[X3];
|
||||
offsetY = vertexOffset[Y3];
|
||||
worldVertices[offset] = offsetX * a + offsetY * b + x; // ul
|
||||
worldVertices[offset + 1] = offsetX * c + offsetY * d + y;
|
||||
offset += stride;
|
||||
|
||||
offsetX = vertexOffset[X4];
|
||||
offsetY = vertexOffset[Y4];
|
||||
worldVertices[offset] = offsetX * a + offsetY * b + x; // ur
|
||||
worldVertices[offset + 1] = offsetX * c + offsetY * d + y;
|
||||
}
|
||||
}
|
||||
|
||||
public function computeWorldVertices (bone:Bone, worldVertices:Vector.<Number>, offset:int, stride:int) : void {
|
||||
var vertexOffset:Vector.<Number> = this.offset;
|
||||
var x:Number = bone.worldX, y:Number = bone.worldY;
|
||||
var a:Number = bone.a, b:Number = bone.b, c:Number = bone.c, d:Number = bone.d;
|
||||
var offsetX:Number = 0, offsetY:Number = 0;
|
||||
|
||||
offsetX = vertexOffset[X1];
|
||||
offsetY = vertexOffset[Y1];
|
||||
worldVertices[offset] = offsetX * a + offsetY * b + x; // br
|
||||
worldVertices[offset + 1] = offsetX * c + offsetY * d + y;
|
||||
offset += stride;
|
||||
|
||||
offsetX = vertexOffset[X2];
|
||||
offsetY = vertexOffset[Y2];
|
||||
worldVertices[offset] = offsetX * a + offsetY * b + x; // bl
|
||||
worldVertices[offset + 1] = offsetX * c + offsetY * d + y;
|
||||
offset += stride;
|
||||
|
||||
offsetX = vertexOffset[X3];
|
||||
offsetY = vertexOffset[Y3];
|
||||
worldVertices[offset] = offsetX * a + offsetY * b + x; // ul
|
||||
worldVertices[offset + 1] = offsetX * c + offsetY * d + y;
|
||||
offset += stride;
|
||||
|
||||
offsetX = vertexOffset[X4];
|
||||
offsetY = vertexOffset[Y4];
|
||||
worldVertices[offset] = offsetX * a + offsetY * b + x; // ur
|
||||
worldVertices[offset + 1] = offsetX * c + offsetY * d + y;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -33,89 +33,99 @@ package spine.attachments {
|
||||
import spine.Skeleton;
|
||||
import spine.Slot;
|
||||
|
||||
public dynamic class VertexAttachment extends Attachment {
|
||||
public var bones:Vector.<int>;
|
||||
public var vertices:Vector.<Number>;
|
||||
public var worldVerticesLength:int;
|
||||
public dynamic class VertexAttachment extends Attachment {
|
||||
public var bones : Vector.<int>;
|
||||
public var vertices : Vector.<Number>;
|
||||
public var worldVerticesLength : int;
|
||||
|
||||
public function VertexAttachment (name:String) {
|
||||
super(name);
|
||||
}
|
||||
public function VertexAttachment(name : String) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
/** Transforms local vertices to world coordinates.
|
||||
* @param start The index of the first local vertex value to transform. Each vertex has 2 values, x and y.
|
||||
* @param count The number of world vertex values to output. Must be <= {@link #getWorldVerticesLength()} - start.
|
||||
* @param worldVertices The output world vertices. Must have a length >= offset + count.
|
||||
* @param offset The worldVertices index to begin writing values. */
|
||||
public function computeWorldVertices (slot:Slot, start:int, count:int, worldVertices:Vector.<Number>, offset:int, stride:int): void {
|
||||
count = offset + (count >> 1) * stride;
|
||||
var skeleton:Skeleton = slot.skeleton;
|
||||
var deformArray:Vector.<Number> = slot.attachmentVertices;
|
||||
var vertices:Vector.<Number> = this.vertices;
|
||||
var bones:Vector.<int> = this.bones;
|
||||
var deform:Vector.<Number>;
|
||||
|
||||
var v:int, w:int, n:int, i:int, skip:int, b:int, f:int;
|
||||
var vx:Number, vy:Number;
|
||||
var wx:Number, wy:Number;
|
||||
var bone:Bone;
|
||||
|
||||
if (bones == null) {
|
||||
if (deformArray.length > 0) vertices = deformArray;
|
||||
bone = slot.bone;
|
||||
var x:Number = bone.worldX;
|
||||
var y:Number = bone.worldY;
|
||||
var a:Number = bone.a, bb:Number = bone.b, c:Number = bone.c, d:Number = bone.d;
|
||||
for (v = start, w = offset; w < count; v += 2, w += stride) {
|
||||
vx = vertices[v], vy = vertices[v + 1];
|
||||
worldVertices[w] = vx * a + vy * bb + x;
|
||||
worldVertices[w + 1] = vx * c + vy * d + y;
|
||||
}
|
||||
return;
|
||||
}
|
||||
v = 0, skip = 0;
|
||||
for (i = 0; i < start; i += 2) {
|
||||
n = bones[v];
|
||||
v += n + 1;
|
||||
skip += n;
|
||||
}
|
||||
var skeletonBones:Vector.<Bone> = skeleton.bones;
|
||||
if (deformArray.length == 0) {
|
||||
for (w = offset, b = skip * 3; w < count; w += stride) {
|
||||
wx = 0, wy = 0;
|
||||
n = bones[v++];
|
||||
n += v;
|
||||
for (; v < n; v++, b += 3) {
|
||||
bone = skeletonBones[bones[v]];
|
||||
vx = vertices[b]; vy = vertices[b + 1]; var weight:Number = vertices[b + 2];
|
||||
wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight;
|
||||
wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight;
|
||||
/** Transforms local vertices to world coordinates.
|
||||
* @param start The index of the first local vertex value to transform. Each vertex has 2 values, x and y.
|
||||
* @param count The number of world vertex values to output. Must be <= {@link #getWorldVerticesLength()} - start.
|
||||
* @param worldVertices The output world vertices. Must have a length >= offset + count.
|
||||
* @param offset The worldVertices index to begin writing values. */
|
||||
public function computeWorldVertices(slot : Slot, start : int, count : int, worldVertices : Vector.<Number>, offset : int, stride : int) : void {
|
||||
count = offset + (count >> 1) * stride;
|
||||
var skeleton : Skeleton = slot.skeleton;
|
||||
var deformArray : Vector.<Number> = slot.attachmentVertices;
|
||||
var vertices : Vector.<Number> = this.vertices;
|
||||
var bones : Vector.<int> = this.bones;
|
||||
var deform : Vector.<Number>;
|
||||
|
||||
var v : int, w : int, n : int, i : int, skip : int, b : int, f : int;
|
||||
var vx : Number, vy : Number;
|
||||
var wx : Number, wy : Number;
|
||||
var bone : Bone;
|
||||
|
||||
if (bones == null) {
|
||||
if (deformArray.length > 0) vertices = deformArray;
|
||||
bone = slot.bone;
|
||||
var x : Number = bone.worldX;
|
||||
var y : Number = bone.worldY;
|
||||
var a : Number = bone.a, bb : Number = bone.b, c : Number = bone.c, d : Number = bone.d;
|
||||
for (v = start, w = offset; w < count; v += 2, w += stride) {
|
||||
vx = vertices[v]
|
||||
,
|
||||
vy = vertices[v + 1];
|
||||
worldVertices[w] = vx * a + vy * bb + x;
|
||||
worldVertices[w + 1] = vx * c + vy * d + y;
|
||||
}
|
||||
worldVertices[w] = wx;
|
||||
worldVertices[w + 1] = wy;
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
deform = deformArray;
|
||||
for (w = offset, b = skip * 3, f = skip << 1; w < count; w += stride) {
|
||||
wx = 0; wy = 0;
|
||||
n = bones[v++];
|
||||
n += v;
|
||||
for (; v < n; v++, b += 3, f += 2) {
|
||||
bone = skeletonBones[bones[v]];
|
||||
vx = vertices[b] + deform[f]; vy = vertices[b + 1] + deform[f + 1]; weight = vertices[b + 2];
|
||||
wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight;
|
||||
wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight;
|
||||
v = 0
|
||||
,
|
||||
skip = 0;
|
||||
for (i = 0; i < start; i += 2) {
|
||||
n = bones[v];
|
||||
v += n + 1;
|
||||
skip += n;
|
||||
}
|
||||
var skeletonBones : Vector.<Bone> = skeleton.bones;
|
||||
if (deformArray.length == 0) {
|
||||
for (w = offset, b = skip * 3; w < count; w += stride) {
|
||||
wx = 0
|
||||
,
|
||||
wy = 0;
|
||||
n = bones[v++];
|
||||
n += v;
|
||||
for (; v < n; v++, b += 3) {
|
||||
bone = skeletonBones[bones[v]];
|
||||
vx = vertices[b];
|
||||
vy = vertices[b + 1];
|
||||
var weight : Number = vertices[b + 2];
|
||||
wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight;
|
||||
wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight;
|
||||
}
|
||||
worldVertices[w] = wx;
|
||||
worldVertices[w + 1] = wy;
|
||||
}
|
||||
} else {
|
||||
deform = deformArray;
|
||||
for (w = offset, b = skip * 3, f = skip << 1; w < count; w += stride) {
|
||||
wx = 0;
|
||||
wy = 0;
|
||||
n = bones[v++];
|
||||
n += v;
|
||||
for (; v < n; v++, b += 3, f += 2) {
|
||||
bone = skeletonBones[bones[v]];
|
||||
vx = vertices[b] + deform[f];
|
||||
vy = vertices[b + 1] + deform[f + 1];
|
||||
weight = vertices[b + 2];
|
||||
wx += (vx * bone.a + vy * bone.b + bone.worldX) * weight;
|
||||
wy += (vx * bone.c + vy * bone.d + bone.worldY) * weight;
|
||||
}
|
||||
worldVertices[w] = wx;
|
||||
worldVertices[w + 1] = wy;
|
||||
}
|
||||
worldVertices[w] = wx;
|
||||
worldVertices[w + 1] = wy;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns true if a deform originally applied to the specified attachment should be applied to this attachment. */
|
||||
public function applyDeform (sourceAttachment:VertexAttachment): Boolean {
|
||||
return this == sourceAttachment;
|
||||
/** Returns true if a deform originally applied to the specified attachment should be applied to this attachment. */
|
||||
public function applyDeform(sourceAttachment : VertexAttachment) : Boolean {
|
||||
return this == sourceAttachment;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,57 +29,56 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.flash {
|
||||
import flash.display.Bitmap;
|
||||
import flash.display.BitmapData;
|
||||
import flash.display.Bitmap;
|
||||
import flash.display.BitmapData;
|
||||
|
||||
import spine.atlas.AtlasPage;
|
||||
import spine.atlas.AtlasRegion;
|
||||
import spine.atlas.TextureLoader;
|
||||
import spine.atlas.AtlasPage;
|
||||
import spine.atlas.AtlasRegion;
|
||||
import spine.atlas.TextureLoader;
|
||||
|
||||
public class FlashTextureLoader implements TextureLoader {
|
||||
public var bitmapDatas:Object = {};
|
||||
public var singleBitmapData:BitmapData;
|
||||
public class FlashTextureLoader implements TextureLoader {
|
||||
public var bitmapDatas : Object = {};
|
||||
public var singleBitmapData : BitmapData;
|
||||
|
||||
/** @param bitmaps A Bitmap or BitmapData for an atlas that has only one page, or for a multi page atlas an object where the
|
||||
* key is the image path and the value is the Bitmap or BitmapData. */
|
||||
public function FlashTextureLoader (bitmaps:Object) {
|
||||
if (bitmaps is BitmapData) {
|
||||
singleBitmapData = BitmapData(bitmaps);
|
||||
return;
|
||||
}
|
||||
if (bitmaps is Bitmap) {
|
||||
singleBitmapData = Bitmap(bitmaps).bitmapData;
|
||||
return;
|
||||
/** @param bitmaps A Bitmap or BitmapData for an atlas that has only one page, or for a multi page atlas an object where the
|
||||
* key is the image path and the value is the Bitmap or BitmapData. */
|
||||
public function FlashTextureLoader(bitmaps : Object) {
|
||||
if (bitmaps is BitmapData) {
|
||||
singleBitmapData = BitmapData(bitmaps);
|
||||
return;
|
||||
}
|
||||
if (bitmaps is Bitmap) {
|
||||
singleBitmapData = Bitmap(bitmaps).bitmapData;
|
||||
return;
|
||||
}
|
||||
|
||||
for (var path : * in bitmaps) {
|
||||
var object : * = bitmaps[path];
|
||||
var bitmapData : BitmapData;
|
||||
if (object is BitmapData)
|
||||
bitmapData = BitmapData(object);
|
||||
else if (object is Bitmap)
|
||||
bitmapData = Bitmap(object).bitmapData;
|
||||
else
|
||||
throw new ArgumentError("Object for path \"" + path + "\" must be a Bitmap or BitmapData: " + object);
|
||||
bitmapDatas[path] = bitmapData;
|
||||
}
|
||||
}
|
||||
|
||||
for (var path:* in bitmaps) {
|
||||
var object:* = bitmaps[path];
|
||||
var bitmapData:BitmapData;
|
||||
if (object is BitmapData)
|
||||
bitmapData = BitmapData(object);
|
||||
else if (object is Bitmap)
|
||||
bitmapData = Bitmap(object).bitmapData;
|
||||
else
|
||||
throw new ArgumentError("Object for path \"" + path + "\" must be a Bitmap or BitmapData: " + object);
|
||||
bitmapDatas[path] = bitmapData;
|
||||
public function loadPage(page : AtlasPage, path : String) : void {
|
||||
var bitmapData : BitmapData = singleBitmapData || bitmapDatas[path];
|
||||
if (!bitmapData)
|
||||
throw new ArgumentError("BitmapData not found with name: " + path);
|
||||
page.rendererObject = bitmapData;
|
||||
page.width = bitmapData.width;
|
||||
page.height = bitmapData.height;
|
||||
}
|
||||
|
||||
public function loadRegion(region : AtlasRegion) : void {
|
||||
}
|
||||
|
||||
public function unloadPage(page : AtlasPage) : void {
|
||||
BitmapData(page.rendererObject).dispose();
|
||||
}
|
||||
}
|
||||
|
||||
public function loadPage (page:AtlasPage, path:String) : void {
|
||||
var bitmapData:BitmapData = singleBitmapData || bitmapDatas[path];
|
||||
if (!bitmapData)
|
||||
throw new ArgumentError("BitmapData not found with name: " + path);
|
||||
page.rendererObject = bitmapData;
|
||||
page.width = bitmapData.width;
|
||||
page.height = bitmapData.height;
|
||||
}
|
||||
|
||||
public function loadRegion (region:AtlasRegion) : void {
|
||||
}
|
||||
|
||||
public function unloadPage (page:AtlasPage) : void {
|
||||
BitmapData(page.rendererObject).dispose();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,24 +29,30 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.flash {
|
||||
import spine.SkeletonData;
|
||||
import spine.animation.AnimationState;
|
||||
import spine.animation.AnimationStateData;
|
||||
import flash.events.Event;
|
||||
import spine.SkeletonData;
|
||||
import spine.animation.AnimationState;
|
||||
import spine.animation.AnimationStateData;
|
||||
|
||||
public class SkeletonAnimation extends SkeletonSprite {
|
||||
public var state:AnimationState;
|
||||
public class SkeletonAnimation extends SkeletonSprite {
|
||||
public var state : AnimationState;
|
||||
|
||||
public function SkeletonAnimation (skeletonData:SkeletonData, stateData:AnimationStateData = null) {
|
||||
super(skeletonData);
|
||||
state = new AnimationState(stateData ? stateData : new AnimationStateData(skeletonData));
|
||||
public function SkeletonAnimation(skeletonData : SkeletonData, stateData : AnimationStateData = null) {
|
||||
super(skeletonData);
|
||||
state = new AnimationState(stateData ? stateData : new AnimationStateData(skeletonData));
|
||||
}
|
||||
|
||||
override protected function onRemove(e:Event):void{
|
||||
state.clearListeners();
|
||||
state.clearListenerNotifications();
|
||||
super.onRemove(e);
|
||||
}
|
||||
|
||||
override public function advanceTime(time : Number) : void {
|
||||
state.update(time * timeScale);
|
||||
state.apply(skeleton);
|
||||
skeleton.updateWorldTransform();
|
||||
super.advanceTime(time);
|
||||
}
|
||||
}
|
||||
|
||||
override public function advanceTime (time:Number) : void {
|
||||
state.update(time * timeScale);
|
||||
state.apply(skeleton);
|
||||
skeleton.updateWorldTransform();
|
||||
super.advanceTime(time);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -29,124 +29,137 @@
|
||||
*****************************************************************************/
|
||||
|
||||
package spine.flash {
|
||||
import flash.utils.Dictionary;
|
||||
import flash.display.Bitmap;
|
||||
import flash.display.BitmapData;
|
||||
import flash.display.BlendMode;
|
||||
import flash.display.Sprite;
|
||||
import flash.events.Event;
|
||||
import flash.geom.ColorTransform;
|
||||
import flash.geom.Point;
|
||||
import flash.geom.Rectangle;
|
||||
import flash.utils.getTimer;
|
||||
import flash.utils.Dictionary;
|
||||
import flash.display.Bitmap;
|
||||
import flash.display.BitmapData;
|
||||
import flash.display.BlendMode;
|
||||
import flash.display.Sprite;
|
||||
import flash.events.Event;
|
||||
import flash.geom.ColorTransform;
|
||||
import flash.geom.Point;
|
||||
import flash.geom.Rectangle;
|
||||
import flash.utils.getTimer;
|
||||
|
||||
import spine.Bone;
|
||||
import spine.Skeleton;
|
||||
import spine.SkeletonData;
|
||||
import spine.Slot;
|
||||
import spine.atlas.AtlasRegion;
|
||||
import spine.attachments.RegionAttachment;
|
||||
import spine.Bone;
|
||||
import spine.Skeleton;
|
||||
import spine.SkeletonData;
|
||||
import spine.Slot;
|
||||
import spine.atlas.AtlasRegion;
|
||||
import spine.attachments.RegionAttachment;
|
||||
|
||||
public class SkeletonSprite extends Sprite {
|
||||
static private var blendModes:Vector.<String> = new <String>[
|
||||
BlendMode.NORMAL, BlendMode.ADD, BlendMode.MULTIPLY, BlendMode.SCREEN];
|
||||
public class SkeletonSprite extends Sprite {
|
||||
static private var blendModes : Vector.<String> = new <String>[BlendMode.NORMAL, BlendMode.ADD, BlendMode.MULTIPLY, BlendMode.SCREEN];
|
||||
private var _skeleton : Skeleton;
|
||||
public var timeScale : Number = 1;
|
||||
private var lastTime : int;
|
||||
private var wrappers : Dictionary = new Dictionary(true);
|
||||
|
||||
private var _skeleton:Skeleton;
|
||||
public var timeScale:Number = 1;
|
||||
private var lastTime:int;
|
||||
private var wrappers:Dictionary = new Dictionary(true);
|
||||
public function SkeletonSprite(skeletonData : SkeletonData) {
|
||||
Bone.yDown = true;
|
||||
|
||||
public function SkeletonSprite (skeletonData:SkeletonData) {
|
||||
Bone.yDown = true;
|
||||
_skeleton = new Skeleton(skeletonData);
|
||||
_skeleton.updateWorldTransform();
|
||||
|
||||
_skeleton = new Skeleton(skeletonData);
|
||||
_skeleton.updateWorldTransform();
|
||||
lastTime = getTimer();
|
||||
addEventListener(Event.ADDED_TO_STAGE, onAdd);
|
||||
addEventListener(Event.REMOVED_FROM_STAGE, onRemove);
|
||||
}
|
||||
protected function onRemove(e:Event) : void {
|
||||
removeEventListener(Event.ENTER_FRAME, enterFrame);
|
||||
}
|
||||
|
||||
public function clearListeners() : void {
|
||||
removeEventListener(Event.ADDED_TO_STAGE, onAdd);
|
||||
removeEventListener(Event.REMOVED_FROM_STAGE, onRemove);
|
||||
}
|
||||
|
||||
addEventListener(Event.ENTER_FRAME, enterFrame);
|
||||
}
|
||||
protected function onAdd(event:Event) : void {
|
||||
lastTime = getTimer();
|
||||
enterFrame(null);
|
||||
addEventListener(Event.ENTER_FRAME, enterFrame);
|
||||
}
|
||||
|
||||
private function enterFrame (event:Event) : void {
|
||||
var time:int = getTimer();
|
||||
advanceTime((time - lastTime) / 1000);
|
||||
lastTime = time;
|
||||
}
|
||||
private function enterFrame(event : Event) : void {
|
||||
var time : int = getTimer();
|
||||
advanceTime((time - lastTime) / 1000);
|
||||
lastTime = time;
|
||||
}
|
||||
|
||||
public function advanceTime (delta:Number) : void {
|
||||
_skeleton.update(delta * timeScale);
|
||||
public function advanceTime(delta : Number) : void {
|
||||
_skeleton.update(delta * timeScale);
|
||||
|
||||
removeChildren();
|
||||
var drawOrder:Vector.<Slot> = skeleton.drawOrder;
|
||||
for (var i:int = 0, n:int = drawOrder.length; i < n; i++) {
|
||||
var slot:Slot = drawOrder[i];
|
||||
var regionAttachment:RegionAttachment = slot.attachment as RegionAttachment;
|
||||
if (!regionAttachment) continue;
|
||||
removeChildren();
|
||||
var drawOrder : Vector.<Slot> = skeleton.drawOrder;
|
||||
for (var i : int = 0, n : int = drawOrder.length; i < n; i++) {
|
||||
var slot : Slot = drawOrder[i];
|
||||
var regionAttachment : RegionAttachment = slot.attachment as RegionAttachment;
|
||||
if (!regionAttachment) continue;
|
||||
|
||||
var wrapper:Sprite = wrappers[regionAttachment];
|
||||
if (!wrapper) {
|
||||
var region:AtlasRegion = AtlasRegion(regionAttachment.rendererObject);
|
||||
var regionHeight:Number = region.rotate ? region.width : region.height;
|
||||
var regionData:BitmapData = region.rendererObject as BitmapData;
|
||||
if (!regionData) {
|
||||
var bitmapData:BitmapData = region.page.rendererObject as BitmapData;
|
||||
var regionWidth:Number = region.rotate ? region.height : region.width;
|
||||
regionData = new BitmapData(regionWidth, regionHeight);
|
||||
regionData.copyPixels(bitmapData, new Rectangle(region.x, region.y, regionWidth, regionHeight), new Point());
|
||||
region.rendererObject = regionData;
|
||||
var wrapper : Sprite = wrappers[regionAttachment];
|
||||
if (!wrapper) {
|
||||
var region : AtlasRegion = AtlasRegion(regionAttachment.rendererObject);
|
||||
var regionHeight : Number = region.rotate ? region.width : region.height;
|
||||
var regionData : BitmapData = region.rendererObject as BitmapData;
|
||||
if (!regionData) {
|
||||
var bitmapData : BitmapData = region.page.rendererObject as BitmapData;
|
||||
var regionWidth : Number = region.rotate ? region.height : region.width;
|
||||
regionData = new BitmapData(regionWidth, regionHeight);
|
||||
regionData.copyPixels(bitmapData, new Rectangle(region.x, region.y, regionWidth, regionHeight), new Point());
|
||||
region.rendererObject = regionData;
|
||||
}
|
||||
|
||||
var bitmap : Bitmap = new Bitmap(regionData);
|
||||
bitmap.smoothing = true;
|
||||
|
||||
// Rotate and scale using default registration point (top left corner, y-down, CW) instead of image center.
|
||||
bitmap.rotation = -regionAttachment.rotation;
|
||||
bitmap.scaleX = regionAttachment.scaleX * (regionAttachment.width / region.width);
|
||||
bitmap.scaleY = regionAttachment.scaleY * (regionAttachment.height / region.height);
|
||||
|
||||
// Position using attachment translation, shifted as if scale and rotation were at image center.
|
||||
var radians : Number = -regionAttachment.rotation * Math.PI / 180;
|
||||
var cos : Number = Math.cos(radians);
|
||||
var sin : Number = Math.sin(radians);
|
||||
var shiftX : Number = -regionAttachment.width / 2 * regionAttachment.scaleX;
|
||||
var shiftY : Number = -regionAttachment.height / 2 * regionAttachment.scaleY;
|
||||
if (region.rotate) {
|
||||
bitmap.rotation += 90;
|
||||
shiftX += regionHeight * (regionAttachment.width / region.width);
|
||||
}
|
||||
bitmap.x = regionAttachment.x + shiftX * cos - shiftY * sin;
|
||||
bitmap.y = -regionAttachment.y + shiftX * sin + shiftY * cos;
|
||||
|
||||
// Use bone as registration point.
|
||||
wrapper = new Sprite();
|
||||
wrapper.transform.colorTransform = new ColorTransform();
|
||||
wrapper.addChild(bitmap);
|
||||
wrappers[regionAttachment] = wrapper;
|
||||
}
|
||||
|
||||
var bitmap:Bitmap = new Bitmap(regionData);
|
||||
bitmap.smoothing = true;
|
||||
wrapper.blendMode = blendModes[slot.data.blendMode.ordinal];
|
||||
|
||||
// Rotate and scale using default registration point (top left corner, y-down, CW) instead of image center.
|
||||
bitmap.rotation = -regionAttachment.rotation;
|
||||
bitmap.scaleX = regionAttachment.scaleX * (regionAttachment.width / region.width);
|
||||
bitmap.scaleY = regionAttachment.scaleY * (regionAttachment.height / region.height);
|
||||
var colorTransform : ColorTransform = wrapper.transform.colorTransform;
|
||||
colorTransform.redMultiplier = skeleton.color.r * slot.color.r * regionAttachment.color.r;
|
||||
colorTransform.greenMultiplier = skeleton.color.g * slot.color.g * regionAttachment.color.g;
|
||||
colorTransform.blueMultiplier = skeleton.color.b * slot.color.b * regionAttachment.color.b;
|
||||
colorTransform.alphaMultiplier = skeleton.color.a * slot.color.a * regionAttachment.color.a;
|
||||
wrapper.transform.colorTransform = colorTransform;
|
||||
|
||||
// Position using attachment translation, shifted as if scale and rotation were at image center.
|
||||
var radians:Number = -regionAttachment.rotation * Math.PI / 180;
|
||||
var cos:Number = Math.cos(radians);
|
||||
var sin:Number = Math.sin(radians);
|
||||
var shiftX:Number = -regionAttachment.width / 2 * regionAttachment.scaleX;
|
||||
var shiftY:Number = -regionAttachment.height / 2 * regionAttachment.scaleY;
|
||||
if (region.rotate) {
|
||||
bitmap.rotation += 90;
|
||||
shiftX += regionHeight * (regionAttachment.width / region.width);
|
||||
}
|
||||
bitmap.x = regionAttachment.x + shiftX * cos - shiftY * sin;
|
||||
bitmap.y = -regionAttachment.y + shiftX * sin + shiftY * cos;
|
||||
var bone : Bone = slot.bone;
|
||||
var flipX : int = skeleton.flipX ? -1 : 1;
|
||||
var flipY : int = skeleton.flipY ? -1 : 1;
|
||||
|
||||
// Use bone as registration point.
|
||||
wrapper = new Sprite();
|
||||
wrapper.transform.colorTransform = new ColorTransform();
|
||||
wrapper.addChild(bitmap);
|
||||
wrappers[regionAttachment] = wrapper;
|
||||
wrapper.x = bone.worldX;
|
||||
wrapper.y = bone.worldY;
|
||||
wrapper.rotation = bone.worldRotationX * flipX * flipY;
|
||||
wrapper.scaleX = bone.worldScaleX * flipX;
|
||||
wrapper.scaleY = bone.worldScaleY * flipY;
|
||||
addChild(wrapper);
|
||||
}
|
||||
}
|
||||
|
||||
wrapper.blendMode = blendModes[slot.data.blendMode.ordinal];
|
||||
|
||||
var colorTransform:ColorTransform = wrapper.transform.colorTransform;
|
||||
colorTransform.redMultiplier = skeleton.color.r * slot.color.r * regionAttachment.color.r;
|
||||
colorTransform.greenMultiplier = skeleton.color.g * slot.color.g * regionAttachment.color.g;
|
||||
colorTransform.blueMultiplier = skeleton.color.b * slot.color.b * regionAttachment.color.b;
|
||||
colorTransform.alphaMultiplier = skeleton.color.a * slot.color.a * regionAttachment.color.a;
|
||||
wrapper.transform.colorTransform = colorTransform;
|
||||
|
||||
var bone:Bone = slot.bone;
|
||||
var flipX:int = skeleton.flipX ? -1 : 1;
|
||||
var flipY:int = skeleton.flipY ? -1 : 1;
|
||||
|
||||
wrapper.x = bone.worldX;
|
||||
wrapper.y = bone.worldY;
|
||||
wrapper.rotation = bone.worldRotationX * flipX * flipY;
|
||||
wrapper.scaleX = bone.worldScaleX * flipX;
|
||||
wrapper.scaleY = bone.worldScaleY * flipY;
|
||||
addChild(wrapper);
|
||||
public function get skeleton() : Skeleton {
|
||||
return _skeleton;
|
||||
}
|
||||
}
|
||||
|
||||
public function get skeleton () : Skeleton {
|
||||
return _skeleton;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@ -64,6 +64,7 @@
|
||||
/* All allocation uses these. */
|
||||
#define MALLOC(TYPE,COUNT) ((TYPE*)_malloc(sizeof(TYPE) * (COUNT), __FILE__, __LINE__))
|
||||
#define CALLOC(TYPE,COUNT) ((TYPE*)_calloc(COUNT, sizeof(TYPE), __FILE__, __LINE__))
|
||||
#define REALLOC(PTR,TYPE,COUNT) ((TYPE*)_realloc(PTR, sizeof(TYPE) * (COUNT)))
|
||||
#define NEW(TYPE) CALLOC(TYPE,1)
|
||||
|
||||
/* Gets the direct super class. Type safe. */
|
||||
@ -162,6 +163,7 @@ char* _spUtil_readFile (const char* path, int* length);
|
||||
|
||||
void* _malloc (size_t size, const char* file, int line);
|
||||
void* _calloc (size_t num, size_t size, const char* file, int line);
|
||||
void* _realloc(void* ptr, size_t size);
|
||||
void _free (void* ptr);
|
||||
|
||||
void _setMalloc (void* (*_malloc) (size_t size));
|
||||
|
||||
@ -198,12 +198,17 @@ static void _addAfterPosition (float p, float* temp, int i, float* out, int o) {
|
||||
out[o + 2] = r;
|
||||
}
|
||||
|
||||
static int _isNan(float value) {
|
||||
float _nan = (float)0.0/(float)0.0;
|
||||
return 0 == memcmp((void*)&value, (void*)&_nan, sizeof(value));
|
||||
}
|
||||
|
||||
static void _addCurvePosition (float p, float x1, float y1, float cx1, float cy1, float cx2, float cy2, float x2, float y2,
|
||||
float* out, int o, int/*bool*/tangents) {
|
||||
float tt, ttt, u, uu, uuu;
|
||||
float ut, ut3, uut3, utt3;
|
||||
float x, y;
|
||||
if (p == 0) p = 0.0001f;
|
||||
if (p == 0 || _isNan(p)) p = 0.0001f;
|
||||
tt = p * p, ttt = tt * p, u = 1 - p, uu = u * u, uuu = uu * u;
|
||||
ut = u * p, ut3 = ut * 3, uut3 = u * ut3, utt3 = ut3 * p;
|
||||
x = x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y = y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt;
|
||||
|
||||
@ -187,6 +187,7 @@ static void readColor (_dataInput* input, float *r, float *g, float *b, float *a
|
||||
|
||||
#define SLOT_ATTACHMENT 0
|
||||
#define SLOT_COLOR 1
|
||||
#define SLOT_TWO_COLOR 2
|
||||
|
||||
#define PATH_POSITION 0
|
||||
#define PATH_SPACING 1
|
||||
@ -261,6 +262,20 @@ static spAnimation* _spSkeletonBinary_readAnimation (spSkeletonBinary* self, con
|
||||
unsigned char timelineType = readByte(input);
|
||||
int frameCount = readVarint(input, 1);
|
||||
switch (timelineType) {
|
||||
case SLOT_ATTACHMENT: {
|
||||
spAttachmentTimeline* timeline = spAttachmentTimeline_create(frameCount);
|
||||
timeline->slotIndex = slotIndex;
|
||||
for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) {
|
||||
float time = readFloat(input);
|
||||
const char* attachmentName = readString(input);
|
||||
/* TODO Avoid copying of attachmentName inside */
|
||||
spAttachmentTimeline_setFrame(timeline, frameIndex, time, attachmentName);
|
||||
FREE(attachmentName);
|
||||
}
|
||||
kv_push(spTimeline*, timelines, SUPER(timeline));
|
||||
duration = MAX(duration, timeline->frames[frameCount - 1]);
|
||||
break;
|
||||
}
|
||||
case SLOT_COLOR: {
|
||||
spColorTimeline* timeline = spColorTimeline_create(frameCount);
|
||||
timeline->slotIndex = slotIndex;
|
||||
@ -275,18 +290,20 @@ static spAnimation* _spSkeletonBinary_readAnimation (spSkeletonBinary* self, con
|
||||
duration = MAX(duration, timeline->frames[(frameCount - 1) * COLOR_ENTRIES]);
|
||||
break;
|
||||
}
|
||||
case SLOT_ATTACHMENT: {
|
||||
spAttachmentTimeline* timeline = spAttachmentTimeline_create(frameCount);
|
||||
case SLOT_TWO_COLOR: {
|
||||
spTwoColorTimeline* timeline = spTwoColorTimeline_create(frameCount);
|
||||
timeline->slotIndex = slotIndex;
|
||||
for (frameIndex = 0; frameIndex < frameCount; ++frameIndex) {
|
||||
float time = readFloat(input);
|
||||
const char* attachmentName = readString(input);
|
||||
/* TODO Avoid copying of attachmentName inside */
|
||||
spAttachmentTimeline_setFrame(timeline, frameIndex, time, attachmentName);
|
||||
FREE(attachmentName);
|
||||
float r, g, b, a;
|
||||
float r2, g2, b2, a2;
|
||||
readColor(input, &r, &g, &b, &a);
|
||||
readColor(input, &a2, &r2, &g2, &b2);
|
||||
spTwoColorTimeline_setFrame(timeline, frameIndex, time, r, g, b, a, r2, g2, b2);
|
||||
if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex);
|
||||
}
|
||||
kv_push(spTimeline*, timelines, SUPER(timeline));
|
||||
duration = MAX(duration, timeline->frames[frameCount - 1]);
|
||||
kv_push(spTimeline*, timelines, SUPER(SUPER(timeline)));
|
||||
duration = MAX(duration, timeline->frames[(frameCount - 1) * TWOCOLOR_ENTRIES]);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
|
||||
@ -93,7 +93,7 @@ static float toColor (const char* value, int index) {
|
||||
char *error;
|
||||
int color;
|
||||
|
||||
if (strlen(value) != 8) return -1;
|
||||
if (strlen(value) / 2 < index) return -1;
|
||||
value += index * 2;
|
||||
|
||||
digits[0] = *value;
|
||||
@ -217,8 +217,8 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r
|
||||
timeline->slotIndex = slotIndex;
|
||||
|
||||
for (valueMap = timelineMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) {
|
||||
const char* s = Json_getString(valueMap, "color", 0);
|
||||
const char* ds = Json_getString(valueMap, "color", 0);
|
||||
const char* s = Json_getString(valueMap, "light", 0);
|
||||
const char* ds = Json_getString(valueMap, "dark", 0);
|
||||
spTwoColorTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), toColor(s, 0), toColor(s, 1), toColor(s, 2),
|
||||
toColor(s, 3), toColor(ds, 0), toColor(ds, 1), toColor(ds, 2));
|
||||
readCurve(valueMap, SUPER(timeline), frameIndex);
|
||||
|
||||
@ -46,6 +46,9 @@ void* _calloc (size_t num, size_t size, const char* file, int line) {
|
||||
if (ptr) memset(ptr, 0, num * size);
|
||||
return ptr;
|
||||
}
|
||||
void* _realloc(void* ptr, size_t size) {
|
||||
return realloc(ptr, size);
|
||||
}
|
||||
void _free (void* ptr) {
|
||||
freeFunc(ptr);
|
||||
}
|
||||
|
||||
@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
||||
|
||||
## Spine version
|
||||
|
||||
spine-cocos2d-objc works with data exported from Spine 3.5.xx.
|
||||
spine-cocos2d-objc works with data exported from Spine 3.6.x.
|
||||
|
||||
spine-cocos2d-objc supports all Spine features.
|
||||
|
||||
@ -29,6 +29,9 @@ See the [Spine Runtimes documentation](http://esotericsoftware.com/spine-documen
|
||||
|
||||
The Spine cocos2d-objc example works on iOS simulators and devices.
|
||||
|
||||
## Notes
|
||||
* To enable two color tinting, set `SkeletonRenderer.twoColorTint = true`. Note that skeletons rendered with this feature will not batch with other skeletons.
|
||||
|
||||
### iOS
|
||||
1. Install [Xcode](https://developer.apple.com/xcode/)
|
||||
2. Install [Homebrew](http://brew.sh/)
|
||||
|
||||
@ -43,7 +43,7 @@
|
||||
self = [super init];
|
||||
if (!self) return nil;
|
||||
|
||||
skeletonNode = [SkeletonAnimation skeletonWithFile:@"goblins-mesh.json" atlasFile:@"goblins-mesh.atlas" scale:1];
|
||||
skeletonNode = [SkeletonAnimation skeletonWithFile:@"goblins-mesh.json" atlasFile:@"goblins.atlas" scale:1];
|
||||
[skeletonNode setSkin:@"goblin"];
|
||||
[skeletonNode setAnimationForTrack:0 name:@"walk" loop:YES];
|
||||
|
||||
|
||||
@ -36,6 +36,7 @@
|
||||
+ (CCScene*) scene {
|
||||
CCScene *scene = [CCScene node];
|
||||
[scene addChild:[SpineboyExample node]];
|
||||
[scene setColorRGBA: [CCColor colorWithRed:1 green:0 blue:0]];
|
||||
return scene;
|
||||
}
|
||||
|
||||
@ -43,11 +44,12 @@
|
||||
self = [super init];
|
||||
if (!self) return nil;
|
||||
|
||||
skeletonNode = [SkeletonAnimation skeletonWithFile:@"spineboy.json" atlasFile:@"spineboy.atlas" scale:0.6];
|
||||
skeletonNode = [SkeletonAnimation skeletonWithFile:@"TwoColorTest.json" atlasFile:@"TwoColorTest.atlas" scale:0.2];
|
||||
[skeletonNode setMixFrom:@"walk" to:@"jump" duration:0.2f];
|
||||
[skeletonNode setMixFrom:@"jump" to:@"run" duration:0.2f];
|
||||
|
||||
__weak SkeletonAnimation* node = skeletonNode;
|
||||
skeletonNode.twoColorTint = true;
|
||||
skeletonNode.startListener = ^(spTrackEntry* entry) {
|
||||
const char* animationName = entry->animation->name;
|
||||
NSLog(@"%d start: %s", entry->trackIndex, animationName);
|
||||
@ -68,18 +70,12 @@
|
||||
NSLog(@"%d event: %s, %d, %f, %s", entry->trackIndex, event->data->name, event->intValue, event->floatValue, event->stringValue);
|
||||
};
|
||||
|
||||
[skeletonNode setAnimationForTrack:0 name:@"walk" loop:YES];
|
||||
spTrackEntry* jumpEntry = [skeletonNode addAnimationForTrack:0 name:@"jump" loop:NO afterDelay:3];
|
||||
[skeletonNode addAnimationForTrack:0 name:@"run" loop:YES afterDelay:0];
|
||||
|
||||
[skeletonNode setListenerForEntry:jumpEntry onStart:^(spTrackEntry* entry) {
|
||||
CCLOG(@"jumped!");
|
||||
}];
|
||||
[skeletonNode setAnimationForTrack:0 name:@"animation" loop:YES];
|
||||
|
||||
// [skeletonNode setAnimationForTrack:1 name:@"test" loop:YES];
|
||||
|
||||
CGSize windowSize = [[CCDirector sharedDirector] viewSize];
|
||||
[skeletonNode setPosition:ccp(windowSize.width / 2, 20)];
|
||||
[skeletonNode setPosition:ccp(windowSize.width / 2, windowSize.height / 2)];
|
||||
[self addChild:skeletonNode];
|
||||
|
||||
self.userInteractionEnabled = YES;
|
||||
@ -90,12 +86,7 @@
|
||||
|
||||
#if ( TARGET_OS_IPHONE || TARGET_IPHONE_SIMULATOR )
|
||||
- (void)touchBegan:(UITouch *)touch withEvent:(UIEvent *)event {
|
||||
if (!skeletonNode.debugBones)
|
||||
skeletonNode.debugBones = true;
|
||||
else if (skeletonNode.timeScale == 1)
|
||||
skeletonNode.timeScale = 0.3f;
|
||||
else
|
||||
[[CCDirector sharedDirector] replaceScene:[GoblinsExample scene]];
|
||||
skeletonNode.twoColorTint = !skeletonNode.twoColorTint;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
@ -33,6 +33,7 @@
|
||||
652107961895250000B1FF07 /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 652107951895250000B1FF07 /* CoreText.framework */; };
|
||||
765A2EF61D7D7A08003FB779 /* goblins.atlas in Resources */ = {isa = PBXBuildFile; fileRef = 765A2EF41D7D7A08003FB779 /* goblins.atlas */; };
|
||||
765A2EF71D7D7A08003FB779 /* goblins.png in Resources */ = {isa = PBXBuildFile; fileRef = 765A2EF51D7D7A08003FB779 /* goblins.png */; };
|
||||
76BF7E071E66ED9C00485998 /* GLUtils.c in Sources */ = {isa = PBXBuildFile; fileRef = 76BF7E051E66ED9C00485998 /* GLUtils.c */; };
|
||||
76F28D161DEC810300CDE54D /* Animation.c in Sources */ = {isa = PBXBuildFile; fileRef = 76F28CF41DEC810200CDE54D /* Animation.c */; };
|
||||
76F28D171DEC810300CDE54D /* AnimationState.c in Sources */ = {isa = PBXBuildFile; fileRef = 76F28CF51DEC810300CDE54D /* AnimationState.c */; };
|
||||
76F28D181DEC810300CDE54D /* AnimationStateData.c in Sources */ = {isa = PBXBuildFile; fileRef = 76F28CF61DEC810300CDE54D /* AnimationStateData.c */; };
|
||||
@ -159,6 +160,8 @@
|
||||
652107951895250000B1FF07 /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; };
|
||||
765A2EF41D7D7A08003FB779 /* goblins.atlas */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = goblins.atlas; path = Resources/goblins.atlas; sourceTree = "<group>"; };
|
||||
765A2EF51D7D7A08003FB779 /* goblins.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = goblins.png; path = Resources/goblins.png; sourceTree = "<group>"; };
|
||||
76BF7E051E66ED9C00485998 /* GLUtils.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = GLUtils.c; path = src/spine/GLUtils.c; sourceTree = "<group>"; };
|
||||
76BF7E061E66ED9C00485998 /* GLUtils.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = GLUtils.h; path = src/spine/GLUtils.h; sourceTree = "<group>"; };
|
||||
76F28CF41DEC810200CDE54D /* Animation.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = Animation.c; path = "../spine-c/spine-c/src/spine/Animation.c"; sourceTree = "<group>"; };
|
||||
76F28CF51DEC810300CDE54D /* AnimationState.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = AnimationState.c; path = "../spine-c/spine-c/src/spine/AnimationState.c"; sourceTree = "<group>"; };
|
||||
76F28CF61DEC810300CDE54D /* AnimationStateData.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = AnimationStateData.c; path = "../spine-c/spine-c/src/spine/AnimationStateData.c"; sourceTree = "<group>"; };
|
||||
@ -326,6 +329,8 @@
|
||||
43F7FF861927F94800CA4038 /* SkeletonRenderer.m */,
|
||||
43C3282E170B0C19004A9460 /* spine-cocos2d-objc.h */,
|
||||
43C3282D170B0C19004A9460 /* spine-cocos2d-objc.m */,
|
||||
76BF7E051E66ED9C00485998 /* GLUtils.c */,
|
||||
76BF7E061E66ED9C00485998 /* GLUtils.h */,
|
||||
);
|
||||
name = "spine-cocos2d-objc";
|
||||
sourceTree = "<group>";
|
||||
@ -557,6 +562,7 @@
|
||||
76F28D171DEC810300CDE54D /* AnimationState.c in Sources */,
|
||||
76F28D221DEC810300CDE54D /* extension.c in Sources */,
|
||||
76F28D231DEC810300CDE54D /* IkConstraint.c in Sources */,
|
||||
76BF7E071E66ED9C00485998 /* GLUtils.c in Sources */,
|
||||
43C3282F170B0C19004A9460 /* spine-cocos2d-objc.m in Sources */,
|
||||
76F28D1F1DEC810300CDE54D /* BoundingBoxAttachment.c in Sources */,
|
||||
76F28D281DEC810300CDE54D /* PathConstraint.c in Sources */,
|
||||
@ -673,6 +679,7 @@
|
||||
);
|
||||
INFOPLIST_FILE = "Resources-ios/Info.plist";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
OTHER_CFLAGS = "";
|
||||
OTHER_LDFLAGS = (
|
||||
"-lz",
|
||||
"-lsqlite3",
|
||||
@ -700,6 +707,7 @@
|
||||
);
|
||||
INFOPLIST_FILE = "Resources-ios/Info.plist";
|
||||
LIBRARY_SEARCH_PATHS = "$(inherited)";
|
||||
OTHER_CFLAGS = "";
|
||||
OTHER_LDFLAGS = (
|
||||
"-lz",
|
||||
"-lsqlite3",
|
||||
|
||||
288
spine-cocos2d-objc/src/spine/GLUtils.c
Normal file
288
spine-cocos2d-objc/src/spine/GLUtils.c
Normal file
@ -0,0 +1,288 @@
|
||||
/******************************************************************************
|
||||
* Spine Runtimes Software License v2.5
|
||||
*
|
||||
* Copyright (c) 2013-2016, Esoteric Software
|
||||
* All rights reserved.
|
||||
*
|
||||
* You are granted a perpetual, non-exclusive, non-sublicensable, and
|
||||
* non-transferable license to use, install, execute, and perform the Spine
|
||||
* Runtimes software and derivative works solely for personal or internal
|
||||
* use. Without the written permission of Esoteric Software (see Section 2 of
|
||||
* the Spine Software License Agreement), you may not (a) modify, translate,
|
||||
* adapt, or develop new applications using the Spine Runtimes or otherwise
|
||||
* create derivative works or improvements of the Spine Runtimes or (b) remove,
|
||||
* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
|
||||
* or other intellectual property or proprietary rights notices on or in the
|
||||
* Software, including any copy thereof. Redistributions in binary or source
|
||||
* form must include this license and terms.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
|
||||
* USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
#include "GLUtils.h"
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
#include <spine/extension.h>
|
||||
|
||||
#include <TargetConditionals.h>
|
||||
#if TARGET_IPHONE_SIMULATOR || TARGET_OS_IPHONE
|
||||
#include <OpenGLES/ES2/gl.h>
|
||||
#include <OpenGLES/ES2/glext.h>
|
||||
#else
|
||||
#include <OpenGL/gl.h>
|
||||
#include <OpenGL/glu.h>
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#define STRINGIFY(A) #A
|
||||
#define MAX_VERTICES 64000
|
||||
#define MAX_INDICES 64000
|
||||
|
||||
const char* TWO_COLOR_TINT_VERTEX_SHADER = STRINGIFY(
|
||||
attribute vec4 a_position;
|
||||
attribute vec4 a_color;
|
||||
attribute vec4 a_color2;
|
||||
attribute vec2 a_texCoords;
|
||||
|
||||
\n#ifdef GL_ES\n
|
||||
varying lowp vec4 v_light;
|
||||
varying lowp vec4 v_dark;
|
||||
varying mediump vec2 v_texCoord;
|
||||
\n#else\n
|
||||
varying vec4 v_light;
|
||||
varying vec4 v_dark;
|
||||
varying vec2 v_texCoord;
|
||||
\n#endif\n
|
||||
|
||||
void main() {
|
||||
v_light = a_color;
|
||||
v_dark = a_color2;
|
||||
v_texCoord = a_texCoords;
|
||||
gl_Position = a_position;
|
||||
}
|
||||
);
|
||||
|
||||
const char* TWO_COLOR_TINT_FRAGMENT_SHADER = STRINGIFY(
|
||||
\n#ifdef GL_ES\n
|
||||
precision lowp float;
|
||||
\n#endif\n
|
||||
|
||||
uniform sampler2D texture;
|
||||
|
||||
varying vec4 v_light;
|
||||
varying vec4 v_dark;
|
||||
varying vec2 v_texCoord;
|
||||
|
||||
void main() {
|
||||
vec4 texColor = texture2D(texture, v_texCoord);
|
||||
float alpha = texColor.a * v_light.a;
|
||||
gl_FragColor.a = alpha;
|
||||
gl_FragColor.rgb = (1.0 - texColor.rgb) * v_dark.rgb * alpha + texColor.rgb * v_light.rgb;
|
||||
}
|
||||
);
|
||||
|
||||
spMesh* spMesh_create(uint32_t numVertices, uint32_t numIndices) {
|
||||
spMesh* mesh = MALLOC(spMesh, 1);
|
||||
mesh->vertices = MALLOC(spVertex, numVertices);
|
||||
mesh->indices = MALLOC(unsigned short, numIndices);
|
||||
mesh->numVertices = numVertices;
|
||||
mesh->numIndices = numIndices;
|
||||
mesh->numAllocatedVertices = 0;
|
||||
mesh->numAllocatedIndices = 0;
|
||||
return mesh;
|
||||
}
|
||||
|
||||
void spMesh_allocatePart(spMesh* mesh, spMeshPart* part, uint32_t numVertices, uint32_t numIndices, uint32_t textureHandle, uint32_t srcBlend, uint32_t dstBlend) {
|
||||
if (mesh->numVertices < mesh->numAllocatedVertices + numVertices) {
|
||||
mesh->numVertices = mesh->numAllocatedVertices + numVertices;
|
||||
mesh->vertices = REALLOC(mesh->vertices, spVertex, mesh->numVertices);
|
||||
}
|
||||
if (mesh->numIndices < mesh->numAllocatedIndices + numIndices) {
|
||||
mesh->numIndices = mesh->numAllocatedIndices + numIndices;
|
||||
mesh->indices = REALLOC(mesh->indices, unsigned short, mesh->numIndices);
|
||||
}
|
||||
|
||||
part->mesh = mesh;
|
||||
part->startVertex = mesh->numAllocatedVertices;
|
||||
part->numIndices = numIndices;
|
||||
part->startIndex = mesh->numAllocatedIndices;
|
||||
part->numVertices = numVertices;
|
||||
part->textureHandle = textureHandle;
|
||||
part->srcBlend = srcBlend;
|
||||
part->dstBlend = dstBlend;
|
||||
|
||||
mesh->numAllocatedVertices += numVertices;
|
||||
mesh->numAllocatedIndices += numIndices;
|
||||
}
|
||||
|
||||
void spMesh_clearParts(spMesh* mesh) {
|
||||
mesh->numAllocatedIndices = 0;
|
||||
mesh->numAllocatedVertices = 0;
|
||||
}
|
||||
|
||||
void spMesh_dispose(spMesh* mesh) {
|
||||
FREE(mesh->vertices);
|
||||
FREE(mesh->indices);
|
||||
FREE(mesh);
|
||||
}
|
||||
|
||||
GLuint compileShader(GLenum shaderType, const char* shaderSource) {
|
||||
GLuint shader = glCreateShader(shaderType);
|
||||
glShaderSource(shader, 1, &shaderSource, 0);
|
||||
glCompileShader(shader);
|
||||
GLint status;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
|
||||
if (!status) {
|
||||
GLsizei length;
|
||||
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &length);
|
||||
if (length < 1) {
|
||||
printf("Unknown error while compiling shader\n");
|
||||
exit(-1);
|
||||
} else {
|
||||
char* log = MALLOC(char, length);
|
||||
glGetShaderInfoLog(shader, length, 0, log);
|
||||
printf("Error compiling shader: %s\n", log);
|
||||
exit(-1);
|
||||
}
|
||||
}
|
||||
return shader;
|
||||
}
|
||||
|
||||
spShader* spShader_create(const char* vertexShaderSource, const char* fragmentShaderSource) {
|
||||
GLuint vertexShader = compileShader(GL_VERTEX_SHADER, vertexShaderSource);
|
||||
GLuint fragmentShader = compileShader(GL_FRAGMENT_SHADER, fragmentShaderSource);
|
||||
|
||||
GLuint program = glCreateProgram();
|
||||
glAttachShader(program, vertexShader);
|
||||
glAttachShader(program, fragmentShader);
|
||||
glLinkProgram(program);
|
||||
|
||||
GLint status;
|
||||
glGetProgramiv(program, GL_LINK_STATUS, &status);
|
||||
if (!status) {
|
||||
printf("Unknown error while linking program\n");
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
spShader* shader = MALLOC(spShader, 1);
|
||||
shader->program = program;
|
||||
shader->vertexShader = vertexShader;
|
||||
shader->fragmentShader = fragmentShader;
|
||||
return shader;
|
||||
}
|
||||
|
||||
void spShader_dispose(spShader* shader) {
|
||||
glDeleteProgram(shader->program);
|
||||
glDeleteShader(shader->vertexShader);
|
||||
glDeleteShader(shader->fragmentShader);
|
||||
FREE(shader);
|
||||
}
|
||||
|
||||
spTwoColorBatcher* spTwoColorBatcher_create() {
|
||||
spTwoColorBatcher* batcher = MALLOC(spTwoColorBatcher, 1);
|
||||
|
||||
batcher->shader = spShader_create(TWO_COLOR_TINT_VERTEX_SHADER, TWO_COLOR_TINT_FRAGMENT_SHADER);
|
||||
batcher->positionAttributeLocation = glGetAttribLocation(batcher->shader->program, "a_position");
|
||||
batcher->colorAttributeLocation = glGetAttribLocation(batcher->shader->program, "a_color");
|
||||
batcher->color2AttributeLocation = glGetAttribLocation(batcher->shader->program, "a_color2");
|
||||
batcher->texCoordsAttributeLocation = glGetAttribLocation(batcher->shader->program, "a_texCoords");
|
||||
batcher->textureUniformLocation = glGetUniformLocation(batcher->shader->program, "texture");
|
||||
|
||||
glGenBuffers(1, &batcher->vertexBufferHandle);
|
||||
glGenBuffers(1, &batcher->indexBufferHandle);
|
||||
batcher->verticesBuffer = MALLOC(spVertex, MAX_VERTICES);
|
||||
batcher->indicesBuffer = MALLOC(unsigned short, MAX_INDICES);
|
||||
batcher->numIndices = 0;
|
||||
batcher->numVertices = 0;
|
||||
batcher->lastTextureHandle = -1;
|
||||
batcher->lastSrcBlend = -1;
|
||||
batcher->lastDstBlend = -1;
|
||||
return batcher;
|
||||
}
|
||||
|
||||
void spTwoColorBatcher_add(spTwoColorBatcher* batcher, spMeshPart mesh) {
|
||||
if (batcher->numVertices + mesh.numVertices > MAX_VERTICES || batcher->numIndices + mesh.numIndices > MAX_INDICES) {
|
||||
spTwoColorBatcher_flush(batcher);
|
||||
}
|
||||
|
||||
if (batcher->lastTextureHandle != mesh.textureHandle || batcher->lastSrcBlend != mesh.srcBlend || batcher->lastDstBlend != mesh.dstBlend) {
|
||||
spTwoColorBatcher_flush(batcher);
|
||||
}
|
||||
|
||||
spVertex* vertices = &batcher->verticesBuffer[batcher->numVertices];
|
||||
unsigned short* indices = &batcher->indicesBuffer[batcher->numIndices];
|
||||
|
||||
memcpy(vertices, &mesh.mesh->vertices[mesh.startVertex], mesh.numVertices * sizeof(spVertex));
|
||||
unsigned short offset = (unsigned short)batcher->numVertices;
|
||||
for (int i = 0, j = mesh.startIndex, n = mesh.numIndices; i < n; i++, j++) {
|
||||
indices[i] = mesh.mesh->indices[j] + offset;
|
||||
}
|
||||
|
||||
batcher->numIndices += mesh.numIndices;
|
||||
batcher->numVertices += mesh.numVertices;
|
||||
batcher->lastSrcBlend = mesh.srcBlend;
|
||||
batcher->lastDstBlend = mesh.dstBlend;
|
||||
batcher->lastTextureHandle = mesh.textureHandle;
|
||||
}
|
||||
|
||||
void spTwoColorBatcher_flush(spTwoColorBatcher* batcher) {
|
||||
if (batcher->numVertices == 0 || batcher->numIndices == 0)
|
||||
return;
|
||||
|
||||
glUseProgram(batcher->shader->program);
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, batcher->lastTextureHandle);
|
||||
glUniform1i(batcher->textureUniformLocation, 0);
|
||||
|
||||
glBlendFunc(batcher->lastSrcBlend, batcher->lastDstBlend);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, batcher->vertexBufferHandle);
|
||||
glBufferData(GL_ARRAY_BUFFER, sizeof(spVertex) * batcher->numVertices , batcher->verticesBuffer, GL_DYNAMIC_DRAW);
|
||||
|
||||
glEnableVertexAttribArray(batcher->positionAttributeLocation);
|
||||
glEnableVertexAttribArray(batcher->colorAttributeLocation);
|
||||
glEnableVertexAttribArray(batcher->color2AttributeLocation);
|
||||
glEnableVertexAttribArray(batcher->texCoordsAttributeLocation);
|
||||
|
||||
glVertexAttribPointer(batcher->positionAttributeLocation, 4, GL_FLOAT, GL_FALSE, sizeof(spVertex), (GLvoid*)offsetof(spVertex, x));
|
||||
glVertexAttribPointer(batcher->colorAttributeLocation, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(spVertex), (GLvoid*)offsetof(spVertex, color));
|
||||
glVertexAttribPointer(batcher->color2AttributeLocation, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(spVertex), (GLvoid*)offsetof(spVertex, color2));
|
||||
glVertexAttribPointer(batcher->texCoordsAttributeLocation, 2, GL_FLOAT, GL_FALSE, sizeof(spVertex), (GLvoid*)offsetof(spVertex, u));
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, batcher->indexBufferHandle);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short) * batcher->numIndices, batcher->indicesBuffer, GL_STATIC_DRAW);
|
||||
|
||||
glDrawElements(GL_TRIANGLES, (GLsizei)batcher->numIndices, GL_UNSIGNED_SHORT, 0);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
|
||||
glUseProgram(0);
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
batcher->numIndices = 0;
|
||||
batcher->numVertices = 0;
|
||||
batcher->lastSrcBlend = -1;
|
||||
batcher->lastDstBlend = -1;
|
||||
batcher->lastTextureHandle = -1;
|
||||
}
|
||||
|
||||
void spDisposeTwoColorBatcher(spTwoColorBatcher* batcher) {
|
||||
spShader_dispose(batcher->shader);
|
||||
glDeleteBuffers(1, &batcher->vertexBufferHandle);
|
||||
FREE(batcher->verticesBuffer);
|
||||
glDeleteBuffers(1, &batcher->indexBufferHandle);
|
||||
FREE(batcher->indicesBuffer);
|
||||
}
|
||||
104
spine-cocos2d-objc/src/spine/GLUtils.h
Normal file
104
spine-cocos2d-objc/src/spine/GLUtils.h
Normal file
@ -0,0 +1,104 @@
|
||||
/******************************************************************************
|
||||
* Spine Runtimes Software License v2.5
|
||||
*
|
||||
* Copyright (c) 2013-2016, Esoteric Software
|
||||
* All rights reserved.
|
||||
*
|
||||
* You are granted a perpetual, non-exclusive, non-sublicensable, and
|
||||
* non-transferable license to use, install, execute, and perform the Spine
|
||||
* Runtimes software and derivative works solely for personal or internal
|
||||
* use. Without the written permission of Esoteric Software (see Section 2 of
|
||||
* the Spine Software License Agreement), you may not (a) modify, translate,
|
||||
* adapt, or develop new applications using the Spine Runtimes or otherwise
|
||||
* create derivative works or improvements of the Spine Runtimes or (b) remove,
|
||||
* delete, alter, or obscure any trademarks or any copyright, trademark, patent,
|
||||
* or other intellectual property or proprietary rights notices on or in the
|
||||
* Software, including any copy thereof. Redistributions in binary or source
|
||||
* form must include this license and terms.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ESOTERIC SOFTWARE "AS IS" AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||
* EVENT SHALL ESOTERIC SOFTWARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, BUSINESS INTERRUPTION, OR LOSS OF
|
||||
* USE, DATA, OR PROFITS) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
|
||||
* IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef GLUtils_h
|
||||
#define GLUtils_h
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
typedef struct spVertex {
|
||||
float x, y, z, w;
|
||||
uint32_t color;
|
||||
uint32_t color2;
|
||||
float u, v;
|
||||
} spVertex;
|
||||
|
||||
typedef struct spMesh {
|
||||
spVertex* vertices;
|
||||
uint32_t numVertices;
|
||||
uint32_t numAllocatedVertices;
|
||||
unsigned short* indices;
|
||||
uint32_t numIndices;
|
||||
uint32_t numAllocatedIndices;
|
||||
} spMesh;
|
||||
|
||||
typedef struct spMeshPart {
|
||||
spMesh* mesh;
|
||||
uint32_t startVertex;
|
||||
uint32_t numVertices;
|
||||
uint32_t startIndex;
|
||||
uint32_t numIndices;
|
||||
uint32_t textureHandle;
|
||||
uint32_t srcBlend;
|
||||
uint32_t dstBlend;
|
||||
} spMeshPart;
|
||||
|
||||
spMesh* spMesh_create(uint32_t numVertices, uint32_t numIndices);
|
||||
void spMesh_allocatePart(spMesh* mesh, spMeshPart* part, uint32_t numVertices, uint32_t numIndices, uint32_t textureHandle, uint32_t srcBlend, uint32_t dstBlend);
|
||||
void spMesh_clearParts(spMesh* mesh);
|
||||
void spMesh_dispose(spMesh* mesh);
|
||||
|
||||
typedef struct spShader {
|
||||
uint32_t program;
|
||||
uint32_t vertexShader;
|
||||
uint32_t fragmentShader;
|
||||
} spShader;
|
||||
|
||||
spShader* spShader_create(const char* vertexShaderSource, const char* fragmentShaderSource);
|
||||
void spShader_dispose(spShader* shader);
|
||||
|
||||
typedef struct spTwoColorBatcher {
|
||||
spShader* shader;
|
||||
|
||||
uint32_t vertexBufferHandle;
|
||||
spVertex* verticesBuffer;
|
||||
uint32_t numVertices;
|
||||
|
||||
uint32_t indexBufferHandle;
|
||||
unsigned short* indicesBuffer;
|
||||
uint32_t numIndices;
|
||||
|
||||
int32_t positionAttributeLocation;
|
||||
int32_t colorAttributeLocation;
|
||||
int32_t color2AttributeLocation;
|
||||
int32_t texCoordsAttributeLocation;
|
||||
int32_t textureUniformLocation;
|
||||
|
||||
uint32_t lastTextureHandle;
|
||||
uint32_t lastSrcBlend;
|
||||
uint32_t lastDstBlend;
|
||||
} spTwoColorBatcher;
|
||||
|
||||
spTwoColorBatcher* spTwoColorBatcher_create();
|
||||
void spTwoColorBatcher_add(spTwoColorBatcher* batcher, spMeshPart meshPart);
|
||||
void spTwoColorBatcher_flush(spTwoColorBatcher* batcher);
|
||||
void spDisposeTwoColorBatcher(spTwoColorBatcher* batcher);
|
||||
|
||||
#endif /* GLUtils_h */
|
||||
@ -38,6 +38,7 @@
|
||||
bool _debugSlots;
|
||||
bool _debugBones;
|
||||
bool _premultipliedAlpha;
|
||||
bool _twoColorTint;
|
||||
bool _skipVisibilityCheck;
|
||||
ccBlendFunc _blendFunc;
|
||||
CCDrawNode* _drawNode;
|
||||
@ -83,6 +84,7 @@
|
||||
- (bool) setAttachment:(NSString*)slotName attachmentName:(NSString*)attachmentName;
|
||||
|
||||
@property (nonatomic, readonly) spSkeleton* skeleton;
|
||||
@property (nonatomic) bool twoColorTint;
|
||||
@property (nonatomic) bool debugSlots;
|
||||
@property (nonatomic) bool debugBones;
|
||||
@property (nonatomic) bool skipVisibilityCheck;
|
||||
|
||||
@ -31,9 +31,13 @@
|
||||
#import <spine/SkeletonRenderer.h>
|
||||
#import <spine/spine-cocos2d-objc.h>
|
||||
#import <spine/extension.h>
|
||||
#import <spine/GLUtils.h>
|
||||
#import "CCDrawNode.h"
|
||||
|
||||
static const unsigned short quadTriangles[6] = {0, 1, 2, 2, 3, 0};
|
||||
static spTwoColorBatcher* batcher = 0;
|
||||
static spMesh* mesh = 0;
|
||||
static bool handlerQueued = false;
|
||||
|
||||
@interface SkeletonRenderer (Private)
|
||||
- (void) initialize:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData;
|
||||
@ -43,6 +47,7 @@ static const unsigned short quadTriangles[6] = {0, 1, 2, 2, 3, 0};
|
||||
|
||||
@synthesize skeleton = _skeleton;
|
||||
@synthesize rootBone = _rootBone;
|
||||
@synthesize twoColorTint = _twoColorTint;
|
||||
@synthesize debugSlots = _debugSlots;
|
||||
@synthesize debugBones = _debugBones;
|
||||
|
||||
@ -59,6 +64,11 @@ static const unsigned short quadTriangles[6] = {0, 1, 2, 2, 3, 0};
|
||||
}
|
||||
|
||||
- (void) initialize:(spSkeletonData*)skeletonData ownsSkeletonData:(bool)ownsSkeletonData {
|
||||
if (!batcher) {
|
||||
batcher = spTwoColorBatcher_create();
|
||||
mesh = spMesh_create(64000, 32000);
|
||||
}
|
||||
|
||||
_ownsSkeletonData = ownsSkeletonData;
|
||||
|
||||
_worldVertices = MALLOC(float, 1000); // Max number of vertices per mesh.
|
||||
@ -147,6 +157,20 @@ static const unsigned short quadTriangles[6] = {0, 1, 2, 2, 3, 0};
|
||||
}
|
||||
|
||||
-(void)draw:(CCRenderer *)renderer transform:(const GLKMatrix4 *)transform {
|
||||
// FIXME we need to clear the mesh parts at the end of the frame
|
||||
// there's no general event mechanism to get notified on end frame
|
||||
// that doesn't need to be re-added every frame. This is a poor man
|
||||
// notification system that may break if the block is called on a
|
||||
// separate thread.
|
||||
if (!handlerQueued) {
|
||||
[[CCDirector sharedDirector] addFrameCompletionHandler: ^{
|
||||
printf("clearing mesh\n");
|
||||
spMesh_clearParts(mesh);
|
||||
handlerQueued = false;
|
||||
}];
|
||||
handlerQueued = true;
|
||||
}
|
||||
|
||||
CCColor* nodeColor = self.color;
|
||||
_skeleton->color.r = nodeColor.red;
|
||||
_skeleton->color.g = nodeColor.green;
|
||||
@ -154,11 +178,14 @@ static const unsigned short quadTriangles[6] = {0, 1, 2, 2, 3, 0};
|
||||
_skeleton->color.a = self.displayedOpacity;
|
||||
|
||||
int blendMode = -1;
|
||||
uint32_t srcBlend = GL_SRC_ALPHA;
|
||||
uint32_t dstBlend = GL_ONE_MINUS_SRC_ALPHA;
|
||||
const float* uvs = 0;
|
||||
int verticesCount = 0;
|
||||
const unsigned short* triangles = 0;
|
||||
int trianglesCount = 0;
|
||||
float r = 0, g = 0, b = 0, a = 0;
|
||||
float dr = 0, dg = 0, db = 0;
|
||||
for (int i = 0, n = _skeleton->slotsCount; i < n; i++) {
|
||||
spSlot* slot = _skeleton->drawOrder[i];
|
||||
if (!slot->attachment) continue;
|
||||
@ -200,15 +227,23 @@ static const unsigned short quadTriangles[6] = {0, 1, 2, 2, 3, 0};
|
||||
switch (slot->data->blendMode) {
|
||||
case SP_BLEND_MODE_ADDITIVE:
|
||||
[self setBlendMode:[CCBlendMode addMode]];
|
||||
srcBlend = !_premultipliedAlpha ? GL_SRC_ALPHA : GL_ONE;
|
||||
dstBlend = GL_ONE;
|
||||
break;
|
||||
case SP_BLEND_MODE_MULTIPLY:
|
||||
[self setBlendMode:[CCBlendMode multiplyMode]];
|
||||
srcBlend = GL_DST_COLOR;
|
||||
dstBlend = GL_ONE_MINUS_SRC_ALPHA;
|
||||
break;
|
||||
case SP_BLEND_MODE_SCREEN:
|
||||
[self setBlendMode:screenMode];
|
||||
srcBlend = GL_ONE;
|
||||
dstBlend = GL_ONE_MINUS_SRC_COLOR;
|
||||
break;
|
||||
default:
|
||||
[self setBlendMode:_premultipliedAlpha ? [CCBlendMode premultipliedAlphaMode] : [CCBlendMode alphaMode]];
|
||||
srcBlend = !_premultipliedAlpha ? GL_SRC_ALPHA : GL_ONE;
|
||||
dstBlend = GL_ONE_MINUS_SRC_ALPHA;
|
||||
}
|
||||
}
|
||||
if (_premultipliedAlpha) {
|
||||
@ -227,20 +262,65 @@ static const unsigned short quadTriangles[6] = {0, 1, 2, 2, 3, 0};
|
||||
GLKVector2 center = GLKVector2Make(size.width / 2.0, size.height / 2.0);
|
||||
GLKVector2 extents = GLKVector2Make(size.width / 2.0, size.height / 2.0);
|
||||
if (_skipVisibilityCheck || CCRenderCheckVisbility(transform, center, extents)) {
|
||||
CCRenderBuffer buffer = [renderer enqueueTriangles:(trianglesCount / 3) andVertexes:verticesCount withState:self.renderState globalSortOrder:0];
|
||||
for (int i = 0; i * 2 < verticesCount; ++i) {
|
||||
CCVertex vertex;
|
||||
vertex.position = GLKVector4Make(_worldVertices[i * 2], _worldVertices[i * 2 + 1], 0.0, 1.0);
|
||||
vertex.color = GLKVector4Make(r, g, b, a);
|
||||
vertex.texCoord1 = GLKVector2Make(uvs[i * 2], 1 - uvs[i * 2 + 1]);
|
||||
CCRenderBufferSetVertex(buffer, i, CCVertexApplyTransform(vertex, transform));
|
||||
}
|
||||
for (int j = 0; j * 3 < trianglesCount; ++j) {
|
||||
CCRenderBufferSetTriangle(buffer, j, triangles[j * 3], triangles[j * 3 + 1], triangles[j * 3 + 2]);
|
||||
if (!self.twoColorTint) {
|
||||
CCRenderBuffer buffer = [renderer enqueueTriangles:(trianglesCount / 3) andVertexes:verticesCount withState:self.renderState globalSortOrder:0];
|
||||
for (int i = 0; i * 2 < verticesCount; ++i) {
|
||||
CCVertex vertex;
|
||||
vertex.position = GLKVector4Make(_worldVertices[i * 2], _worldVertices[i * 2 + 1], 0.0, 1.0);
|
||||
vertex.color = GLKVector4Make(r, g, b, a);
|
||||
vertex.texCoord1 = GLKVector2Make(uvs[i * 2], 1 - uvs[i * 2 + 1]);
|
||||
CCRenderBufferSetVertex(buffer, i, CCVertexApplyTransform(vertex, transform));
|
||||
}
|
||||
for (int j = 0; j * 3 < trianglesCount; ++j) {
|
||||
CCRenderBufferSetTriangle(buffer, j, triangles[j * 3], triangles[j * 3 + 1], triangles[j * 3 + 2]);
|
||||
}
|
||||
} else {
|
||||
if (slot->darkColor) {
|
||||
dr = slot->darkColor->r;
|
||||
dg = slot->darkColor->g;
|
||||
db = slot->darkColor->b;
|
||||
} else {
|
||||
dr = dg = db = 0;
|
||||
}
|
||||
|
||||
spMeshPart meshPart;
|
||||
spMesh_allocatePart(mesh, &meshPart, verticesCount / 2, trianglesCount, self.texture.name, srcBlend, dstBlend);
|
||||
|
||||
spVertex* vertices = &meshPart.mesh->vertices[meshPart.startVertex];
|
||||
unsigned short* indices = &meshPart.mesh->indices[meshPart.startIndex];
|
||||
|
||||
for (int i = 0; i * 2 < verticesCount; i++, vertices++) {
|
||||
CCVertex vertex;
|
||||
vertex.position = GLKVector4Make(_worldVertices[i * 2], _worldVertices[i * 2 + 1], 0.0, 1.0);
|
||||
vertex = CCVertexApplyTransform(vertex, transform);
|
||||
vertices->x = vertex.position.x;
|
||||
vertices->y = vertex.position.y;
|
||||
vertices->z = vertex.position.z;
|
||||
vertices->w = vertex.position.w;
|
||||
vertices->color = ((unsigned short)(r * 255))| ((unsigned short)(g * 255)) << 8 | ((unsigned short)(b * 255)) <<16 | ((unsigned short)(a * 255)) << 24;
|
||||
vertices->color2 = ((unsigned short)(dr * 255)) | ((unsigned short)(dg * 255)) << 8 | ((unsigned short)(db * 255)) << 16 | ((unsigned short)(255)) << 24;
|
||||
vertices->u = uvs[i * 2];
|
||||
vertices->v = 1 - uvs[i * 2 + 1];
|
||||
}
|
||||
|
||||
for (int j = 0; j < trianglesCount; j++, indices++) {
|
||||
*indices = triangles[j];
|
||||
}
|
||||
|
||||
[renderer enqueueBlock:^{
|
||||
spTwoColorBatcher_add(batcher, meshPart);
|
||||
} globalSortOrder:0 debugLabel: nil threadSafe: false];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (self.twoColorTint) {
|
||||
[renderer enqueueBlock:^{
|
||||
spTwoColorBatcher_flush(batcher);
|
||||
} globalSortOrder:0 debugLabel: nil threadSafe: false];
|
||||
}
|
||||
|
||||
[_drawNode clear];
|
||||
if (_debugSlots) {
|
||||
// Slots.
|
||||
|
||||
@ -2,14 +2,14 @@ cmake_minimum_required(VERSION 2.8)
|
||||
set(EXAMPLE_DIR "${CMAKE_CURRENT_LIST_DIR}/example")
|
||||
if (NOT EXISTS ${EXAMPLE_DIR}/cocos2d)
|
||||
message("Downloading cocos2dx, this may take some time!")
|
||||
file(DOWNLOAD "http://cdn.cocos2d-x.org/cocos2d-x-3.13.zip" "${EXAMPLE_DIR}/cocos2dx.zip")
|
||||
file(DOWNLOAD "http://www.cocos2d-x.org/filedown/start/364" "${EXAMPLE_DIR}/cocos2dx.zip")
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E tar x ${EXAMPLE_DIR}/cocos2dx.zip
|
||||
WORKING_DIRECTORY ${EXAMPLE_DIR}
|
||||
)
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E rename
|
||||
"${EXAMPLE_DIR}/cocos2d-x-3.13" "${EXAMPLE_DIR}/cocos2d"
|
||||
"${EXAMPLE_DIR}/cocos2d-x-3.14.1" "${EXAMPLE_DIR}/cocos2d"
|
||||
)
|
||||
execute_process(
|
||||
COMMAND ${CMAKE_COMMAND} -E remove_directory "${EXAMPLE_DIR}/cocos2d/cocos/editor-support/spine"
|
||||
|
||||
@ -10,7 +10,7 @@ The Spine Runtimes are developed with the intent to be used with data exported f
|
||||
|
||||
## Spine version
|
||||
|
||||
spine-cocos2dx works with data exported from Spine 3.5.xx.
|
||||
spine-cocos2dx works with data exported from Spine 3.6.xx.
|
||||
|
||||
spine-cocos2dx supports all Spine features.
|
||||
|
||||
@ -36,6 +36,7 @@ The Spine cocos2d-x example works on Windows and Mac OS X.
|
||||
5. Click `Browse Source` and select the directory `spine-runtimes`
|
||||
6. Click `Browse Build` and select the `spine-runtimes/spine-cocos2dx/build` directory. You can create the `build` folder directly in the file dialog via `New Folder`.
|
||||
7. Click `Configure`. This will download the cocos2d-x dependency and wire it up with the example source code in `spine-runtimes/spine-cocos2dx/example`. The download is 400mb, so get yourself a cup of tea.
|
||||
7. Open the file `spine-cocos2dx\example\cocos2d\cocos\2d\cocos2dx.props` and remove the `libSpine.lib` entry from the `<AdditionalDependencies>` tag.
|
||||
8. Open the `spine-runtimes/spine-cocos2dx/example/proj.win32/spine-cocos2d-x.sln` file in Visual Studio 2015. Visual Studio may ask you to install the Windows XP/7 SDK, which you should install.
|
||||
9. Expand the cocos2d_libs sub project and delete the `editor-support/spine` group. This will remove the outdated Spine cocos2d-x runtime shipped by cocos2d-x from your build.
|
||||
9. Expand `References` of the cocos2d_libs sub project, and remove the entry for `libSpine`, which should be marked with an error.
|
||||
@ -68,7 +69,8 @@ The Spine cocos2d-x example works on Windows and Mac OS X.
|
||||
|
||||
## Notes
|
||||
|
||||
- Images are premultiplied by cocos2d-x, so the Spine atlas images should *not* use premultiplied alpha.
|
||||
* Images are premultiplied by cocos2d-x, so the Spine atlas images should *not* use premultiplied alpha.
|
||||
* Two color tinting needs to be enabled on a per-skeleton basis. Call `SkeletonRenderer::setTwoColorTine(true)` or `SkeletonAnimation::setTwoColorTint(true)` after you created the skeleton instance. Note that two color tinting requires a custom shader and vertex format. Skeletons rendered with two color tinting can therefore not be batched with single color tinted skeletons or other 2D cocos2d-x elements like sprites. However, two-color tinted skeletons will be batched if possible when rendered after one another. Attaching a child to a two color tinted skeleton will also break the batch.
|
||||
|
||||
## Examples
|
||||
|
||||
|
||||
@ -65,7 +65,7 @@ bool BatchingExample::init () {
|
||||
|
||||
int xMin = _contentSize.width * 0.10f, xMax = _contentSize.width * 0.90f;
|
||||
int yMin = 0, yMax = _contentSize.height * 0.7f;
|
||||
for (int i = 0; i < 500; i++) {
|
||||
for (int i = 0, j = 0; i < 50; i++) {
|
||||
// Each skeleton node shares the same atlas, skeleton data, and mix times.
|
||||
SkeletonAnimation* skeletonNode = SkeletonAnimation::createWithData(_skeletonData, false);
|
||||
skeletonNode->setAnimationStateData(_stateData);
|
||||
@ -73,6 +73,12 @@ bool BatchingExample::init () {
|
||||
skeletonNode->setAnimation(0, "walk", true);
|
||||
skeletonNode->addAnimation(0, "jump", true, RandomHelper::random_int(0, 300) / 100.0f);
|
||||
skeletonNode->addAnimation(0, "run", true);
|
||||
|
||||
// alternative setting two color tint for groups of 10 skeletons
|
||||
// should end up with #skeletons / 10 batches
|
||||
if (j++ < 10)
|
||||
skeletonNode->setTwoColorTint(true);
|
||||
if (j == 20) j = 0;
|
||||
|
||||
skeletonNode->setPosition(Vec2(
|
||||
RandomHelper::random_int(xMin, xMax),
|
||||
|
||||
@ -23,6 +23,7 @@ LOCAL_SRC_FILES := hellocpp/main.cpp \
|
||||
../../../src/spine/Cocos2dAttachmentLoader.cpp \
|
||||
../../../src/spine/SkeletonAnimation.cpp \
|
||||
../../../src/spine/SkeletonBatch.cpp \
|
||||
../../../src/spine/SkeletonTwoColorBatch.cpp \
|
||||
../../../src/spine/SkeletonRenderer.cpp \
|
||||
../../../src/spine/spine-cocos2dx.cpp \
|
||||
../../../../spine-c/spine-c/src/spine/Animation.c \
|
||||
@ -35,6 +36,7 @@ LOCAL_SRC_FILES := hellocpp/main.cpp \
|
||||
../../../../spine-c/spine-c/src/spine/Bone.c \
|
||||
../../../../spine-c/spine-c/src/spine/BoneData.c \
|
||||
../../../../spine-c/spine-c/src/spine/BoundingBoxAttachment.c \
|
||||
../../../../spine-c/spine-c/src/spine/Color.c \
|
||||
../../../../spine-c/spine-c/src/spine/Event.c \
|
||||
../../../../spine-c/spine-c/src/spine/EventData.c \
|
||||
../../../../spine-c/spine-c/src/spine/IkConstraint.c \
|
||||
@ -42,6 +44,7 @@ LOCAL_SRC_FILES := hellocpp/main.cpp \
|
||||
../../../../spine-c/spine-c/src/spine/Json.c \
|
||||
../../../../spine-c/spine-c/src/spine/MeshAttachment.c \
|
||||
../../../../spine-c/spine-c/src/spine/PathAttachment.c \
|
||||
../../../../spine-c/spine-c/src/spine/PointAttachment.c \
|
||||
../../../../spine-c/spine-c/src/spine/PathConstraint.c \
|
||||
../../../../spine-c/spine-c/src/spine/PathConstraintData.c \
|
||||
../../../../spine-c/spine-c/src/spine/RegionAttachment.c \
|
||||
|
||||
@ -46,6 +46,8 @@
|
||||
521A8E6519F0C34300D177D7 /* Default-736h@3x.png in Resources */ = {isa = PBXBuildFile; fileRef = 521A8E6319F0C34300D177D7 /* Default-736h@3x.png */; };
|
||||
52B47A471A53D09C004E4C60 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 52B47A461A53D09B004E4C60 /* Security.framework */; };
|
||||
7602C5551D7DAA1300C7C674 /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 7602C5541D7DAA1300C7C674 /* CoreText.framework */; };
|
||||
76A45BDE1E64396800745AA1 /* SkeletonTwoColorBatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 76A45BDC1E64396800745AA1 /* SkeletonTwoColorBatch.cpp */; };
|
||||
76A45BDF1E64396800745AA1 /* SkeletonTwoColorBatch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 76A45BDC1E64396800745AA1 /* SkeletonTwoColorBatch.cpp */; };
|
||||
76AAA3C01D180F7C00C54FCB /* AppDelegate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 76AAA3B31D180F7C00C54FCB /* AppDelegate.cpp */; };
|
||||
76AAA3C11D180F7C00C54FCB /* BatchingExample.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 76AAA3B61D180F7C00C54FCB /* BatchingExample.cpp */; };
|
||||
76AAA3C21D180F7C00C54FCB /* GoblinsExample.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 76AAA3B81D180F7C00C54FCB /* GoblinsExample.cpp */; };
|
||||
@ -251,6 +253,8 @@
|
||||
521A8E6319F0C34300D177D7 /* Default-736h@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-736h@3x.png"; sourceTree = "<group>"; };
|
||||
52B47A461A53D09B004E4C60 /* Security.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Security.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.1.sdk/System/Library/Frameworks/Security.framework; sourceTree = DEVELOPER_DIR; };
|
||||
7602C5541D7DAA1300C7C674 /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS9.3.sdk/System/Library/Frameworks/CoreText.framework; sourceTree = DEVELOPER_DIR; };
|
||||
76A45BDC1E64396800745AA1 /* SkeletonTwoColorBatch.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SkeletonTwoColorBatch.cpp; path = ../../src/spine/SkeletonTwoColorBatch.cpp; sourceTree = "<group>"; };
|
||||
76A45BDD1E64396800745AA1 /* SkeletonTwoColorBatch.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SkeletonTwoColorBatch.h; path = ../../src/spine/SkeletonTwoColorBatch.h; sourceTree = "<group>"; };
|
||||
76AAA3B31D180F7C00C54FCB /* AppDelegate.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AppDelegate.cpp; sourceTree = "<group>"; };
|
||||
76AAA3B41D180F7C00C54FCB /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
|
||||
76AAA3B51D180F7C00C54FCB /* AppMacros.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppMacros.h; sourceTree = "<group>"; };
|
||||
@ -573,6 +577,8 @@
|
||||
76AAA3FF1D18102C00C54FCB /* spine-cocos2dx */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
76A45BDC1E64396800745AA1 /* SkeletonTwoColorBatch.cpp */,
|
||||
76A45BDD1E64396800745AA1 /* SkeletonTwoColorBatch.h */,
|
||||
76AAA4001D18106000C54FCB /* AttachmentVertices.cpp */,
|
||||
76AAA4011D18106000C54FCB /* AttachmentVertices.h */,
|
||||
76AAA4021D18106000C54FCB /* Cocos2dAttachmentLoader.cpp */,
|
||||
@ -775,6 +781,7 @@
|
||||
503AE10217EB989F00D1A890 /* RootViewController.mm in Sources */,
|
||||
503AE10117EB989F00D1A890 /* main.m in Sources */,
|
||||
76F28CCB1DEC7EBB00CDE54D /* Skin.c in Sources */,
|
||||
76A45BDE1E64396800745AA1 /* SkeletonTwoColorBatch.cpp in Sources */,
|
||||
76F28CBF1DEC7EBB00CDE54D /* IkConstraintData.c in Sources */,
|
||||
76F28CC61DEC7EBB00CDE54D /* Skeleton.c in Sources */,
|
||||
76AAA4101D18106000C54FCB /* SkeletonRenderer.cpp in Sources */,
|
||||
@ -840,6 +847,7 @@
|
||||
76AAA4121D18119F00C54FCB /* AttachmentVertices.cpp in Sources */,
|
||||
76AAA4131D18119F00C54FCB /* AttachmentVertices.h in Sources */,
|
||||
76AAA4141D18119F00C54FCB /* Cocos2dAttachmentLoader.cpp in Sources */,
|
||||
76A45BDF1E64396800745AA1 /* SkeletonTwoColorBatch.cpp in Sources */,
|
||||
76AAA4151D18119F00C54FCB /* Cocos2dAttachmentLoader.h in Sources */,
|
||||
76AAA4161D18119F00C54FCB /* SkeletonAnimation.cpp in Sources */,
|
||||
76AAA4171D18119F00C54FCB /* SkeletonAnimation.h in Sources */,
|
||||
|
||||
@ -2,9 +2,7 @@
|
||||
#include "AppDelegate.h"
|
||||
#include "cocos2d.h"
|
||||
|
||||
USING_NS_CC;
|
||||
|
||||
int APIENTRY _tWinMain(HINSTANCE hInstance,
|
||||
int wWinMain(HINSTANCE hInstance,
|
||||
HINSTANCE hPrevInstance,
|
||||
LPTSTR lpCmdLine,
|
||||
int nCmdShow)
|
||||
@ -14,5 +12,5 @@ int APIENTRY _tWinMain(HINSTANCE hInstance,
|
||||
|
||||
// create the application instance
|
||||
AppDelegate app;
|
||||
return Application::getInstance()->run();
|
||||
return cocos2d::Application::getInstance()->run();
|
||||
}
|
||||
|
||||
@ -155,6 +155,7 @@ xcopy "$(ProjectDir)..\Resources" "$(OutDir)" /D /E /I /F /Y
|
||||
<ClCompile Include="..\..\..\spine-c\spine-c\src\spine\Bone.c" />
|
||||
<ClCompile Include="..\..\..\spine-c\spine-c\src\spine\BoneData.c" />
|
||||
<ClCompile Include="..\..\..\spine-c\spine-c\src\spine\BoundingBoxAttachment.c" />
|
||||
<ClCompile Include="..\..\..\spine-c\spine-c\src\spine\Color.c" />
|
||||
<ClCompile Include="..\..\..\spine-c\spine-c\src\spine\Event.c" />
|
||||
<ClCompile Include="..\..\..\spine-c\spine-c\src\spine\EventData.c" />
|
||||
<ClCompile Include="..\..\..\spine-c\spine-c\src\spine\extension.c" />
|
||||
@ -165,6 +166,7 @@ xcopy "$(ProjectDir)..\Resources" "$(OutDir)" /D /E /I /F /Y
|
||||
<ClCompile Include="..\..\..\spine-c\spine-c\src\spine\PathAttachment.c" />
|
||||
<ClCompile Include="..\..\..\spine-c\spine-c\src\spine\PathConstraint.c" />
|
||||
<ClCompile Include="..\..\..\spine-c\spine-c\src\spine\PathConstraintData.c" />
|
||||
<ClCompile Include="..\..\..\spine-c\spine-c\src\spine\PointAttachment.c" />
|
||||
<ClCompile Include="..\..\..\spine-c\spine-c\src\spine\RegionAttachment.c" />
|
||||
<ClCompile Include="..\..\..\spine-c\spine-c\src\spine\Skeleton.c" />
|
||||
<ClCompile Include="..\..\..\spine-c\spine-c\src\spine\SkeletonBinary.c" />
|
||||
@ -182,6 +184,7 @@ xcopy "$(ProjectDir)..\Resources" "$(OutDir)" /D /E /I /F /Y
|
||||
<ClCompile Include="..\..\src\spine\SkeletonAnimation.cpp" />
|
||||
<ClCompile Include="..\..\src\spine\SkeletonBatch.cpp" />
|
||||
<ClCompile Include="..\..\src\spine\SkeletonRenderer.cpp" />
|
||||
<ClCompile Include="..\..\src\spine\SkeletonTwoColorBatch.cpp" />
|
||||
<ClCompile Include="..\..\src\spine\spine-cocos2dx.cpp" />
|
||||
<ClCompile Include="..\Classes\AppDelegate.cpp" />
|
||||
<ClCompile Include="..\Classes\BatchingExample.cpp" />
|
||||
|
||||
@ -156,6 +156,15 @@
|
||||
<ClCompile Include="..\..\..\spine-c\spine-c\src\spine\VertexAttachment.c">
|
||||
<Filter>spine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\spine-c\spine-c\src\spine\Color.c">
|
||||
<Filter>spine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\spine-c\spine-c\src\spine\PointAttachment.c">
|
||||
<Filter>spine</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\src\spine\SkeletonTwoColorBatch.cpp">
|
||||
<Filter>spine-cocos2dx</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="main.h">
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user