Meshes, FFD and skinning for spine-starling.

This commit is contained in:
NathanSweet 2014-06-02 15:33:22 +02:00
parent fb28ee1b49
commit 6b9d514ca7
19 changed files with 1656 additions and 292 deletions

View File

@ -41,7 +41,7 @@ public class Skeleton {
public var g:Number = 1;
public var b:Number = 1;
public var a:Number = 1;
public var time:Number;
public var time:Number = 0;
public var flipX:Boolean;
public var flipY:Boolean;
public var x:Number = 0;

View File

@ -96,9 +96,9 @@ public dynamic class MeshAttachment extends Attachment {
if (slot.attachmentVertices.length == verticesCount) vertices = slot.attachmentVertices;
for (var i:int = 0, ii:int = 0; i < verticesCount; i += 2, ii += 2) {
var vx:Number = vertices[i];
var vy:Number = vertices[ii];
worldVertices[i] = vx * m00 + vy * m01 + x;
worldVertices[ii] = vx * m10 + vy * m11 + y;
var vy:Number = vertices[int(i + 1)];
worldVertices[ii] = vx * m00 + vy * m01 + x;
worldVertices[int(ii + 1)] = vx * m10 + vy * m11 + y;
}
}
}

View File

@ -1,14 +1,15 @@
package {
import flash.display.Bitmap;
import spine.Event;
import spine.SkeletonData;
import spine.SkeletonJson;
import spine.animation.AnimationStateData;
import spine.atlas.Atlas;
import spine.attachments.AtlasAttachmentLoader;
import spine.starling.StarlingTextureLoader;
import spine.starling.SkeletonAnimation;
import spine.starling.StarlingAtlasAttachmentLoader;
import spine.starling.StarlingTextureLoader;
import starling.core.Starling;
import starling.display.Sprite;
@ -16,7 +17,6 @@ import starling.events.Touch;
import starling.events.TouchEvent;
import starling.events.TouchPhase;
import starling.textures.Texture;
import starling.textures.TextureAtlas;
public class AtlasExample extends Sprite {
[Embed(source = "spineboy.atlas", mimeType = "application/octet-stream")]
@ -33,14 +33,14 @@ public class AtlasExample extends Sprite {
public function AtlasExample () {
var atlas:Atlas = new Atlas(new SpineboyAtlasFile(), new StarlingTextureLoader(new SpineboyAtlasTexture()));
var json:SkeletonJson = new SkeletonJson(new AtlasAttachmentLoader(atlas));
json.scale = 0.6;
var skeletonData:SkeletonData = json.readSkeletonData(new SpineboyJson());
var stateData:AnimationStateData = new AnimationStateData(skeletonData);
stateData.setMixByName("walk", "jump", 0.2);
stateData.setMixByName("jump", "walk", 0.4);
stateData.setMixByName("jump", "jump", 0.2);
stateData.defaultMix = 0.2;
stateData.setMixByName("jump", "run", 0.3);
skeleton = new SkeletonAnimation(skeletonData, stateData);
skeleton = new SkeletonAnimation(skeletonData, false, stateData);
skeleton.x = 320;
skeleton.y = 420;
@ -60,7 +60,7 @@ public class AtlasExample extends Sprite {
skeleton.state.setAnimationByName(0, "walk", true);
skeleton.state.addAnimationByName(0, "jump", false, 3);
skeleton.state.addAnimationByName(0, "walk", true, 0);
skeleton.state.addAnimationByName(0, "run", true, 0);
addChild(skeleton);
Starling.juggler.add(skeleton);
@ -72,7 +72,7 @@ public class AtlasExample extends Sprite {
var touch:Touch = event.getTouch(this);
if (touch && touch.phase == TouchPhase.BEGAN) {
skeleton.state.setAnimationByName(0, "jump", false);
skeleton.state.addAnimationByName(0, "walk", true, 0);
skeleton.state.addAnimationByName(0, "run", true, 0);
}
}
}

View File

@ -19,13 +19,13 @@ import starling.textures.Texture;
import starling.textures.TextureAtlas;
public class GoblinsExample extends Sprite {
[Embed(source = "goblins.atlas", mimeType = "application/octet-stream")]
[Embed(source = "goblins-ffd.atlas", mimeType = "application/octet-stream")]
static public const SpineboyAtlasFile:Class;
[Embed(source = "goblins.png")]
[Embed(source = "goblins-ffd.png")]
static public const SpineboyAtlasTexture:Class;
[Embed(source = "goblins.json", mimeType = "application/octet-stream")]
[Embed(source = "goblins-ffd.json", mimeType = "application/octet-stream")]
static public const SpineboyJson:Class;
private var skeleton:SkeletonAnimation;
@ -35,7 +35,7 @@ public class GoblinsExample extends Sprite {
var json:SkeletonJson = new SkeletonJson(new AtlasAttachmentLoader(atlas));
var skeletonData:SkeletonData = json.readSkeletonData(new SpineboyJson());
skeleton = new SkeletonAnimation(skeletonData);
skeleton = new SkeletonAnimation(skeletonData, true);
skeleton.x = 320;
skeleton.y = 420;
skeleton.skeleton.skinName = "goblin";

View File

@ -2,6 +2,7 @@
package {
import flash.display.Sprite;
import starling.core.Starling;
[SWF(width = "640", height = "480", frameRate = "60", backgroundColor = "#dddddd")]
@ -9,7 +10,13 @@ public class Main extends Sprite {
private var _starling:Starling;
public function Main () {
_starling = new Starling(AtlasExample, stage);
var example:Class;
//example = AtlasExample;
//example = StarlingAtlasExample;
example = GoblinsExample;
_starling = new Starling(example, stage);
_starling.showStats = true;
_starling.start();
}
}

View File

@ -22,7 +22,7 @@ public class StarlingAtlasExample extends Sprite {
[Embed(source = "spineboy-starling.png")]
static public const SpineboyAtlasTexture:Class;
[Embed(source = "spineboy.json", mimeType = "application/octet-stream")]
[Embed(source = "spineboy-starling.json", mimeType = "application/octet-stream")]
static public const SpineboyJson:Class;
private var skeleton:SkeletonAnimation;
@ -40,23 +40,23 @@ public class StarlingAtlasExample extends Sprite {
stateData.setMixByName("jump", "walk", 0.4);
stateData.setMixByName("jump", "jump", 0.2);
skeleton = new SkeletonAnimation(skeletonData, stateData);
skeleton = new SkeletonAnimation(skeletonData, false, stateData);
skeleton.x = 320;
skeleton.y = 420;
skeleton.state.onStart = function (trackIndex:int) : void {
skeleton.state.onStart.add(function (trackIndex:int) : void {
trace(trackIndex + " start: " + skeleton.state.getCurrent(trackIndex));
};
skeleton.state.onEnd = function (trackIndex:int) : void {
});
skeleton.state.onEnd.add(function (trackIndex:int) : void {
trace(trackIndex + " end: " + skeleton.state.getCurrent(trackIndex));
};
skeleton.state.onComplete = function (trackIndex:int, count:int) : void {
});
skeleton.state.onComplete.add(function (trackIndex:int, count:int) : void {
trace(trackIndex + " complete: " + skeleton.state.getCurrent(trackIndex) + ", " + count);
};
skeleton.state.onEvent = function (trackIndex:int, event:Event) : void {
});
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);
};
});
skeleton.state.setAnimationByName(0, "walk", true);
skeleton.state.addAnimationByName(0, "jump", false, 3);

View File

@ -4,288 +4,288 @@ format: RGBA8888
filter: Linear,Linear
repeat: none
dagger
rotate: false
xy: 2, 28
rotate: true
xy: 372, 100
size: 26, 108
orig: 26, 108
offset: 0, 0
index: -1
goblin/eyes-closed
rotate: false
xy: 137, 29
xy: 2, 7
size: 34, 12
orig: 34, 12
offset: 0, 0
index: -1
goblin/head
rotate: false
xy: 26, 357
xy: 107, 36
size: 103, 66
orig: 103, 66
offset: 0, 0
index: -1
goblin/left-arm
rotate: false
xy: 30, 28
xy: 901, 56
size: 37, 35
orig: 37, 35
offset: 0, 0
index: -1
goblin/left-foot
rotate: false
xy: 134, 260
xy: 929, 95
size: 65, 31
orig: 65, 31
offset: 0, 0
index: -1
goblin/left-hand
rotate: false
xy: 69, 25
xy: 452, 2
size: 36, 41
orig: 36, 41
offset: 0, 0
index: -1
goblin/left-lower-leg
rotate: false
xy: 134, 293
rotate: true
xy: 713, 93
size: 33, 70
orig: 33, 70
offset: 0, 0
index: -1
goblin/left-shoulder
rotate: false
xy: 137, 43
xy: 610, 44
size: 29, 44
orig: 29, 44
offset: 0, 0
index: -1
goblin/left-upper-leg
rotate: false
xy: 30, 65
rotate: true
xy: 638, 93
size: 33, 73
orig: 33, 73
offset: 0, 0
index: -1
goblin/neck
rotate: false
xy: 201, 387
xy: 490, 2
size: 36, 41
orig: 36, 41
offset: 0, 0
index: -1
goblin/pelvis
rotate: false
xy: 26, 140
xy: 482, 45
size: 62, 43
orig: 62, 43
offset: 0, 0
index: -1
goblin/right-arm
rotate: false
xy: 171, 84
rotate: true
xy: 690, 2
size: 23, 50
orig: 23, 50
offset: 0, 0
index: -1
goblin/right-foot
rotate: false
xy: 134, 225
xy: 771, 58
size: 63, 33
orig: 63, 33
offset: 0, 0
index: -1
goblin/right-hand
rotate: false
xy: 204, 258
xy: 940, 56
size: 36, 37
orig: 36, 37
offset: 0, 0
index: -1
goblin/right-lower-leg
rotate: false
xy: 201, 430
rotate: true
xy: 482, 90
size: 36, 76
orig: 36, 76
offset: 0, 0
index: -1
goblin/right-shoulder
rotate: false
xy: 130, 89
rotate: true
xy: 602, 3
size: 39, 45
orig: 39, 45
offset: 0, 0
index: -1
goblin/right-upper-leg
rotate: false
xy: 98, 214
rotate: true
xy: 641, 57
size: 34, 63
orig: 34, 63
offset: 0, 0
index: -1
goblin/torso
rotate: false
xy: 131, 410
rotate: true
xy: 212, 34
size: 68, 96
orig: 68, 96
offset: 0, 0
index: -1
goblin/undie-straps
rotate: false
xy: 2, 7
xy: 380, 5
size: 55, 19
orig: 55, 19
offset: 0, 0
index: -1
goblin/undies
rotate: false
xy: 199, 227
xy: 174, 5
size: 36, 29
orig: 36, 29
offset: 0, 0
index: -1
goblingirl/eyes-closed
rotate: false
xy: 59, 2
xy: 269, 11
size: 37, 21
orig: 37, 21
offset: 0, 0
index: -1
goblingirl/head
rotate: false
xy: 26, 425
xy: 2, 21
size: 103, 81
orig: 103, 81
offset: 0, 0
index: -1
goblingirl/left-arm
rotate: false
xy: 201, 190
rotate: true
xy: 978, 56
size: 37, 35
orig: 37, 35
offset: 0, 0
index: -1
goblingirl/left-foot
rotate: false
xy: 134, 192
xy: 107, 3
size: 65, 31
orig: 65, 31
offset: 0, 0
index: -1
goblingirl/left-hand
rotate: false
xy: 196, 109
xy: 565, 2
size: 35, 40
orig: 35, 40
offset: 0, 0
index: -1
goblingirl/left-lower-leg
rotate: false
xy: 169, 293
rotate: true
xy: 785, 93
size: 33, 70
orig: 33, 70
offset: 0, 0
index: -1
goblingirl/left-shoulder
rotate: false
xy: 107, 30
rotate: true
xy: 690, 27
size: 28, 46
orig: 28, 46
offset: 0, 0
index: -1
goblingirl/left-upper-leg
rotate: false
xy: 65, 68
rotate: true
xy: 857, 93
size: 33, 70
orig: 33, 70
offset: 0, 0
index: -1
goblingirl/neck
rotate: false
xy: 204, 297
xy: 528, 2
size: 35, 41
orig: 35, 41
offset: 0, 0
index: -1
goblingirl/pelvis
rotate: false
xy: 131, 365
xy: 546, 45
size: 62, 43
orig: 62, 43
offset: 0, 0
index: -1
goblingirl/right-arm
rotate: false
xy: 100, 97
xy: 452, 48
size: 28, 50
orig: 28, 50
offset: 0, 0
index: -1
goblingirl/right-foot
rotate: false
xy: 134, 157
xy: 836, 58
size: 63, 33
orig: 63, 33
offset: 0, 0
index: -1
goblingirl/right-hand
rotate: false
xy: 199, 151
rotate: true
xy: 771, 20
size: 36, 37
orig: 36, 37
offset: 0, 0
index: -1
goblingirl/right-lower-leg
rotate: false
xy: 96, 279
rotate: true
xy: 560, 90
size: 36, 76
orig: 36, 76
offset: 0, 0
index: -1
goblingirl/right-shoulder
rotate: false
xy: 204, 340
xy: 649, 10
size: 39, 45
orig: 39, 45
offset: 0, 0
index: -1
goblingirl/right-upper-leg
rotate: false
xy: 98, 149
rotate: true
xy: 706, 57
size: 34, 63
orig: 34, 63
offset: 0, 0
index: -1
goblingirl/torso
rotate: false
xy: 26, 259
xy: 310, 2
size: 68, 96
orig: 68, 96
offset: 0, 0
index: -1
goblingirl/undie-straps
rotate: false
xy: 134, 136
xy: 212, 13
size: 55, 19
orig: 55, 19
offset: 0, 0
index: -1
goblingirl/undies
rotate: false
xy: 196, 78
xy: 810, 27
size: 36, 29
orig: 36, 29
offset: 0, 0
index: -1
shield
rotate: false
xy: 26, 185
xy: 380, 26
size: 70, 72
orig: 70, 72
offset: 0, 0
index: -1
spear
rotate: false
xy: 2, 138
rotate: true
xy: 2, 104
size: 22, 368
orig: 22, 368
offset: 0, 0

View File

@ -759,6 +759,11 @@
},
"ffd": {
"default": {
"left hand item": {
"spear": [
{ "time": 0 }
]
},
"right hand item": {
"dagger": [
{

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 217 KiB

File diff suppressed because it is too large Load Diff

View File

@ -54,7 +54,8 @@
{ "name": "goggles", "bone": "head", "attachment": "goggles" },
{ "name": "front_bracer", "bone": "front_bracer", "attachment": "front_bracer" },
{ "name": "front_fist", "bone": "front_fist", "attachment": "front_fist_closed" },
{ "name": "muzzle", "bone": "gunTip", "additive": true }
{ "name": "muzzle", "bone": "gunTip", "additive": true },
{ "name": "head-bb", "bone": "head" }
],
"skins": {
"default": {
@ -92,6 +93,12 @@
"head": {
"head": { "x": 128.95, "y": 0.29, "rotation": -70.63, "width": 271, "height": 298 }
},
"head-bb": {
"head": {
"type": "boundingbox",
"vertices": [ -19.143097, -70.30209, 40.80313, -118.074234, 257.77155, -115.61827, 285.16193, 57.18005, 120.77191, 164.95125, -5.067627, 76.94907 ]
}
},
"mouth": {
"mouth_grind": { "x": 23.68, "y": -32.23, "rotation": -70.63, "width": 93, "height": 59 },
"mouth_oooo": { "x": 23.68, "y": -32.23, "rotation": -70.63, "width": 93, "height": 59 },

Binary file not shown.

Before

Width:  |  Height:  |  Size: 239 KiB

After

Width:  |  Height:  |  Size: 253 KiB

View File

@ -10,7 +10,7 @@
</excludedEntries>
</libraryPathEntry>
<libraryPathEntry kind="3" linkType="1" path="/spine-as3/bin/spine-as3.swc" useDefaultLinkType="false"/>
<libraryPathEntry kind="3" linkType="1" path="libs/starling-1.5rc.swc" useDefaultLinkType="false"/>
<libraryPathEntry kind="3" linkType="1" path="libs/starling-1.5.1.swc" useDefaultLinkType="false"/>
</libraryPath>
<sourceAttachmentPath/>
</compiler>

Binary file not shown.

View File

@ -0,0 +1,272 @@
/******************************************************************************
* Spine Runtimes Software License
* Version 2.1
*
* Copyright (c) 2013, Esoteric Software
* All rights reserved.
*
* You are granted a perpetual, non-exclusive, non-sublicensable and
* non-transferable license to install, execute and perform the Spine Runtimes
* Software (the "Software") solely for internal use. Without the written
* permission of Esoteric Software (typically granted by licensing Spine), you
* may not (a) modify, translate, adapt or otherwise create derivative works,
* improvements of the Software or develop new applications using the Software
* 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 SOFTARE BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
* OR BUSINESS INTERRUPTION) 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.starling {
import flash.display3D.Context3D;
import flash.display3D.Context3DProgramType;
import flash.display3D.Context3DTextureFormat;
import flash.display3D.Context3DVertexBufferFormat;
import flash.display3D.IndexBuffer3D;
import flash.display3D.Program3D;
import flash.display3D.VertexBuffer3D;
import flash.events.Event;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.utils.Dictionary;
import starling.core.RenderSupport;
import starling.core.Starling;
import starling.display.BlendMode;
import starling.textures.Texture;
import starling.textures.TextureSmoothing;
import starling.utils.MatrixUtil;
import starling.utils.VertexData;
internal class PolygonBatch {
static private var _tempPoint:Point = new Point();
static private var _renderAlpha:Vector.<Number> = new <Number>[1.0, 1.0, 1.0, 1.0];
static private var _programNameCache:Dictionary = new Dictionary();
private var _capacity:int;
public var maxCapacity:int = 2000;
public var smoothing:String = "bilinear";
private var _texture:Texture;
private var _support:RenderSupport;
private var _programBits:uint;
private var _blendMode:String;
private var _additive:Boolean;
private var _verticesCount:int;
private var _vertices:Vector.<Number> = new <Number>[];
private var _verticesBuffer:VertexBuffer3D;
private var _trianglesCount:int;
private var _triangles:Vector.<uint> = new <uint>[];
private var _trianglesBuffer:IndexBuffer3D;
public function PolygonBatch () {
resize(32);
Starling.current.stage3D.addEventListener(Event.CONTEXT3D_CREATE, onContextCreated, false, 0, true);
}
public function dispose () : void {
Starling.current.stage3D.removeEventListener(Event.CONTEXT3D_CREATE, onContextCreated);
if (_verticesBuffer) _verticesBuffer.dispose();
if (_trianglesBuffer) _trianglesBuffer.dispose();
}
public function begin (support:RenderSupport, alpha:Number, blendMode:String) : void {
_support = support;
_renderAlpha[3] = alpha;
_programBits = 0xffffffff;
support.finishQuadBatch();
support.blendMode = blendMode;
support.applyBlendMode(true);
_blendMode = support.blendMode;
_additive = false;
var context:Context3D = Starling.context;
context.setProgramConstantsFromVector(Context3DProgramType.VERTEX, 0, _renderAlpha, 1);
context.setProgramConstantsFromMatrix(Context3DProgramType.VERTEX, 1, support.mvpMatrix3D, true);
var verticesBuffer:VertexBuffer3D = _verticesBuffer;
if (verticesBuffer) {
context.setVertexBufferAt(0, verticesBuffer, VertexData.POSITION_OFFSET, Context3DVertexBufferFormat.FLOAT_2);
context.setVertexBufferAt(1, verticesBuffer, VertexData.COLOR_OFFSET, Context3DVertexBufferFormat.FLOAT_4);
context.setVertexBufferAt(2, verticesBuffer, VertexData.TEXCOORD_OFFSET, Context3DVertexBufferFormat.FLOAT_2);
}
}
public function end () : void {
flush();
var context:Context3D = Starling.context;
context.setTextureAt(0, null);
context.setVertexBufferAt(2, null);
context.setVertexBufferAt(1, null);
context.setVertexBufferAt(0, null);
}
public function add (texture:Texture, vertices:Vector.<Number>, vl:int, uvs:Vector.<Number>, triangles:Vector.<uint>,
r:Number, g:Number, b:Number, a:Number, additive:Boolean, matrix:Matrix) : void {
if (additive != _additive) {
_additive = additive;
flush();
_support.blendMode = additive ? BlendMode.ADD : _blendMode;
_support.applyBlendMode(true);
}
if (texture != _texture) {
flush();
_texture = texture;
}
var tl:int = triangles.length;
var vc:int = _verticesCount, tc:int = _trianglesCount;
var firstVertex:int = vc >> 3;
if (firstVertex + (vl >> 1) > _capacity) resize(vl >> 1);
if (tc + tl > _triangles.length) resize(tl / 3);
var i:int, t:Vector.<uint> = _triangles;
for (i = 0; i < tl; i += 3, tc += 3) {
t[tc] = firstVertex + triangles[i];
t[int(tc + 1)] = firstVertex + triangles[int(i + 1)];
t[int(tc + 2)] = firstVertex + triangles[int(i + 2)];
}
_trianglesCount = tc;
var v:Vector.<Number> = _vertices;
if (matrix) {
var point:Point = _tempPoint;
for (i = 0; i < vl; i += 2, vc += 8) {
MatrixUtil.transformCoords(matrix, vertices[i], vertices[int(i + 1)], point);
v[vc] = point.x;
v[int(vc + 1)] = point.y;
v[int(vc + 2)] = r;
v[int(vc + 3)] = g;
v[int(vc + 4)] = b;
v[int(vc + 5)] = a;
v[int(vc + 6)] = uvs[i];
v[int(vc + 7)] = uvs[int(i + 1)];
}
} else {
for (i = 0; i < vl; i += 2, vc += 8) {
v[vc] = vertices[i];
v[int(vc + 1)] = vertices[int(i + 1)];
v[int(vc + 2)] = r;
v[int(vc + 3)] = g;
v[int(vc + 4)] = b;
v[int(vc + 5)] = a;
v[int(vc + 6)] = uvs[i];
v[int(vc + 7)] = uvs[int(i + 1)];
}
}
_verticesCount = vc;
}
private function resize (additional:int) : void {
var newCapacity:int = (_verticesCount >> 3) + additional;
if (newCapacity > maxCapacity) {
flush();
newCapacity = additional;
if (newCapacity < _capacity) return;
if (newCapacity > maxCapacity) throw new ArgumentError("Too many vertices: " + newCapacity + " > " + maxCapacity);
}
_capacity = newCapacity;
_vertices.length = newCapacity << 3;
_triangles.length = newCapacity * 3;
_verticesBuffer = null;
_trianglesBuffer = null;
}
public function flush () : void {
if (!_verticesCount) return;
var context:Context3D = Starling.context;
if (!_verticesBuffer) {
_verticesBuffer = context.createVertexBuffer(_capacity, 8);
var count:int = _verticesCount >> 3;
_verticesBuffer.uploadFromVector(_vertices, 0, count);
var verticesTemp:Vector.<Number> = new <Number>[]; // Buffer must be filled completely once.
verticesTemp.length = (_capacity << 3) - _verticesCount;
_verticesBuffer.uploadFromVector(verticesTemp, count, _capacity - count);
verticesTemp = null;
_trianglesBuffer = context.createIndexBuffer(_capacity * 3);
_trianglesBuffer.uploadFromVector(_triangles, 0, _trianglesCount);
var trianglesTemp:Vector.<uint> = new <uint>[]; // Buffer must be filled completely once.
trianglesTemp.length = _capacity * 3 - _trianglesCount;
_trianglesBuffer.uploadFromVector(trianglesTemp, _trianglesCount, trianglesTemp.length);
trianglesTemp = null;
context.setVertexBufferAt(0, _verticesBuffer, VertexData.POSITION_OFFSET, Context3DVertexBufferFormat.FLOAT_2);
context.setVertexBufferAt(1, _verticesBuffer, VertexData.COLOR_OFFSET, Context3DVertexBufferFormat.FLOAT_4);
context.setVertexBufferAt(2, _verticesBuffer, VertexData.TEXCOORD_OFFSET, Context3DVertexBufferFormat.FLOAT_2);
} else {
_verticesBuffer.uploadFromVector(_vertices, 0, _verticesCount >> 3);
_trianglesBuffer.uploadFromVector(_triangles, 0, _trianglesCount);
}
setProgram(context);
context.setTextureAt(0, _texture.base);
context.drawTriangles(_trianglesBuffer, 0, _trianglesCount / 3);
_verticesCount = 0;
_trianglesCount = 0;
_support.raiseDrawCount();
}
private function onContextCreated (event:Event) : void {
_verticesBuffer = null;
_trianglesBuffer = null;
}
private function setProgram (context:Context3D) : void {
var bits:uint = 0;
var texture:Texture = _texture;
if (texture.mipMapping) bits |= 1 << 1;
if (texture.repeat) bits |= 1 << 2;
if (smoothing != TextureSmoothing.BILINEAR) bits |= 1 << (smoothing == TextureSmoothing.TRILINEAR ? 3 : 4);
if (texture.format != Context3DTextureFormat.BGRA) bits |= 1 << (texture.format == "compressedAlpha" ? 5 : 6);
if (bits == _programBits) return;
_programBits = bits;
var name:String = _programNameCache[bits];
if (name == null) {
name = "PB_i." + bits.toString(16);
_programNameCache[bits] = name;
}
var program:Program3D = Starling.current.getProgram(name);
if (!program) {
// va0 -> position
// va1 -> color
// va2 -> texCoords
// vc0 -> alpha
// vc1 -> mvpMatrix
// fs0 -> texture
var vertexShader:String =
"m44 op, va0, vc1 \n" + // 4x4 matrix transform to output clipspace
"mul v0, va1, vc0 \n" + // multiply alpha (vc0) with color (va1)
"mov v1, va2 \n"; // pass texture coordinates to fragment program
var flags:String = RenderSupport.getTextureLookupFlags(texture.format, texture.mipMapping, texture.repeat, smoothing);
var fragmentShader:String =
"tex ft1, v1, fs0 " + flags + " \n" + // sample texture 0
"mul oc, ft1, v0 \n"; // multiply color with texel color
Starling.current.registerProgramFromSource(name, vertexShader, fragmentShader);
}
context.setProgram(program);
}
}
}

View File

@ -29,23 +29,27 @@
*****************************************************************************/
package spine.starling {
import spine.SkeletonData;
import spine.animation.AnimationState;
import spine.animation.AnimationStateData;
import spine.SkeletonData;
public class SkeletonAnimation extends SkeletonSprite {
import starling.animation.IAnimatable;
public class SkeletonAnimation extends SkeletonSprite implements IAnimatable {
public var state:AnimationState;
public var timeScale:Number = 1;
public function SkeletonAnimation (skeletonData:SkeletonData, stateData:AnimationStateData = null) {
super(skeletonData);
public function SkeletonAnimation (skeletonData:SkeletonData, renderMeshes:Boolean = false, stateData:AnimationStateData = null) {
super(skeletonData, renderMeshes);
state = new AnimationState(stateData ? stateData : new AnimationStateData(skeletonData));
}
override public function advanceTime (time:Number) : void {
public function advanceTime (time:Number) : void {
time *= timeScale;
skeleton.update(time);
state.update(time);
state.apply(skeleton);
skeleton.updateWorldTransform();
super.advanceTime(time);
}
}

View File

@ -29,6 +29,8 @@
*****************************************************************************/
package spine.starling {
import flash.display3D.Context3D;
import flash.display3D.textures.Texture;
import flash.geom.Matrix;
import flash.geom.Point;
import flash.geom.Rectangle;
@ -37,79 +39,172 @@ import spine.Bone;
import spine.Skeleton;
import spine.SkeletonData;
import spine.Slot;
import spine.atlas.AtlasPage;
import spine.atlas.AtlasRegion;
import spine.attachments.Attachment;
import spine.attachments.MeshAttachment;
import spine.attachments.RegionAttachment;
import spine.attachments.SkinnedMeshAttachment;
import starling.animation.IAnimatable;
import starling.core.RenderSupport;
import starling.core.Starling;
import starling.display.BlendMode;
import starling.display.DisplayObject;
import starling.utils.Color;
import starling.utils.MatrixUtil;
import starling.utils.VertexData;
public class SkeletonSprite extends DisplayObject implements IAnimatable {
static private var tempPoint:Point = new Point();
static private var tempMatrix:Matrix = new Matrix();
static private var tempVertices:Vector.<Number> = new Vector.<Number>(8);
public class SkeletonSprite extends DisplayObject {
static private var _tempPoint:Point = new Point();
static private var _tempMatrix:Matrix = new Matrix();
static private var _tempVertices:Vector.<Number> = new Vector.<Number>(8);
static private var _quadTriangles:Vector.<uint> = new <uint>[0, 1, 2, 2, 3, 0];
private var _skeleton:Skeleton;
private var _renderMeshes:Boolean;
private var _polygonBatch:PolygonBatch;
public var batchable:Boolean = true;
private var _batched:Boolean;
public function SkeletonSprite (skeletonData:SkeletonData) {
public function SkeletonSprite (skeletonData:SkeletonData, renderMeshes:Boolean = false) {
Bone.yDown = true;
_renderMeshes = renderMeshes;
if (renderMeshes) _polygonBatch = new PolygonBatch();
_skeleton = new Skeleton(skeletonData);
_skeleton.updateWorldTransform();
}
public function advanceTime (delta:Number) : void {
_skeleton.update(delta);
}
override public function render (support:RenderSupport, alpha:Number) : void {
alpha *= this.alpha * skeleton.a;
if (_renderMeshes)
renderMeshes(support, alpha);
else
renderRegions(support, alpha);
}
private function renderMeshes (support:RenderSupport, alpha:Number) : void {
if (!batchable) {
_polygonBatch.begin(support, alpha, blendMode);
addToBatch(_polygonBatch, support, alpha, null);
_polygonBatch.end();
} else if (!_batched) {
support.popMatrix();
_polygonBatch.begin(support, alpha, blendMode);
addToBatch(_polygonBatch, support, alpha, transformationMatrix);
for(var i:int = parent.getChildIndex(this) + 1, n:int = parent.numChildren; i < n; ++i) {
var skeletonSprite:SkeletonSprite = parent.getChildAt(i) as SkeletonSprite;
if (!skeletonSprite || !skeletonSprite.batchable || skeletonSprite.blendMode != blendMode) break;
skeletonSprite._batched = true;
skeletonSprite.addToBatch(_polygonBatch, support, alpha, skeletonSprite.transformationMatrix);
}
_polygonBatch.end();
support.pushMatrix();
support.transformMatrix(this);
} else
_batched = false;
}
private function addToBatch (polygonBatch:PolygonBatch, support:RenderSupport, skeletonA:Number, matrix:Matrix) : void {
var skeletonR:Number = skeleton.r;
var skeletonG:Number = skeleton.g;
var skeletonB:Number = skeleton.b;
var x:Number = skeleton.x;
var y:Number = skeleton.y;
var worldVertices:Vector.<Number> = _tempVertices;
var drawOrder:Vector.<Slot> = skeleton.drawOrder;
for (var i:int = 0, n:int = drawOrder.length; i < n; ++i) {
var slot:Slot = drawOrder[i];
var attachment:Attachment = slot.attachment;
if (!attachment) continue;
var image:SkeletonImage, verticesLength:int, uvs:Vector.<Number>, triangles:Vector.<uint>;
var r:Number, g:Number, b:Number, a:Number;
if (attachment is RegionAttachment) {
var region:RegionAttachment = RegionAttachment(slot.attachment);
verticesLength = 8;
region.computeWorldVertices(x, y, slot.bone, worldVertices);
uvs = region.uvs;
triangles = _quadTriangles;
r = region.r;
g = region.g;
b = region.b;
a = region.a;
image = region.rendererObject as SkeletonImage;
if (image == null) region.rendererObject = image = SkeletonImage(AtlasRegion(region.rendererObject).rendererObject);
} else if (attachment is MeshAttachment) {
var mesh:MeshAttachment = MeshAttachment(attachment);
verticesLength = mesh.vertices.length;
if (worldVertices.length < verticesLength) worldVertices.length = verticesLength;
mesh.computeWorldVertices(x, y, slot, worldVertices);
uvs = mesh.uvs;
triangles = mesh.triangles;
r = mesh.r;
g = mesh.g;
b = mesh.b;
a = mesh.a;
image = mesh.rendererObject as SkeletonImage;
if (image == null) mesh.rendererObject = image = SkeletonImage(AtlasRegion(mesh.rendererObject).rendererObject);
} else if (attachment is SkinnedMeshAttachment) {
var skinnedMesh:SkinnedMeshAttachment = SkinnedMeshAttachment(attachment);
verticesLength = skinnedMesh.uvs.length;
if (worldVertices.length < verticesLength) worldVertices.length = verticesLength;
skinnedMesh.computeWorldVertices(x, y, slot, worldVertices);
uvs = skinnedMesh.uvs;
triangles = skinnedMesh.triangles;
r = skinnedMesh.r;
g = skinnedMesh.g;
b = skinnedMesh.b;
a = skinnedMesh.a;
image = skinnedMesh.rendererObject as SkeletonImage;
if (image == null) skinnedMesh.rendererObject = image = SkeletonImage(AtlasRegion(skinnedMesh.rendererObject).rendererObject);
}
if (image) {
a *= skeletonA * slot.a;
r *= skeletonR * slot.r * a;
g *= skeletonG * slot.g * a;
b *= skeletonB * slot.b * a;
polygonBatch.add(image.texture, worldVertices, verticesLength, uvs, triangles, r, g, b, a, slot.data.additiveBlending, matrix);
}
}
}
private function renderRegions (support:RenderSupport, alpha:Number) : void {
var r:Number = skeleton.r * 255;
var g:Number = skeleton.g * 255;
var b:Number = skeleton.b * 255;
var x:Number = skeleton.x;
var y:Number = skeleton.y;
var drawOrder:Vector.<Slot> = skeleton.drawOrder;
for (var i:int = 0, n:int = drawOrder.length; i < n; i++) {
var worldVertices:Vector.<Number> = _tempVertices;
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 != null) {
var vertices:Vector.<Number> = tempVertices;
regionAttachment.computeWorldVertices(x, y, slot.bone, vertices);
var a:Number = slot.a * regionAttachment.a;
var region:RegionAttachment = slot.attachment as RegionAttachment;
if (region != null) {
region.computeWorldVertices(x, y, slot.bone, worldVertices);
var a:Number = slot.a * region.a;
var rgb:uint = Color.rgb(
r * slot.r * regionAttachment.r,
g * slot.g * regionAttachment.g,
b * slot.b * regionAttachment.b);
r * slot.r * region.r,
g * slot.g * region.g,
b * slot.b * region.b);
var image:SkeletonImage;
image = regionAttachment.rendererObject as SkeletonImage;
if (image == null) {
image = SkeletonImage(AtlasRegion(regionAttachment.rendererObject).rendererObject);
regionAttachment.rendererObject = image;
}
var image:SkeletonImage = region.rendererObject as SkeletonImage;
if (image == null) region.rendererObject = image = SkeletonImage(AtlasRegion(region.rendererObject).rendererObject);
var vertexData:VertexData = image.vertexData;
vertexData.setPosition(0, vertices[2], vertices[3]);
vertexData.setPosition(0, worldVertices[2], worldVertices[3]);
vertexData.setColorAndAlpha(0, rgb, a);
vertexData.setPosition(1, vertices[4], vertices[5]);
vertexData.setPosition(1, worldVertices[4], worldVertices[5]);
vertexData.setColorAndAlpha(1, rgb, a);
vertexData.setPosition(2, vertices[0], vertices[1]);
vertexData.setPosition(2, worldVertices[0], worldVertices[1]);
vertexData.setColorAndAlpha(2, rgb, a);
vertexData.setPosition(3, vertices[6], vertices[7]);
vertexData.setPosition(3, worldVertices[6], worldVertices[7]);
vertexData.setColorAndAlpha(3, rgb, a);
image.updateVertices();
support.blendMode = slot.data.additiveBlending ? BlendMode.ADD : BlendMode.NORMAL;
support.blendMode = slot.data.additiveBlending ? BlendMode.ADD : blendMode;
support.batchQuad(image, alpha, image.texture);
}
}
@ -122,63 +217,35 @@ public class SkeletonSprite extends DisplayObject implements IAnimatable {
var minX:Number = Number.MAX_VALUE, minY:Number = Number.MAX_VALUE;
var maxX:Number = Number.MIN_VALUE, maxY:Number = Number.MIN_VALUE;
var slots:Vector.<Slot> = skeleton.slots;
var value:Number;
for (var i:int = 0, n:int = slots.length; i < n; i++) {
var worldVertices:Vector.<Number> = _tempVertices;
for (var i:int = 0, n:int = slots.length; i < n; ++i) {
var slot:Slot = slots[i];
var regionAttachment:RegionAttachment = slot.attachment as RegionAttachment;
if (!regionAttachment)
var attachment:Attachment = slot.attachment;
if (!attachment) continue;
var verticesLength:int;
if (attachment is RegionAttachment) {
var region:RegionAttachment = RegionAttachment(slot.attachment);
verticesLength = 8;
region.computeWorldVertices(0, 0, slot.bone, worldVertices);
} else if (attachment is MeshAttachment) {
var mesh:MeshAttachment = MeshAttachment(attachment);
verticesLength = mesh.vertices.length;
if (worldVertices.length < verticesLength) worldVertices.length = verticesLength;
mesh.computeWorldVertices(0, 0, slot, worldVertices);
} else if (attachment is SkinnedMeshAttachment) {
var skinnedMesh:SkinnedMeshAttachment = SkinnedMeshAttachment(attachment);
verticesLength = skinnedMesh.uvs.length;
if (worldVertices.length < verticesLength) worldVertices.length = verticesLength;
skinnedMesh.computeWorldVertices(0, 0, slot, worldVertices);
} else
continue;
var vertices:Vector.<Number> = tempVertices;
regionAttachment.computeWorldVertices(skeleton.x, skeleton.y, slot.bone, vertices);
value = vertices[0];
if (value < minX)
minX = value;
if (value > maxX)
maxX = value;
value = vertices[1];
if (value < minY)
minY = value;
if (value > maxY)
maxY = value;
value = vertices[2];
if (value < minX)
minX = value;
if (value > maxX)
maxX = value;
value = vertices[3];
if (value < minY)
minY = value;
if (value > maxY)
maxY = value;
value = vertices[4];
if (value < minX)
minX = value;
if (value > maxX)
maxX = value;
value = vertices[5];
if (value < minY)
minY = value;
if (value > maxY)
maxY = value;
value = vertices[6];
if (value < minX)
minX = value;
if (value > maxX)
maxX = value;
value = vertices[7];
if (value < minY)
minY = value;
if (value > maxY)
maxY = value;
for (var ii:int = 0; ii < verticesLength; ii += 2) {
var x:Number = worldVertices[ii], y:Number = worldVertices[ii + 1];
minX = Math.min(minX, x);
minY = Math.min(minY, y);
maxX = Math.max(maxX, x);
maxY = Math.max(maxY, y);
}
}
minX *= scaleX;
@ -211,9 +278,9 @@ public class SkeletonSprite extends DisplayObject implements IAnimatable {
else if (targetSpace == parent)
resultRect.setTo(x, y, 0, 0);
else {
getTransformationMatrix(targetSpace, tempMatrix);
MatrixUtil.transformCoords(tempMatrix, 0, 0, tempPoint);
resultRect.setTo(tempPoint.x, tempPoint.y, 0, 0);
getTransformationMatrix(targetSpace, _tempMatrix);
MatrixUtil.transformCoords(_tempMatrix, 0, 0, _tempPoint);
resultRect.setTo(_tempPoint.x, _tempPoint.y, 0, 0);
}
return resultRect;
}