[haxe] More porting from 4.0 -> 4.1, WIP

This commit is contained in:
Mario Zechner 2023-09-11 13:53:32 +02:00
parent 51b108f2e1
commit 30311f2cd8
28 changed files with 431 additions and 497 deletions

View File

@ -10,7 +10,7 @@ import openfl.geom.Rectangle;
import openfl.utils.ByteArray;
import openfl.utils.Endian;
import spine.animation.AnimationStateData;
import spine.atlas.Atlas;
import spine.atlas.TextureAtlas;
import spine.attachments.AtlasAttachmentLoader;
import spine.SkeletonBinary;
import spine.SkeletonData;
@ -22,7 +22,7 @@ import starling.events.Event;
import starling.textures.Texture;
class Main extends Sprite {
private static inline var loadBinary:Bool = true;
private static inline var loadBinary:Bool = false;
private var starlingSingleton:Starling;
@ -44,13 +44,13 @@ class Main extends Sprite {
private function loadSpineAnimation():Void {
var textureAtlasBitmapData:BitmapData = Assets.getBitmapData("assets/coin.png");
var stAtlas:String = Assets.getText("assets/coin.atlas");
var binaryData:Bytes = Assets.getBytes("assets/coin-pro.skel");
var jsonData:String = Assets.getText("assets/coin-pro.json");
var stAtlas = Assets.getText("assets/coin.atlas");
var binaryData = Assets.getBytes("assets/coin-pro.skel");
var jsonData = Assets.getText("assets/coin-pro.json");
var textureAtlas:Texture = Texture.fromBitmapData(textureAtlasBitmapData);
var textureloader:StarlingTextureLoader = new StarlingTextureLoader(textureAtlas);
var atlas:Atlas = new Atlas(stAtlas, textureloader);
var textureAtlas = Texture.fromBitmapData(textureAtlasBitmapData);
var textureloader = new StarlingTextureLoader(textureAtlas);
var atlas = new TextureAtlas(stAtlas, textureloader);
var skeletondata:SkeletonData;
if (loadBinary) {

View File

@ -0,0 +1,9 @@
package spine;
interface HasTextureRegion {
public var path:String;
public var region:TextureRegion;
public var color:Color;
public var sequence:Sequence;
public function updateRegion():Void;
}

View File

@ -72,7 +72,7 @@ class IkConstraint implements Updatable {
tx = targetX - bone.worldX;
ty = targetY - bone.worldY;
case TransformMode.noRotationOrReflection:
var s:Float = Math.abs(pa * pd - pb * pc) / (pa * pa + pc * pc);
var s = Math.abs(pa * pd - pb * pc) / Math.max(0.0001, pa * pa + pc * pc);
var sa:Float = pa / bone.skeleton.scaleX;
var sc:Float = pc / bone.skeleton.scaleY;
pb = -sc * s * bone.skeleton.scaleX;
@ -85,8 +85,13 @@ class IkConstraint implements Updatable {
default:
var x:Float = targetX - p.worldX, y:Float = targetY - p.worldY;
var d:Float = pa * pd - pb * pc;
tx = (x * pd - y * pb) / d - bone.ax;
ty = (y * pa - x * pc) / d - bone.ay;
if (Math.abs(d) <= 0.0001) {
tx = 0;
ty = 0;
} else {
tx = (x * pd - y * pb) / d - bone.ax;
ty = (y * pa - x * pc) / d - bone.ay;
}
}
rotationIK += Math.atan2(ty, tx) * MathUtils.radDeg;
@ -172,9 +177,8 @@ class IkConstraint implements Updatable {
b = pp.b;
c = pp.c;
d = pp.d;
var id:Float = 1 / (a * d - b * c),
x:Float = cwx - pp.worldX,
y:Float = cwy - pp.worldY;
var id = a * d - b * c, x = cwx - pp.worldX, y = cwy - pp.worldY;
id = Math.abs(id) <= 0.0001 ? 0 : 1 / id;
var dx:Float = (x * d - y * b) * id - px,
dy:Float = (y * a - x * c) * id - py;
var l1:Float = Math.sqrt(dx * dx + dy * dy);

View File

@ -1,11 +0,0 @@
package spine;
class Interpolation {
private function applyInternal(a:Float):Float {
return a;
}
public function apply(start:Float, end:Float, a:Float):Float {
return start + (end - start) * applyInternal(a);
}
}

View File

@ -6,9 +6,9 @@ class PathConstraintData extends ConstraintData {
private 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 positionMode:PositionMode = PositionMode.fixed;
public var spacingMode:SpacingMode = SpacingMode.fixed;
public var rotateMode:RotateMode = RotateMode.chain;
public var offsetRotation:Float = 0;
public var position:Float = 0;
public var spacing:Float = 0;

View File

@ -0,0 +1,54 @@
package spine;
import openfl.Vector;
class Sequence {
private static var _nextID = 0;
public var id = _nextID++;
public var regions:Vector<TextureRegion>;
public var start = 0;
public var digits = 0;
/** The index of the region to show for the setup pose. */
public var setupIndex = 0;
public function new(count:Int) {
this.regions = new Vector<TextureRegion>(count);
}
public function copy():Sequence {
var copy = new Sequence(this.regions.length);
for (i in 0...this.regions.length) {
copy.regions[i] = this.regions[i];
}
copy.start = this.start;
copy.digits = this.digits;
copy.setupIndex = this.setupIndex;
return copy;
}
public function apply(slot:Slot, attachment:HasTextureRegion) {
var index:Int = slot.sequenceIndex;
if (index == -1)
index = this.setupIndex;
if (index >= this.regions.length)
index = this.regions.length - 1;
var region = this.regions[index];
if (attachment.region != region) {
attachment.region = region;
attachment.updateRegion();
}
}
public function getPath(basePath:String, index:Int):String {
var result = basePath;
var frame = Std.string(this.start + index);
for (i in 0...(this.digits - frame.length)) {
result += "0";
}
result += frame;
return result;
}
}

View File

@ -0,0 +1,27 @@
package spine;
class SequenceMode {
public static var hold(default, never):RotateMode = new SequenceMode("hold");
public static var once(default, never):RotateMode = new SequenceMode("once");
public static var loop(default, never):RotateMode = new SequenceMode("loop");
public static var pingpong(default, never):RotateMode = new SequenceMode("pingpong");
public static var onceReverse(default, never):RotateMode = new SequenceMode("onceReverse");
public static var loopReverse(default, never):RotateMode = new SequenceMode("loopReverse");
public static var pingpongReverse(default, never):RotateMode = new SequenceMode("pingpongReverse");
public static var values(default, never):Vector<SequenceMode> = Vector.ofArray([tangent, chain, chainScale]);
public var name(default, null):String;
public function new(name:String) {
this.name = name;
}
public static function fromName(name:String):SequenceMode {
for (value in values) {
if (value.name == name)
return value;
}
return null;
}
}

View File

@ -22,7 +22,6 @@ class Skeleton {
private var _skin:Skin;
public var color:Color = new Color(1, 1, 1, 1);
public var time:Float = 0;
public var scaleX:Float = 1;
public var scaleY:Float = 1;
public var x:Float = 0;
@ -558,10 +557,6 @@ class Skeleton {
return null;
}
public function update(delta:Float):Void {
time += delta;
}
public function toString():String {
return _data.name != null ? _data.name : "Skeleton?";
}
@ -583,7 +578,7 @@ class Skeleton {
verticesLength = 8;
temp.length = verticesLength;
vertices = temp;
cast(attachment, RegionAttachment).computeWorldVertices(slot.bone, vertices, 0, 2);
cast(attachment, RegionAttachment).computeWorldVertices(slot, vertices, 0, 2);
} else if (Std.isOfType(attachment, MeshAttachment)) {
var mesh:MeshAttachment = cast(attachment, MeshAttachment);
verticesLength = mesh.worldVerticesLength;

View File

@ -119,7 +119,7 @@ class Skin {
public function removeAttachment(slotIndex:Int, name:String):Void {
var dictionary:Dictionary<String, Attachment> = _attachments[slotIndex];
if (dictionary != null)
dictionary[name] = null;
dictionary.remove(name);
}
public function getAttachments():Vector<SkinEntry> {

View File

@ -13,7 +13,8 @@ class Slot {
public var darkColor:Color;
private var _attachment:Attachment;
private var _attachmentTime:Float = 0;
public var sequenceIndex = -1;
public var attachmentState:Int = 0;
public var deform:Vector<Float> = new Vector<Float>();
@ -63,26 +64,14 @@ class Slot {
return attachmentNew;
if (!Std.isOfType(attachmentNew, VertexAttachment)
|| !Std.isOfType(attachment, VertexAttachment)
|| cast(attachmentNew, VertexAttachment).deformAttachment != cast(attachment, VertexAttachment).deformAttachment) {
|| cast(attachmentNew, VertexAttachment).timelineAttachment != cast(attachment, VertexAttachment).timelineAttachment) {
deform = new Vector<Float>();
}
_attachment = attachmentNew;
_attachmentTime = skeleton.time;
sequenceIndex = -1;
return attachmentNew;
}
public var attachmentTime(get, set):Float;
private function set_attachmentTime(time:Float):Float {
_attachmentTime = skeleton.time - time;
return _attachmentTime;
}
/** Returns the time since the attachment was set. */
private function get_attachmentTime():Float {
return skeleton.time - _attachmentTime;
}
public function setToSetupPose():Void {
color.setFromColor(data.color);
if (darkColor != null)

View File

@ -10,7 +10,7 @@ class SlotData {
public var color:Color = new Color(1, 1, 1, 1);
public var darkColor:Color = null;
public var attachmentName:String;
public var blendMode:BlendMode;
public var blendMode:BlendMode = BlendMode.normal;
public function new(index:Int, name:String, boneData:BoneData) {
if (index < 0)

View File

@ -0,0 +1,18 @@
package spine;
class TextureRegion {
public var width:Int = 0;
public var height:Int = 0;
public var u:Float = 0;
public var v:Float = 0;
public var u2:Float = 0;
public var v2:Float = 0;
public var degrees:Int = 0;
public var offsetX:Float = 0;
public var offsetY:Float = 0;
public var originalWidth:Int = 0;
public var originalHeight:Int = 0;
public var texture:Dynamic;
public function new() {}
}

View File

@ -43,7 +43,7 @@ class TransformConstraint implements Updatable {
}
public function update():Void {
if (mixRotate == 0 && mixX == 0 && mixY == 0 && mixScaleX == 0 && mixScaleX == 0 && mixShearY == 0)
if (mixRotate == 0 && mixX == 0 && mixY == 0 && mixScaleX == 0 && mixScaleY == 0 && mixShearY == 0)
return;
if (data.local) {

View File

@ -1,9 +0,0 @@
package spine;
interface VertexEffect {
function begin(skeleton:Skeleton):Void;
function transform(vertex:Vertex):Void;
function end():Void;
}

View File

@ -1,29 +0,0 @@
package spine.atlas;
import openfl.Vector;
class AtlasRegion {
public var page:AtlasPage;
public var name:String;
public var x:Int = 0;
public var y:Int = 0;
public var width:Int = 0;
public var height:Int = 0;
public var u:Float = 0;
public var v:Float = 0;
public var u2:Float = 0;
public var v2:Float = 0;
public var offsetX:Float = 0;
public var offsetY:Float = 0;
public var originalWidth:Int = 0;
public var originalHeight:Int = 0;
public var index:Int = 0;
public var degrees:Int = 0;
public var splits:Vector<Int>;
public var pads:Vector<Int>;
public var rendererObject:Dynamic;
public var names:Vector<String>;
public var values:Vector<Vector<Float>>;
public function new() {}
}

View File

@ -5,9 +5,9 @@ import openfl.utils.ByteArray;
import openfl.utils.Dictionary;
import openfl.Vector;
class Atlas {
private var pages:Vector<AtlasPage> = new Vector<AtlasPage>();
private var regions:Vector<AtlasRegion> = new Vector<AtlasRegion>();
class TextureAtlas {
private var pages = new Vector<TextureAtlasPage>();
private var regions = new Vector<TextureAtlasRegion>();
private var textureLoader:TextureLoader;
/** @param object A String or ByteArray. */
@ -20,7 +20,7 @@ class Atlas {
} else if (Std.isOfType(object, ByteArrayData)) {
load(cast(object, ByteArray).readUTFBytes(cast(object, ByteArray).length), textureLoader);
} else {
throw new ArgumentError("object must be a TextureAtlas or AttachmentLoader.");
throw new ArgumentError("object must be a string or ByteArrayData.");
}
}
@ -32,8 +32,8 @@ class Atlas {
var reader:Reader = new Reader(atlasText);
var entry:Vector<String> = new Vector<String>(5, true);
var page:AtlasPage = null;
var region:AtlasRegion = null;
var page:TextureAtlasPage = null;
var region:TextureAtlasRegion = null;
var pageFields:Dictionary<String, Void->Void> = new Dictionary<String, Void->Void>();
pageFields["size"] = function():Void {
@ -58,12 +58,28 @@ class Atlas {
};
var regionFields:Dictionary<String, Void->Void> = new Dictionary<String, Void->Void>();
regionFields["xy"] = function():Void {
region.x = Std.parseInt(entry[1]);
region.y = Std.parseInt(entry[2]);
};
regionFields["size"] = function():Void {
region.width = Std.parseInt(entry[1]);
region.height = Std.parseInt(entry[2]);
};
regionFields["bounds"] = function():Void {
region.x = Std.parseInt(entry[1]);
region.y = Std.parseInt(entry[2]);
region.width = Std.parseInt(entry[3]);
region.height = Std.parseInt(entry[4]);
};
regionFields["offset"] = function():Void {
region.offsetX = Std.parseInt(entry[1]);
region.offsetY = Std.parseInt(entry[2]);
};
regionFields["orig"] = function():Void {
region.originalWidth = Std.parseInt(entry[1]);
region.originalHeight = Std.parseInt(entry[2]);
};
regionFields["offsets"] = function():Void {
region.offsetX = Std.parseInt(entry[1]);
region.offsetY = Std.parseInt(entry[2]);
@ -107,8 +123,7 @@ class Atlas {
page = null;
line = reader.readLine();
} else if (page == null) {
page = new AtlasPage();
page.name = line;
page = new TextureAtlasPage(line);
while (true) {
if (reader.readEntry(entry, line = reader.readLine()) == 0)
break;
@ -120,9 +135,7 @@ class Atlas {
textureLoader.loadPage(page, line);
pages.push(page);
} else {
region = new AtlasRegion();
region.page = page;
region.name = line;
region = new TextureAtlasRegion(page, line);
while (true) {
var count:Int = reader.readEntry(entry, line = reader.readLine());
if (count == 0)
@ -149,7 +162,7 @@ class Atlas {
region.originalHeight = region.height;
}
if (names != null && names.length > 0) {
if (names != null && names.length > 0 && values != null && values.length > 0) {
region.names = names;
region.values = values;
names = null;
@ -174,7 +187,7 @@ class Atlas {
/** 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 {
public function findRegion(name:String):TextureAtlasRegion {
for (region in regions) {
if (region.name == name) {
return region;

View File

@ -1,16 +1,19 @@
package spine.atlas;
class AtlasPage {
class TextureAtlasPage {
public var name:String;
public var format:Format;
public var minFilter:TextureFilter = TextureFilter.nearest;
public var magFilter:TextureFilter = TextureFilter.nearest;
public var uWrap:TextureWrap = TextureWrap.clampToEdge;
public var vWrap:TextureWrap = TextureWrap.clampToEdge;
public var width:Int = 0;
public var height:Int = 0;
public var pma:Bool = false;
public var rendererObject:Dynamic;
public var width = 0;
public var height = 0;
public var pma = false;
public var texture:Dynamic;
public var regions = new Array<TextureAtlasRegion>();
public function new() {}
public function new(name:String) {
this.name = name;
}
}

View File

@ -0,0 +1,22 @@
package spine.atlas;
import openfl.Vector;
class TextureAtlasRegion extends TextureRegion {
public var page:TextureAtlasPage;
public var name:String;
public var x:Int = 0;
public var y:Int = 0;
public var index:Int = 0;
public var splits:Vector<Int>;
public var pads:Vector<Int>;
public var names:Vector<String>;
public var values:Vector<Vector<Float>>;
public function new(page:TextureAtlasPage, name:String) {
super();
this.page = page;
this.name = name;
page.regions.push(this);
}
}

View File

@ -1,9 +1,9 @@
package spine.atlas;
interface TextureLoader {
function loadPage(page:AtlasPage, path:String):Void;
function loadPage(page:TextureAtlasPage, path:String):Void;
function loadRegion(region:AtlasRegion):Void;
function loadRegion(region:TextureAtlasRegion):Void;
function unloadPage(page:AtlasPage):Void;
function unloadPage(page:TextureAtlasPage):Void;
}

View File

@ -1,22 +1,32 @@
package spine.attachments;
import openfl.errors.ArgumentError;
import spine.atlas.Atlas;
import spine.atlas.AtlasRegion;
import spine.atlas.TextureAtlas;
import spine.Skin;
class AtlasAttachmentLoader implements AttachmentLoader {
private var atlas:Atlas;
private var atlas:TextureAtlas;
public function new(atlas:Atlas) {
public function new(atlas:TextureAtlas) {
if (atlas == null) {
throw new ArgumentError("atlas cannot be null.");
}
this.atlas = atlas;
}
private function loadSequence(name:String, basePath:String, sequence:Sequence) {
var regions = sequence.regions;
for (i in 0...regions.length) {
var path = sequence.getPath(basePath, i);
var region = this.atlas.findRegion(path);
if (region == null)
trace("Region not found in atlas: " + path + " (sequence: " + name + ")");
regions[i] = region;
}
}
public function newRegionAttachment(skin:Skin, name:String, path:String):RegionAttachment {
var region:AtlasRegion = atlas.findRegion(path);
var region = atlas.findRegion(path);
if (region == null) {
trace("Region not found in atlas: " + path + " (region attachment: " + name + ")");
return null;
@ -34,7 +44,7 @@ class AtlasAttachmentLoader implements AttachmentLoader {
}
public function newMeshAttachment(skin:Skin, name:String, path:String):MeshAttachment {
var region:AtlasRegion = atlas.findRegion(path);
var region = atlas.findRegion(path);
if (region == null) {
trace("Region not found in atlas: " + path + " (mesh attachment: " + name + ")");
return null;

View File

@ -4,10 +4,10 @@ import spine.Skin;
interface AttachmentLoader {
/** @return May be null to not load an attachment. */
function newRegionAttachment(skin:Skin, name:String, path:String):RegionAttachment;
function newRegionAttachment(skin:Skin, name:String, path:String, sequence:Sequence):RegionAttachment;
/** @return May be null to not load an attachment. */
function newMeshAttachment(skin:Skin, name:String, path:String):MeshAttachment;
function newMeshAttachment(skin:Skin, name:String, path:String, sequence:Sequence):MeshAttachment;
/** @return May be null to not load an attachment. */
function newBoundingBoxAttachment(skin:Skin, name:String):BoundingBoxAttachment;

View File

@ -2,107 +2,95 @@ package spine.attachments;
import openfl.Vector;
import spine.Color;
import spine.atlas.TextureAtlasRegion;
class MeshAttachment extends VertexAttachment {
public var uvs:Vector<Float>;
public var regionUVs:Vector<Float>;
public var triangles:Vector<Int>;
class MeshAttachment extends VertexAttachment implements HasTextureRegion {
public var region:TextureRegion;
public var path:String;
public var regionUVs = new Vector<Float>();
public var uvs = new Vector<Float>();
public var triangles = new Vector<Int>();
public var color:Color = new Color(1, 1, 1, 1);
public var width:Float = 0;
public var height:Float = 0;
public var hullLength:Int = 0;
public var edges = new Vector<Int>();
public var rendererObject:Dynamic;
public var sequence:Sequence;
private var _parentMesh:MeshAttachment;
public var path:String;
public var rendererObject:Dynamic;
public var regionU:Float = 0;
public var regionV:Float = 0;
public var regionU2:Float = 0;
public var regionV2:Float = 0;
public var regionDegrees:Int = 0;
public var regionOffsetX:Float = 0; // Pixels stripped from the bottom left, unrotated.
public var regionOffsetY:Float = 0;
public var regionWidth:Float = 0; // Unrotated, stripped size.
public var regionHeight:Float = 0;
public var regionOriginalWidth:Float = 0; // Unrotated, unstripped size.
public var regionOriginalHeight:Float = 0;
// Nonessential.
public var edges:Vector<Int>;
public var width:Float = 0;
public var height:Float = 0;
public function new(name:String) {
public function new(name:String, path:String) {
super(name);
this.path = path;
}
public function updateUVs():Void {
var i:Int = 0, n:Int = regionUVs.length;
var u:Float = regionU, v:Float = regionV;
var width:Float = 0, height:Float = 0;
var textureWidth:Float, textureHeight:Float;
if (uvs == null || uvs.length != n)
uvs = new Vector<Float>(n, true);
switch (regionDegrees) {
case 90:
{
textureWidth = regionHeight / (regionU2 - regionU);
textureHeight = regionWidth / (regionV2 - regionV);
u -= (regionOriginalHeight - regionOffsetY - regionHeight) / textureWidth;
v -= (regionOriginalWidth - regionOffsetX - regionWidth) / textureHeight;
width = regionOriginalHeight / textureWidth;
height = regionOriginalWidth / textureHeight;
i = 0;
public function updateRegion():Void {
if (region == null) {
trace("Region not set.");
return;
}
var regionUVs = this.regionUVs;
if (uvs.length != regionUVs.length)
uvs = new Vector<Float>(regionUVs.length, true);
var n = uvs.length;
var u = region.u, v = region.v, width:Float = 0, height:Float = 0;
if (Std.isOfType(region, TextureAtlasRegion)) {
var atlasRegion:TextureAtlasRegion = cast(region, TextureAtlasRegion);
var textureWidth = atlasRegion.page.width,
textureHeight = atlasRegion.page.height;
switch (atlasRegion.degrees) {
case 90:
u -= (region.originalHeight - region.offsetY - region.height) / textureWidth;
v -= (region.originalWidth - region.offsetX - region.width) / textureHeight;
width = region.originalHeight / textureWidth;
height = region.originalWidth / textureHeight;
var i = 0;
while (i < n) {
uvs[i] = u + regionUVs[i + 1] * width;
uvs[i + 1] = v + (1 - regionUVs[i]) * height;
i += 2;
}
}
case 180:
{
textureWidth = regionWidth / (regionU2 - regionU);
textureHeight = regionHeight / (regionV2 - regionV);
u -= (regionOriginalWidth - regionOffsetX - regionWidth) / textureWidth;
v -= regionOffsetY / textureHeight;
width = regionOriginalWidth / textureWidth;
height = regionOriginalHeight / textureHeight;
i = 0;
return;
case 180:
u -= (region.originalWidth - region.offsetX - region.width) / textureWidth;
v -= region.offsetY / textureHeight;
width = region.originalWidth / textureWidth;
height = region.originalHeight / textureHeight;
var i = 0;
while (i < n) {
uvs[i] = u + (1 - regionUVs[i]) * width;
uvs[i + 1] = v + (1 - regionUVs[i + 1]) * height;
i += 2;
}
}
case 270:
{
textureWidth = regionWidth / (regionU2 - regionU);
textureHeight = regionHeight / (regionV2 - regionV);
u -= regionOffsetY / textureWidth;
v -= regionOffsetX / textureHeight;
width = regionOriginalHeight / textureWidth;
height = regionOriginalWidth / textureHeight;
i = 0;
return;
case 270:
u -= region.offsetY / textureWidth;
v -= region.offsetX / textureHeight;
width = region.originalHeight / textureWidth;
height = region.originalWidth / textureHeight;
var i = 0;
while (i < n) {
uvs[i] = u + (1 - regionUVs[i + 1]) * width;
uvs[i + 1] = v + regionUVs[i] * height;
i += 2;
}
}
default:
{
textureWidth = regionWidth / (regionU2 - regionU);
textureHeight = regionHeight / (regionV2 - regionV);
u -= regionOffsetX / textureWidth;
v -= (regionOriginalHeight - regionOffsetY - regionHeight) / textureHeight;
width = regionOriginalWidth / textureWidth;
height = regionOriginalHeight / textureHeight;
i = 0;
while (i < n) {
uvs[i] = u + regionUVs[i] * width;
uvs[i + 1] = v + regionUVs[i + 1] * height;
i += 2;
}
}
return;
}
u -= region.offsetX / textureWidth;
v -= (region.originalHeight - region.offsetY - region.height) / textureHeight;
width = region.originalWidth / textureWidth;
height = region.originalHeight / textureHeight;
} else if (region == null) {
u = v = 0;
width = height = 1;
} else {
width = this.region.u2 - u;
height = this.region.v2 - v;
}
var i = 0;
while (i < n) {
uvs[i] = u + regionUVs[i] * width;
uvs[i + 1] = v + regionUVs[i + 1] * height;
}
}
@ -129,62 +117,46 @@ class MeshAttachment extends VertexAttachment {
}
override public function copy():Attachment {
var copy:MeshAttachment = new MeshAttachment(name);
copy.rendererObject = rendererObject;
copy.regionU = regionU;
copy.regionV = regionV;
copy.regionU2 = regionU2;
copy.regionV2 = regionV2;
copy.regionDegrees = regionDegrees;
copy.regionOffsetX = regionOffsetX;
copy.regionOffsetY = regionOffsetY;
copy.regionWidth = regionWidth;
copy.regionHeight = regionHeight;
copy.regionOriginalWidth = regionOriginalWidth;
copy.regionOriginalHeight = regionOriginalHeight;
copy.path = path;
if (parentMesh != null)
return newLinkedMesh();
var copy:MeshAttachment = new MeshAttachment(name, this.path);
copy.region = region;
copy.color.setFromColor(color);
copy.rendererObject = rendererObject;
if (parentMesh == null) {
this.copyTo(copy);
copy.regionUVs = regionUVs.concat();
copy.uvs = uvs.concat();
copy.triangles = triangles.concat();
copy.hullLength = hullLength;
this.copyTo(copy);
copy.regionUVs = regionUVs.concat();
copy.uvs = uvs.concat();
copy.triangles = triangles.concat();
copy.hullLength = hullLength;
// Nonessential.
if (edges != null) {
copy.edges = edges.concat();
}
copy.width = width;
copy.height = height;
} else {
copy.parentMesh = parentMesh;
copy.updateUVs();
copy.sequence = sequence != null ? sequence.copy() : null;
if (edges != null) {
copy.edges = edges.concat();
}
copy.width = width;
copy.height = height;
return copy;
}
public override function computeWorldVertices(slot:Slot, start:Int, count:Int, worldVertices:Vector<Float>, offset:Int, stride:Int):Void {
if (sequence != null)
sequence.apply(slot, this);
super.computeWorldVertices(slot, start, count, worldVertices, offset, stride);
}
public function newLinkedMesh():MeshAttachment {
var copy:MeshAttachment = new MeshAttachment(name);
var copy:MeshAttachment = new MeshAttachment(name, path);
copy.rendererObject = rendererObject;
copy.regionU = regionU;
copy.regionV = regionV;
copy.regionU2 = regionU2;
copy.regionV2 = regionV2;
copy.regionDegrees = regionDegrees;
copy.regionOffsetX = regionOffsetX;
copy.regionOffsetY = regionOffsetY;
copy.regionWidth = regionWidth;
copy.regionHeight = regionHeight;
copy.regionOriginalWidth = regionOriginalWidth;
copy.regionOriginalHeight = regionOriginalHeight;
copy.path = path;
copy.region = region;
copy.color.setFromColor(color);
copy.deformAttachment = deformAttachment;
copy.parentMesh = parentMesh != null ? parentMesh : this;
copy.updateUVs();
copy.timelineAttachment = timelineAttachment;
copy.parentMesh = this.parentMesh != null ? this.parentMesh : this;
if (copy.region != null)
copy.updateRegion();
return copy;
}
}

View File

@ -4,7 +4,7 @@ import openfl.Vector;
import spine.Bone;
import spine.Color;
class RegionAttachment extends Attachment {
class RegionAttachment extends Attachment implements HasTextureRegion {
public static inline var BLX:Int = 0;
public static inline var BLY:Int = 1;
public static inline var ULX:Int = 2;
@ -24,49 +24,79 @@ class RegionAttachment extends Attachment {
public var color:Color = new Color(1, 1, 1, 1);
public var path:String;
public var rendererObject:Dynamic;
public var regionOffsetX:Float = 0; // Pixels stripped from the bottom left, unrotated.
public var regionOffsetY:Float = 0;
public var regionWidth:Float = 0; // Unrotated, stripped size.
public var regionHeight:Float = 0;
public var regionOriginalWidth:Float = 0; // Unrotated, unstripped size.
public var regionOriginalHeight:Float = 0;
public var region:TextureRegion;
public var sequence:Sequence;
private var offsets:Vector<Float> = new Vector<Float>(8, true);
public var uvs:Vector<Float> = new Vector<Float>(8, true);
public function new(name:String) {
public function new(name:String, path:String) {
super(name);
this.path = path;
}
public function updateOffset():Void {
var regionScaleX:Float = width / regionOriginalWidth * scaleX;
var regionScaleY:Float = height / regionOriginalHeight * scaleY;
var localX:Float = -width * 0.5 * scaleX + regionOffsetX * regionScaleX;
var localY:Float = -height * 0.5 * scaleY + regionOffsetY * regionScaleY;
var localX2:Float = localX + regionWidth * regionScaleX;
var localY2:Float = localY + regionHeight * regionScaleY;
public function updateRegion():Void {
if (region == null) {
trace("Region not set.");
uvs[0] = 0;
uvs[1] = 0;
uvs[2] = 0;
uvs[3] = 1;
uvs[4] = 1;
uvs[5] = 1;
uvs[6] = 1;
uvs[7] = 0;
return;
}
var radians:Float = rotation * MathUtils.degRad;
var cos:Float = Math.cos(radians);
var sin:Float = Math.sin(radians);
var localXCos:Float = localX * cos + x;
var localXSin:Float = localX * sin;
var localYCos:Float = localY * cos + y;
var localYSin:Float = localY * sin;
var localX2Cos:Float = localX2 * cos + x;
var localX2Sin:Float = localX2 * sin;
var localY2Cos:Float = localY2 * cos + y;
var localY2Sin:Float = localY2 * sin;
var regionScaleX = width / region.originalWidth * scaleX;
var regionScaleY = height / region.originalHeight * scaleY;
var localX = -width / 2 * scaleX + region.offsetX * regionScaleX;
var localY = -height / 2 * scaleY + region.offsetY * regionScaleY;
var localX2 = localX + region.width * regionScaleX;
var localY2 = localY + region.height * regionScaleY;
var radians = rotation * Math.PI / 180;
var cos = Math.cos(radians);
var sin = Math.sin(radians);
var x = this.x, y = this.y;
var localXCos = localX * cos + x;
var localXSin = localX * sin;
var localYCos = localY * cos + y;
var localYSin = localY * sin;
var localX2Cos = localX2 * cos + x;
var localX2Sin = localX2 * sin;
var localY2Cos = localY2 * cos + y;
var localY2Sin = localY2 * sin;
offsets[BLX] = localXCos - localYSin;
offsets[BLY] = localYCos + localXSin;
offsets[ULX] = localXCos - localY2Sin;
offsets[ULY] = localY2Cos + localXSin;
offsets[URX] = localX2Cos - localY2Sin;
offsets[URY] = localY2Cos + localX2Sin;
offsets[BRX] = localX2Cos - localYSin;
offsets[BRY] = localYCos + localX2Sin;
offsets[0] = localXCos - localYSin;
offsets[1] = localYCos + localXSin;
offsets[2] = localXCos - localY2Sin;
offsets[3] = localY2Cos + localXSin;
offsets[4] = localX2Cos - localY2Sin;
offsets[5] = localY2Cos + localX2Sin;
offsets[6] = localX2Cos - localYSin;
offsets[7] = localYCos + localX2Sin;
if (region.degrees == 90) {
uvs[0] = region.u2;
uvs[1] = region.v2;
uvs[2] = region.u;
uvs[3] = region.v2;
uvs[4] = region.u;
uvs[5] = region.v;
uvs[6] = region.u2;
uvs[7] = region.v;
} else {
uvs[0] = region.u;
uvs[1] = region.v2;
uvs[2] = region.u;
uvs[3] = region.v;
uvs[4] = region.u2;
uvs[5] = region.v;
uvs[6] = region.u2;
uvs[7] = region.v2;
}
}
public function setUVs(u:Float, v:Float, u2:Float, v2:Float, degrees:Int):Void {
@ -91,48 +121,44 @@ class RegionAttachment extends Attachment {
}
}
public function computeWorldVertices(bone:Bone, worldVertices:Vector<Float>, offset:Int, stride:Int):Void {
var x:Float = bone.worldX, y:Float = bone.worldY;
var a:Float = bone.a,
b:Float = bone.b,
c:Float = bone.c,
d:Float = bone.d;
public function computeWorldVertices(slot:Slot, worldVertices:Vector<Float>, offset:Int, stride:Int):Void {
if (sequence != null)
sequence.apply(slot, this);
var bone = slot.bone;
var vertexOffset = this.offsets;
var x = bone.worldX, y = bone.worldY;
var a = bone.a, b = bone.b, c = bone.c, d = bone.d;
var offsetX:Float = 0, offsetY:Float = 0;
offsetX = offsets[BRX];
offsetY = offsets[BRY];
offsetX = vertexOffset[0];
offsetY = vertexOffset[1];
worldVertices[offset] = offsetX * a + offsetY * b + x; // br
worldVertices[offset + 1] = offsetX * c + offsetY * d + y;
offset += stride;
offsetX = offsets[BLX];
offsetY = offsets[BLY];
offsetX = vertexOffset[2];
offsetY = vertexOffset[3];
worldVertices[offset] = offsetX * a + offsetY * b + x; // bl
worldVertices[offset + 1] = offsetX * c + offsetY * d + y;
offset += stride;
offsetX = offsets[ULX];
offsetY = offsets[ULY];
offsetX = vertexOffset[4];
offsetY = vertexOffset[5];
worldVertices[offset] = offsetX * a + offsetY * b + x; // ul
worldVertices[offset + 1] = offsetX * c + offsetY * d + y;
offset += stride;
offsetX = offsets[URX];
offsetY = offsets[URY];
offsetX = vertexOffset[6];
offsetY = vertexOffset[7];
worldVertices[offset] = offsetX * a + offsetY * b + x; // ur
worldVertices[offset + 1] = offsetX * c + offsetY * d + y;
}
override public function copy():Attachment {
var copy:RegionAttachment = new RegionAttachment(name);
copy.regionWidth = regionWidth;
copy.regionHeight = regionHeight;
copy.regionOffsetX = regionOffsetX;
copy.regionOffsetY = regionOffsetY;
copy.regionOriginalWidth = regionOriginalWidth;
copy.regionOriginalHeight = regionOriginalHeight;
var copy:RegionAttachment = new RegionAttachment(name, path);
copy.region = region;
copy.rendererObject = rendererObject;
copy.path = path;
copy.x = x;
copy.y = y;
copy.scaleX = scaleX;
@ -143,6 +169,7 @@ class RegionAttachment extends Attachment {
copy.uvs = uvs.concat();
copy.offsets = offsets.concat();
copy.color.setFromColor(color);
copy.sequence = sequence != null ? sequence.copy() : null;
return copy;
}
}

View File

@ -9,14 +9,14 @@ class VertexAttachment extends Attachment {
private static var nextID:Int = 0;
public var bones:Vector<Int>;
public var vertices:Vector<Float>;
public var vertices = new Vector<Float>();
public var worldVerticesLength:Int = 0;
public var id:Int = nextID++;
public var deformAttachment:VertexAttachment;
public var timelineAttachment:VertexAttachment;
public function new(name:String) {
super(name);
deformAttachment = this;
timelineAttachment = this;
}
/** Transforms the attachment's local {@link #vertices} to world coordinates. If the slot's {@link Slot#deform} is
@ -130,11 +130,9 @@ class VertexAttachment extends Attachment {
if (this.vertices != null) {
attachment.vertices = vertices.concat();
} else {
attachment.vertices = null;
}
attachment.worldVerticesLength = worldVerticesLength;
attachment.deformAttachment = deformAttachment;
attachment.timelineAttachment = timelineAttachment;
}
}

View File

@ -5,7 +5,7 @@ import openfl.geom.Matrix;
import openfl.geom.Point;
import openfl.geom.Rectangle;
import openfl.Vector;
import spine.atlas.AtlasRegion;
import spine.atlas.TextureAtlasRegion;
import spine.attachments.Attachment;
import spine.attachments.ClippingAttachment;
import spine.attachments.MeshAttachment;
@ -15,7 +15,6 @@ import spine.Skeleton;
import spine.SkeletonClipping;
import spine.SkeletonData;
import spine.Slot;
import spine.VertexEffect;
import starling.display.BlendMode;
import starling.display.DisplayObject;
import starling.display.Image;
@ -37,11 +36,8 @@ class SkeletonSprite extends DisplayObject {
private static var clipper:SkeletonClipping = new SkeletonClipping();
private static var QUAD_INDICES:Vector<Int> = Vector.ofArray([0, 1, 2, 2, 3, 0]);
public var vertexEffect:VertexEffect;
private var tempLight:spine.Color = new spine.Color(0, 0, 0);
private var tempDark:spine.Color = new spine.Color(0, 0, 0);
private var tempVertex:spine.Vertex = new spine.Vertex();
public function new(skeletonData:SkeletonData) {
super();
@ -71,9 +67,6 @@ class SkeletonSprite extends DisplayObject {
var vertexData:VertexData;
var uvs:Vector<Float>;
if (vertexEffect != null)
vertexEffect.begin(skeleton);
for (slot in drawOrder) {
if (!slot.bone.active) {
clipper.clipEndWithSlot(slot);
@ -96,8 +89,8 @@ class SkeletonSprite extends DisplayObject {
} else {
if (Std.isOfType(region.rendererObject, Image)) {
region.rendererObject = mesh = new SkeletonMesh(cast(region.rendererObject, Image).texture);
} else if (Std.isOfType(region.rendererObject, AtlasRegion)) {
region.rendererObject = mesh = new SkeletonMesh(cast(cast(region.rendererObject, AtlasRegion).rendererObject, Image).texture);
} else if (Std.isOfType(region.rendererObject, TextureAtlasRegion)) {
region.rendererObject = mesh = new SkeletonMesh(cast(region.rendererObject, TextureAtlasRegion).texture);
}
indexData = mesh.getIndexData();
@ -127,9 +120,8 @@ class SkeletonSprite extends DisplayObject {
} else {
if (Std.isOfType(meshAttachment.rendererObject, Image)) {
meshAttachment.rendererObject = mesh = new SkeletonMesh(cast(meshAttachment.rendererObject, Image).texture);
} else if (Std.isOfType(meshAttachment.rendererObject, AtlasRegion)) {
meshAttachment.rendererObject = mesh = new SkeletonMesh(cast(cast(meshAttachment.rendererObject, AtlasRegion).rendererObject, Image)
.texture);
} else if (Std.isOfType(meshAttachment.rendererObject, TextureAtlasRegion)) {
meshAttachment.rendererObject = mesh = new SkeletonMesh(cast(meshAttachment.rendererObject, TextureAtlasRegion).texture);
}
indexData = mesh.getIndexData();
@ -189,39 +181,12 @@ class SkeletonSprite extends DisplayObject {
vertexData = mesh.getVertexData();
vertexData.numVertices = verticesCount;
if (vertexEffect != null) {
tempLight.r = ((rgb >> 16) & 0xff) / 255.0;
tempLight.g = ((rgb >> 8) & 0xff) / 255.0;
tempLight.b = (rgb & 0xff) / 255.0;
tempLight.a = a;
tempDark.r = ((dark >> 16) & 0xff) / 255.0;
tempDark.g = ((dark >> 8) & 0xff) / 255.0;
tempDark.b = (dark & 0xff) / 255.0;
tempDark.a = 0;
var ii:Int = 0;
for (i in 0...verticesCount) {
tempVertex.x = worldVertices[ii];
tempVertex.y = worldVertices[ii + 1];
tempVertex.u = uvs[ii];
tempVertex.v = uvs[ii + 1];
tempVertex.light.setFromColor(tempLight);
tempVertex.dark.setFromColor(tempDark);
vertexEffect.transform(tempVertex);
vertexData.colorize("color",
Color.rgb(Std.int(tempVertex.light.r * 255), Std.int(tempVertex.light.g * 255), Std.int(tempVertex.light.b * 255)),
tempVertex.light.a, i, 1);
mesh.setVertexPosition(i, tempVertex.x, tempVertex.y);
mesh.setTexCoords(i, tempVertex.u, tempVertex.v);
ii += 2;
}
} else {
vertexData.colorize("color", rgb, a);
var ii:Int = 0;
for (i in 0...verticesCount) {
mesh.setVertexPosition(i, worldVertices[ii], worldVertices[ii + 1]);
mesh.setTexCoords(i, uvs[ii], uvs[ii + 1]);
ii += 2;
}
vertexData.colorize("color", rgb, a);
var ii:Int = 0;
for (i in 0...verticesCount) {
mesh.setVertexPosition(i, worldVertices[ii], worldVertices[ii + 1]);
mesh.setTexCoords(i, uvs[ii], uvs[ii + 1]);
ii += 2;
}
if (indexData.numIndices > 0 && vertexData.numVertices > 0) {
@ -233,9 +198,6 @@ class SkeletonSprite extends DisplayObject {
}
painter.state.blendMode = originalBlendMode;
clipper.clipEnd();
if (vertexEffect != null)
vertexEffect.end();
}
override public function hitTest(localPoint:Point):DisplayObject {

View File

@ -4,8 +4,8 @@ import openfl.display.Bitmap;
import openfl.display.BitmapData;
import openfl.errors.ArgumentError;
import openfl.utils.Object;
import spine.atlas.AtlasPage;
import spine.atlas.AtlasRegion;
import spine.atlas.TextureAtlasPage;
import spine.atlas.TextureAtlasRegion;
import spine.atlas.TextureLoader;
import starling.display.Image;
import starling.textures.Texture;
@ -46,37 +46,39 @@ class StarlingTextureLoader implements TextureLoader {
}
}
public function loadPage(page:AtlasPage, path:String):Void {
public function loadPage(page:TextureAtlasPage, path:String):Void {
var bitmapDataOrTexture:Dynamic = singleBitmapDataOrTexture != null ? singleBitmapDataOrTexture : bitmapDatasOrTextures[path];
if (bitmapDataOrTexture == null) {
throw new ArgumentError("BitmapData/Texture not found with name: " + path);
}
if (Std.isOfType(bitmapDataOrTexture, BitmapData)) {
var bitmapData:BitmapData = cast(bitmapDataOrTexture, BitmapData);
page.rendererObject = Texture.fromBitmapData(bitmapData);
page.texture = Texture.fromBitmapData(bitmapData);
} else {
var texture:Texture = cast(bitmapDataOrTexture, Texture);
page.rendererObject = texture;
page.texture = texture;
}
}
public function loadRegion(region:AtlasRegion):Void {
var image:Image = new Image(cast(region.page.rendererObject, Texture));
if (region.degrees == 90) {
image.setTexCoords(0, region.u, region.v2);
image.setTexCoords(1, region.u, region.v);
image.setTexCoords(2, region.u2, region.v2);
image.setTexCoords(3, region.u2, region.v);
} else {
image.setTexCoords(0, region.u, region.v);
image.setTexCoords(1, region.u2, region.v);
image.setTexCoords(2, region.u, region.v2);
image.setTexCoords(3, region.u2, region.v2);
}
region.rendererObject = image;
public function loadRegion(region:TextureAtlasRegion):Void {
// FIXME rotation shouldn't be implemented like this
/*var image:Image = new Image(cast(region.page.texture, Texture));
if (region.degrees == 90) {
image.setTexCoords(0, region.u, region.v2);
image.setTexCoords(1, region.u, region.v);
image.setTexCoords(2, region.u2, region.v2);
image.setTexCoords(3, region.u2, region.v);
} else {
image.setTexCoords(0, region.u, region.v);
image.setTexCoords(1, region.u2, region.v);
image.setTexCoords(2, region.u, region.v2);
image.setTexCoords(3, region.u2, region.v2);
}
region.texture = image; */
region.texture = region.page.texture;
}
public function unloadPage(page:AtlasPage):Void {
cast(page.rendererObject, Texture).dispose();
public function unloadPage(page:TextureAtlasPage):Void {
cast(page.texture, Texture).dispose();
}
}

View File

@ -1,25 +0,0 @@
package spine.vertexeffects;
import spine.MathUtils;
import spine.Skeleton;
import spine.Vertex;
import spine.VertexEffect;
class JitterEffect implements VertexEffect {
public var jitterX:Float = 0;
public var jitterY:Float = 0;
public function new(jitterX:Float, jitterY:Float) {
this.jitterX = jitterX;
this.jitterY = jitterY;
}
public function begin(skeleton:Skeleton):Void {}
public function transform(vertex:Vertex):Void {
vertex.x += MathUtils.randomTriangular(-jitterX, jitterY);
vertex.y += MathUtils.randomTriangular(-jitterX, jitterY);
}
public function end():Void {}
}

View File

@ -1,97 +0,0 @@
package spine.vertexeffects;
import spine.interpolation.Pow;
import spine.Interpolation;
import spine.MathUtils;
import spine.Skeleton;
import spine.Vertex;
import spine.VertexEffect;
class SwirlEffect implements VertexEffect {
private var worldX:Float = 0;
private var worldY:Float = 0;
private var _radius:Float = 0;
private var _angle:Float = 0;
private var _interpolation:Interpolation;
private var _centerX:Float = 0;
private var _centerY:Float = 0;
public function new(radius:Float) {
this._interpolation = new Pow(2);
this._radius = radius;
}
public function begin(skeleton:Skeleton):Void {
worldX = skeleton.x + _centerX;
worldY = skeleton.y + _centerY;
}
public function transform(vertex:Vertex):Void {
var x:Float = vertex.x - worldX;
var y:Float = vertex.y - worldY;
var dist:Float = Math.sqrt(x * x + y * y);
if (dist < radius) {
var theta:Float = interpolation.apply(0, angle, (radius - dist) / radius);
var cos:Float = Math.cos(theta), sin:Float = Math.sin(theta);
vertex.x = cos * x - sin * y + worldX;
vertex.y = sin * x + cos * y + worldY;
}
}
public function end():Void {}
public var radius(get, set):Float;
private function get_radius():Float {
return _radius;
}
private function set_radius(radius:Float):Float {
_radius = radius;
return _radius;
}
public var angle(get, set):Float;
private function get_angle():Float {
return _angle;
}
private function set_angle(angle:Float):Float {
_angle = angle * MathUtils.degRad;
return _angle;
}
public var centerX(get, set):Float;
private function get_centerX():Float {
return _centerX;
}
private function set_centerX(centerX:Float):Float {
_centerX = centerX;
return _centerX;
}
public var centerY(get, set):Float;
private function get_centerY():Float {
return _centerY;
}
private function set_centerY(centerY:Float):Float {
_centerY = centerY;
return _centerY;
}
public var interpolation(get, set):Interpolation;
private function get_interpolation():Interpolation {
return _interpolation;
}
private function set_interpolation(interpolation:Interpolation):Interpolation {
_interpolation = interpolation;
return _interpolation;
}
}