Flip for bones. Flip timelines now affect bones. "draworder" in JSON -> "drawOrder".

Falls back to "draworder" to not break existing JSON (for the time being).
This commit is contained in:
NathanSweet 2014-10-04 13:01:52 +02:00
parent 6ce7a62245
commit 22b2086f39
19 changed files with 202 additions and 133 deletions

View File

@ -469,7 +469,8 @@ public class SkeletonJson {
}
}
var drawOrderValues:Object = map["draworder"];
var drawOrderValues:Object = map["drawOrder"];
if (!drawOrderValues) drawOrderValues = map["draworder"];
if (drawOrderValues) {
var drawOrderTimeline:DrawOrderTimeline = new DrawOrderTimeline(drawOrderValues.length);
var slotCount:int = skeletonData.slots.length;

View File

@ -307,10 +307,11 @@ typedef spIkConstraintTimeline IkConstraintTimeline;
/**/
typedef struct {
spCurveTimeline super;
spTimeline super;
int const x;
int const framesCount;
float* const frames; /* time, flip, ... */
int boneIndex;
} spFlipTimeline;
spFlipTimeline* spFlipTimeline_create (int framesCount, int/*bool*/x);

View File

@ -47,11 +47,13 @@ struct spBone {
float x, y;
float rotation, rotationIK;
float scaleX, scaleY;
int/*bool*/flipX, flipY;
float const m00, m01, worldX; /* a b x */
float const m10, m11, worldY; /* c d y */
float const worldRotation;
float const worldScaleX, worldScaleY;
int/*bool*/const worldFlipX, worldFlipY;
};
void spBone_setYDown (int/*bool*/yDown);

View File

@ -43,6 +43,7 @@ struct spBoneData {
float x, y;
float rotation;
float scaleX, scaleY;
int/*bool*/flipX, flipY;
int/*bool*/inheritScale, inheritRotation;
};

View File

@ -808,22 +808,21 @@ void _spFlipTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, fl
if (self->frames[frameIndex] <= lastTime) return;
if (self->x)
skeleton->flipX = self->frames[frameIndex + 1];
skeleton->bones[self->boneIndex]->flipX = self->frames[frameIndex + 1];
else
skeleton->flipY = self->frames[frameIndex + 1];
skeleton->bones[self->boneIndex]->flipY = self->frames[frameIndex + 1];
}
void _spFlipTimeline_dispose (spTimeline* timeline) {
spFlipTimeline* self = SUB_CAST(spFlipTimeline, timeline);
_spCurveTimeline_deinit(SUPER(self));
_spTimeline_deinit(SUPER(self));
FREE(self->frames);
FREE(self);
}
spFlipTimeline* spFlipTimeline_create (int framesCount, int/*bool*/x) {
spFlipTimeline* self = NEW(spFlipTimeline);
_spCurveTimeline_init(SUPER(self), x ? SP_TIMELINE_FLIPX : SP_TIMELINE_FLIPY, framesCount,
_spFlipTimeline_dispose, _spFlipTimeline_apply);
_spTimeline_init(SUPER(self), x ? SP_TIMELINE_FLIPX : SP_TIMELINE_FLIPY, _spFlipTimeline_dispose, _spFlipTimeline_apply);
CONST_CAST(int, self->x) = x;
CONST_CAST(int, self->framesCount) = framesCount << 1;
CONST_CAST(float*, self->frames) = CALLOC(float, self->framesCount);

View File

@ -64,24 +64,29 @@ void spBone_updateWorldTransform (spBone* self) {
}
CONST_CAST(float, self->worldRotation) =
self->data->inheritRotation ? self->parent->worldRotation + self->rotationIK : self->rotationIK;
CONST_CAST(int, self->worldFlipX) = self->parent->worldFlipX ^ self->flipX;
CONST_CAST(int, self->worldFlipY) = self->parent->worldFlipY ^ self->flipY;
} else {
int skeletonFlipX = self->skeleton->flipX, skeletonFlipY = self->skeleton->flipY;
CONST_CAST(float, self->worldX) = self->skeleton->flipX ? -self->x : self->x;
CONST_CAST(float, self->worldY) = self->skeleton->flipY != yDown ? -self->y : self->y;
CONST_CAST(float, self->worldScaleX) = self->scaleX;
CONST_CAST(float, self->worldScaleY) = self->scaleY;
CONST_CAST(float, self->worldRotation) = self->rotationIK;
CONST_CAST(int, self->worldFlipX) = skeletonFlipX ^ self->flipX;
CONST_CAST(int, self->worldFlipY) = skeletonFlipY ^ self->flipY;
}
radians = self->worldRotation * DEG_RAD;
cosine = COS(radians);
sine = SIN(radians);
if (self->skeleton->flipX) {
if (self->worldFlipX) {
CONST_CAST(float, self->m00) = -cosine * self->worldScaleX;
CONST_CAST(float, self->m01) = sine * self->worldScaleY;
} else {
CONST_CAST(float, self->m00) = cosine * self->worldScaleX;
CONST_CAST(float, self->m01) = -sine * self->worldScaleY;
}
if (self->skeleton->flipY != yDown) {
if (self->worldFlipY != yDown) {
CONST_CAST(float, self->m10) = -sine * self->worldScaleX;
CONST_CAST(float, self->m11) = -cosine * self->worldScaleY;
} else {
@ -97,13 +102,15 @@ void spBone_setToSetupPose (spBone* self) {
self->rotationIK = self->rotation;
self->scaleX = self->data->scaleX;
self->scaleY = self->data->scaleY;
self->flipX = self->data->flipX;
self->flipY = self->data->flipY;
}
void spBone_worldToLocal (spBone* self, float worldX, float worldY, float* localX, float* localY) {
float invDet;
float dx = worldX - self->worldX, dy = worldY - self->worldY;
float m00 = self->m00, m11 = self->m11;
if (self->skeleton->flipX != (self->skeleton->flipY != yDown)) {
if (self->worldFlipX != (self->worldFlipY != yDown)) {
m00 *= -1;
m11 *= -1;
}

View File

@ -111,7 +111,8 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r
Json* slots = Json_getItem(root, "slots");
Json* ik = Json_getItem(root, "ik");
Json* ffd = Json_getItem(root, "ffd");
Json* drawOrder = Json_getItem(root, "draworder");
Json* drawOrder = Json_getItem(root, "drawOrder");
if (!drawOrder) drawOrder = Json_getItem(root, "draworder");
Json* events = Json_getItem(root, "events");
Json* flipX = Json_getItem(root, "flipx");
Json* flipY = Json_getItem(root, "flipy");
@ -218,6 +219,17 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r
animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline);
duration = timeline->frames[timelineArray->size * 3 - 3];
if (duration > animation->duration) animation->duration = duration;
} else if (strcmp(timelineArray->name, "flipX") == 0 || strcmp(timelineArray->name, "flipY") == 0) {
int x = strcmp(timelineArray->name, "flipX") == 0;
char* field = x ? "x" : "y";
spFlipTimeline *timeline = spFlipTimeline_create(timelineArray->size, x);
timeline->boneIndex = boneIndex;
for (frame = timelineArray->child, i = 0; frame; frame = frame->next, ++i)
spFlipTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0), Json_getInt(frame, field, 0));
animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline);
duration = timeline->frames[timelineArray->size * 2 - 2];
if (duration > animation->duration) animation->duration = duration;
} else {
spAnimation_dispose(animation);
_spSkeletonJson_setError(self, 0, "Invalid timeline type for a bone: ", timelineArray->name);
@ -316,26 +328,6 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r
}
}
/* Flip timelines. */
if (flipX) {
Json* frame;
spFlipTimeline* timeline = spFlipTimeline_create(flipX->size, 1);
for (frame = flipX->child, i = 0; frame; frame = frame->next, ++i)
spFlipTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0), Json_getInt(frame, "x", 0));
animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline);
duration = timeline->frames[flipX->size * 2 - 2];
if (duration > animation->duration) animation->duration = duration;
}
if (flipY) {
Json* frame;
spFlipTimeline* timeline = spFlipTimeline_create(flipY->size, 0);
for (frame = flipY->child, i = 0; frame; frame = frame->next, ++i)
spFlipTimeline_setFrame(timeline, i, Json_getFloat(frame, "time", 0), Json_getInt(frame, "y", 0));
animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline);
duration = timeline->frames[flipY->size * 2 - 2];
if (duration > animation->duration) animation->duration = duration;
}
/* Draw order timeline. */
if (drawOrder) {
spDrawOrderTimeline* timeline = spDrawOrderTimeline_create(drawOrder->size, skeletonData->slotsCount);

View File

@ -670,13 +670,15 @@ namespace Spine {
}
}
public class FlipXTimeline : CurveTimeline {
public class FlipXTimeline : Timeline {
internal int boneIndex;
internal float[] frames;
public int BoneIndex { get { return boneIndex; } set { boneIndex = value; } }
public float[] Frames { get { return frames; } set { frames = value; } } // time, flip, ...
public int FrameCount { get { return frames.Length >> 1; } }
public FlipXTimeline (int frameCount)
: base(frameCount) {
public FlipXTimeline (int frameCount) {
frames = new float[frameCount << 1];
}
@ -687,7 +689,7 @@ namespace Spine {
frames[frameIndex + 1] = flip ? 1 : 0;
}
override public void Apply (Skeleton skeleton, float lastTime, float time, List<Event> firedEvents, float alpha) {
public void Apply (Skeleton skeleton, float lastTime, float time, List<Event> firedEvents, float alpha) {
float[] frames = this.frames;
if (time < frames[0]) {
if (lastTime > time) Apply(skeleton, lastTime, int.MaxValue, null, 0);
@ -698,11 +700,11 @@ namespace Spine {
int frameIndex = (time >= frames[frames.Length - 2] ? frames.Length : Animation.binarySearch(frames, time, 2)) - 2;
if (frames[frameIndex] <= lastTime) return;
Flip(skeleton, frames[frameIndex + 1] != 0);
SetFlip(skeleton.bones[boneIndex], frames[frameIndex + 1] != 0);
}
virtual protected void Flip (Skeleton skeleton, bool flip) {
skeleton.flipX = flip;
virtual protected void SetFlip (Bone bone, bool flip) {
bone.flipX = flip;
}
}
@ -711,8 +713,8 @@ namespace Spine {
: base(frameCount) {
}
override protected void Flip (Skeleton skeleton, bool flip) {
skeleton.flipY = flip;
override protected void SetFlip (Bone bone, bool flip) {
bone.flipY = flip;
}
}
}

View File

@ -40,8 +40,10 @@ namespace Spine {
internal Bone parent;
internal List<Bone> children;
internal float x, y, rotation, rotationIK, scaleX, scaleY;
internal bool flipX, flipY;
internal float m00, m01, m10, m11;
internal float worldX, worldY, worldRotation, worldScaleX, worldScaleY;
internal bool worldFlipX, worldFlipY;
public BoneData Data { get { return data; } }
public Skeleton Skeleton { get { return skeleton; } }
@ -55,6 +57,8 @@ namespace Spine {
public float RotationIK { get { return rotationIK; } set { rotationIK = value; } }
public float ScaleX { get { return scaleX; } set { scaleX = value; } }
public float ScaleY { get { return scaleY; } set { scaleY = value; } }
public bool FlipX { get { return flipX; } set { flipX = value; } }
public bool FlipY { get { return flipY; } set { flipY = value; } }
public float M00 { get { return m00; } }
public float M01 { get { return m01; } }
@ -65,6 +69,8 @@ namespace Spine {
public float WorldRotation { get { return worldRotation; } }
public float WorldScaleX { get { return worldScaleX; } }
public float WorldScaleY { get { return worldScaleY; } }
public bool WorldFlipX { get { return worldFlipX; } set { worldFlipX = value; } }
public bool WorldFlipY { get { return worldFlipY; } set { worldFlipY = value; } }
/// <param name="parent">May be null.</param>
public Bone (BoneData data, Skeleton skeleton, Bone parent) {
@ -93,24 +99,29 @@ namespace Spine {
worldScaleY = scaleY;
}
worldRotation = data.inheritRotation ? parent.worldRotation + rotationIK : rotationIK;
worldFlipX = parent.worldFlipX ^ flipX;
worldFlipY = parent.worldFlipY ^ flipY;
} else {
worldX = skeleton.flipX ? -x : x;
worldY = skeleton.flipY != yDown ? -y : y;
bool skeletonFlipX = skeleton.flipX, skeletonFlipY = skeleton.flipY;
worldX = skeletonFlipX ? -x : x;
worldY = skeletonFlipY != yDown ? -y : y;
worldScaleX = scaleX;
worldScaleY = scaleY;
worldRotation = rotationIK;
worldFlipX = skeletonFlipX ^ flipX;
worldFlipY = skeletonFlipY ^ flipY;
}
float radians = worldRotation * (float)Math.PI / 180;
float cos = (float)Math.Cos(radians);
float sin = (float)Math.Sin(radians);
if (skeleton.flipX) {
if (worldFlipX) {
m00 = -cos * worldScaleX;
m01 = sin * worldScaleY;
} else {
m00 = cos * worldScaleX;
m01 = -sin * worldScaleY;
}
if (skeleton.flipY != yDown) {
if (worldFlipY != yDown) {
m10 = -sin * worldScaleX;
m11 = -cos * worldScaleY;
} else {
@ -127,13 +138,14 @@ namespace Spine {
rotationIK = rotation;
scaleX = data.scaleX;
scaleY = data.scaleY;
flipX = data.flipX;
flipY = data.flipY;
}
public void worldToLocal (float worldX, float worldY, out float localX, out float localY) {
float dx = worldX - this.worldX, dy = worldY - this.worldY;
float m00 = this.m00, m10 = this.m10, m01 = this.m01, m11 = this.m11;
Skeleton skeleton = this.skeleton;
if (skeleton.flipX != (skeleton.flipY != yDown)) {
if (worldFlipX != (worldFlipY != yDown)) {
m00 = -m00;
m11 = -m11;
}

View File

@ -35,6 +35,7 @@ namespace Spine {
internal BoneData parent;
internal String name;
internal float length, x, y, rotation, scaleX = 1, scaleY = 1;
internal bool flipX, flipY;
internal bool inheritScale = true, inheritRotation = true;
/// <summary>May be null.</summary>
@ -46,6 +47,8 @@ namespace Spine {
public float Rotation { get { return rotation; } set { rotation = value; } }
public float ScaleX { get { return scaleX; } set { scaleX = value; } }
public float ScaleY { get { return scaleY; } set { scaleY = value; } }
public bool FlipX { get { return flipX; } set { flipX = value; } }
public bool FlipY { get { return flipY; } set { flipY = value; } }
public bool InheritScale { get { return inheritScale; } set { inheritScale = value; } }
public bool InheritRotation { get { return inheritRotation; } set { inheritRotation = value; } }

View File

@ -114,6 +114,8 @@ namespace Spine {
boneData.rotation = GetFloat(boneMap, "rotation", 0);
boneData.scaleX = GetFloat(boneMap, "scaleX", 1);
boneData.scaleY = GetFloat(boneMap, "scaleY", 1);
boneData.flipX = GetBoolean(boneMap, "flipX", false);
boneData.flipY = GetBoolean(boneMap, "flipY", false);
boneData.inheritScale = GetBoolean(boneMap, "inheritScale", true);
boneData.inheritRotation = GetBoolean(boneMap, "inheritRotation", true);
skeletonData.bones.Add(boneData);
@ -387,7 +389,7 @@ namespace Spine {
foreach (KeyValuePair<String, Object> timelineEntry in timelineMap) {
var values = (List<Object>)timelineEntry.Value;
var timelineName = (String)timelineEntry.Key;
if (timelineName.Equals("color")) {
if (timelineName == "color") {
var timeline = new ColorTimeline(values.Count);
timeline.slotIndex = slotIndex;
@ -402,7 +404,7 @@ namespace Spine {
timelines.Add(timeline);
duration = Math.Max(duration, timeline.frames[timeline.FrameCount * 5 - 5]);
} else if (timelineName.Equals("attachment")) {
} else if (timelineName == "attachment") {
var timeline = new AttachmentTimeline(values.Count);
timeline.slotIndex = slotIndex;
@ -431,7 +433,7 @@ namespace Spine {
foreach (KeyValuePair<String, Object> timelineEntry in timelineMap) {
var values = (List<Object>)timelineEntry.Value;
var timelineName = (String)timelineEntry.Key;
if (timelineName.Equals("rotate")) {
if (timelineName == "rotate") {
var timeline = new RotateTimeline(values.Count);
timeline.boneIndex = boneIndex;
@ -445,10 +447,10 @@ namespace Spine {
timelines.Add(timeline);
duration = Math.Max(duration, timeline.frames[timeline.FrameCount * 2 - 2]);
} else if (timelineName.Equals("translate") || timelineName.Equals("scale")) {
} else if (timelineName == "translate" || timelineName == "scale") {
TranslateTimeline timeline;
float timelineScale = 1;
if (timelineName.Equals("scale"))
if (timelineName == "scale")
timeline = new ScaleTimeline(values.Count);
else {
timeline = new TranslateTimeline(values.Count);
@ -468,6 +470,21 @@ namespace Spine {
timelines.Add(timeline);
duration = Math.Max(duration, timeline.frames[timeline.FrameCount * 3 - 3]);
} else if (timelineName == "flipX" || timelineName == "flipY") {
bool x = timelineName == "flipX";
var timeline = x ? new FlipXTimeline(values.Count) : new FlipYTimeline(values.Count);
timeline.boneIndex = boneIndex;
String field = x ? "x" : "y";
int frameIndex = 0;
foreach (Dictionary<String, Object> valueMap in values) {
float time = (float)valueMap["time"];
timeline.SetFrame(frameIndex, time, valueMap.ContainsKey(field) ? (bool)valueMap[field] : false);
frameIndex++;
}
timelines.Add(timeline);
duration = Math.Max(duration, timeline.frames[timeline.FrameCount * 2 - 2]);
} else
throw new Exception("Invalid timeline type for a bone: " + timelineName + " (" + boneName + ")");
}
@ -550,27 +567,8 @@ namespace Spine {
}
}
if (map.ContainsKey("flipx")) {
var flipMap = (List<Object>)map["flipx"];
var timeline = new FlipXTimeline(flipMap.Count);
int frameIndex = 0;
foreach (Dictionary<String, Object> valueMap in flipMap)
timeline.SetFrame(frameIndex++, (float)valueMap["time"], valueMap.ContainsKey("x") ? (bool)valueMap["x"] : false);
timelines.Add(timeline);
duration = Math.Max(duration, timeline.frames[timeline.FrameCount * 2 - 2]);
}
if (map.ContainsKey("flipy")) {
var flipMap = (List<Object>)map["flipy"];
var timeline = new FlipYTimeline(flipMap.Count);
int frameIndex = 0;
foreach (Dictionary<String, Object> valueMap in flipMap)
timeline.SetFrame(frameIndex++, (float)valueMap["time"], valueMap.ContainsKey("y") ? (bool)valueMap["y"] : false);
timelines.Add(timeline);
duration = Math.Max(duration, timeline.frames[timeline.FrameCount * 2 - 2]);
}
if (map.ContainsKey("draworder")) {
var values = (List<Object>)map["draworder"];
if (map.ContainsKey("drawOrder") || map.ContainsKey("draworder")) {
var values = (List<Object>)map[map.ContainsKey("drawOrder") ? "drawOrder" : "draworder"];
var timeline = new DrawOrderTimeline(values.Count);
int slotCount = skeletonData.slots.Count;
int frameIndex = 0;

View File

@ -1712,7 +1712,8 @@ spine.SkeletonJson.prototype = {
}
}
var drawOrderValues = map["draworder"];
var drawOrderValues = map["drawOrder"];
if (!drawOrderValues) drawOrderValues = map["draworder"];
if (drawOrderValues) {
var timeline = new spine.DrawOrderTimeline(drawOrderValues.length);
var slotCount = skeletonData.slots.length;

View File

@ -778,12 +778,21 @@ public class Animation {
}
static public class FlipXTimeline implements Timeline {
int boneIndex;
final float[] frames; // time, flip, ...
public FlipXTimeline (int frameCount) {
frames = new float[frameCount << 1];
}
public void setBoneIndex (int boneIndex) {
this.boneIndex = boneIndex;
}
public int getBoneIndex () {
return boneIndex;
}
public int getFrameCount () {
return frames.length >> 1;
}
@ -806,15 +815,13 @@ public class Animation {
return;
} else if (lastTime > time) //
lastTime = -1;
int frameIndex = (time >= frames[frames.length - 2] ? frames.length : binarySearch(frames, time, 2)) - 2;
if (frames[frameIndex] <= lastTime) return;
flip(skeleton, frames[frameIndex + 1] != 0);
setFlip(skeleton.bones.get(boneIndex), frames[frameIndex + 1] != 0);
}
protected void flip (Skeleton skeleton, boolean flip) {
skeleton.setFlipX(flip);
protected void setFlip (Bone bone, boolean flip) {
bone.setFlipX(flip);
}
}
@ -823,8 +830,8 @@ public class Animation {
super(frameCount);
}
protected void flip (Skeleton skeleton, boolean flip) {
skeleton.setFlipY(flip);
protected void setFlip (Bone bone, boolean flip) {
bone.setFlipY(flip);
}
}
}

View File

@ -43,11 +43,13 @@ public class Bone {
float x, y;
float rotation, rotationIK;
float scaleX, scaleY;
boolean flipX, flipY;
float m00, m01, worldX; // a b x
float m10, m11, worldY; // c d y
float worldRotation;
float worldScaleX, worldScaleY;
boolean worldFlipX, worldFlipY;
Bone (BoneData data) {
this.data = data;
@ -78,6 +80,8 @@ public class Bone {
rotationIK = bone.rotationIK;
scaleX = bone.scaleX;
scaleY = bone.scaleY;
flipX = bone.flipX;
flipY = bone.flipY;
}
/** Computes the world SRT using the parent bone and the local SRT. */
@ -96,23 +100,28 @@ public class Bone {
worldScaleY = scaleY;
}
worldRotation = data.inheritRotation ? parent.worldRotation + rotationIK : rotationIK;
worldFlipX = parent.worldFlipX ^ flipX;
worldFlipY = parent.worldFlipY ^ flipY;
} else {
worldX = skeleton.flipX ? -x : x;
worldY = skeleton.flipY ? -y : y;
boolean skeletonFlipX = skeleton.flipX, skeletonFlipY = skeleton.flipY;
worldX = skeletonFlipX ? -x : x;
worldY = skeletonFlipY ? -y : y;
worldScaleX = scaleX;
worldScaleY = scaleY;
worldRotation = rotationIK;
worldFlipX = skeletonFlipX ^ flipX;
worldFlipY = skeletonFlipY ^ flipY;
}
float cos = MathUtils.cosDeg(worldRotation);
float sin = MathUtils.sinDeg(worldRotation);
if (skeleton.flipX) {
if (worldFlipX) {
m00 = -cos * worldScaleX;
m01 = sin * worldScaleY;
} else {
m00 = cos * worldScaleX;
m01 = -sin * worldScaleY;
}
if (skeleton.flipY) {
if (worldFlipY) {
m10 = -sin * worldScaleX;
m11 = -cos * worldScaleY;
} else {
@ -129,6 +138,8 @@ public class Bone {
rotationIK = rotation;
scaleX = data.scaleX;
scaleY = data.scaleY;
flipX = data.flipX;
flipY = data.flipY;
}
public BoneData getData () {
@ -208,6 +219,22 @@ public class Bone {
scaleY = scale;
}
public boolean getFlipX () {
return flipX;
}
public void setFlipX (boolean flipX) {
this.flipX = flipX;
}
public boolean getFlipY () {
return flipY;
}
public void setFlipY (boolean flipY) {
this.flipY = flipY;
}
public float getM00 () {
return m00;
}
@ -244,6 +271,14 @@ public class Bone {
return worldScaleY;
}
public boolean getWorldFlipX () {
return worldFlipX;
}
public boolean getWorldFlipY () {
return worldFlipY;
}
public Matrix3 getWorldTransform (Matrix3 worldTransform) {
if (worldTransform == null) throw new IllegalArgumentException("worldTransform cannot be null.");
float[] val = worldTransform.val;
@ -262,8 +297,7 @@ public class Bone {
public Vector2 worldToLocal (Vector2 world) {
float x = world.x - worldX, y = world.y - worldY;
float m00 = this.m00, m10 = this.m10, m01 = this.m01, m11 = this.m11;
Skeleton skeleton = this.skeleton;
if (skeleton.flipX != skeleton.flipY) {
if (worldFlipX != worldFlipY) {
m00 = -m00;
m11 = -m11;
}

View File

@ -39,6 +39,7 @@ public class BoneData {
float x, y;
float rotation;
float scaleX = 1, scaleY = 1;
boolean flipX, flipY;
boolean inheritScale = true, inheritRotation = true;
// Nonessential.
@ -63,6 +64,8 @@ public class BoneData {
rotation = bone.rotation;
scaleX = bone.scaleX;
scaleY = bone.scaleY;
flipX = bone.flipX;
flipY = bone.flipY;
}
/** @return May be null. */
@ -132,6 +135,22 @@ public class BoneData {
this.scaleY = scaleY;
}
public boolean getFlipX () {
return flipX;
}
public void setFlipX (boolean flipX) {
this.flipX = flipX;
}
public boolean getFlipY () {
return flipY;
}
public void setFlipY (boolean flipY) {
this.flipY = flipY;
}
public boolean getInheritScale () {
return inheritScale;
}

View File

@ -68,6 +68,8 @@ public class SkeletonBinary {
static public final int TIMELINE_TRANSLATE = 2;
static public final int TIMELINE_ATTACHMENT = 3;
static public final int TIMELINE_COLOR = 4;
static public final int TIMELINE_FLIPX = 5;
static public final int TIMELINE_FLIPY = 6;
static public final int CURVE_LINEAR = 0;
static public final int CURVE_STEPPED = 1;
@ -124,6 +126,8 @@ public class SkeletonBinary {
boneData.scaleY = input.readFloat();
boneData.rotation = input.readFloat();
boneData.length = input.readFloat() * scale;
boneData.flipX = input.readBoolean();
boneData.flipY = input.readBoolean();
boneData.inheritScale = input.readBoolean();
boneData.inheritRotation = input.readBoolean();
if (nonessential) Color.rgba8888ToColor(boneData.color, input.readInt());
@ -384,7 +388,7 @@ public class SkeletonBinary {
break;
}
case TIMELINE_TRANSLATE:
case TIMELINE_SCALE:
case TIMELINE_SCALE: {
TranslateTimeline timeline;
float timelineScale = 1;
if (timelineType == TIMELINE_SCALE)
@ -403,6 +407,18 @@ public class SkeletonBinary {
duration = Math.max(duration, timeline.getFrames()[frameCount * 3 - 3]);
break;
}
case TIMELINE_FLIPX:
case TIMELINE_FLIPY: {
FlipXTimeline timeline = timelineType == TIMELINE_FLIPX ? new FlipXTimeline(frameCount) : new FlipYTimeline(
frameCount);
timeline.boneIndex = boneIndex;
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++)
timeline.setFrame(frameIndex, input.readFloat(), input.readBoolean());
timelines.add(timeline);
duration = Math.max(duration, timeline.getFrames()[frameCount * 2 - 2]);
break;
}
}
}
}
@ -474,28 +490,6 @@ public class SkeletonBinary {
}
}
// Flip timelines.
int flipCount = input.readInt(true);
if (flipCount > 0) {
FlipXTimeline timeline = new FlipXTimeline(flipCount);
for (int i = 0; i < flipCount; i++) {
float time = input.readFloat();
timeline.setFrame(i, time, input.readBoolean());
}
timelines.add(timeline);
duration = Math.max(duration, timeline.getFrames()[flipCount * 2 - 2]);
}
flipCount = input.readInt(true);
if (flipCount > 0) {
FlipYTimeline timeline = new FlipYTimeline(flipCount);
for (int i = 0; i < flipCount; i++) {
float time = input.readFloat();
timeline.setFrame(i, time, input.readBoolean());
}
timelines.add(timeline);
duration = Math.max(duration, timeline.getFrames()[flipCount * 2 - 2]);
}
// Draw order timeline.
int drawOrderCount = input.readInt(true);
if (drawOrderCount > 0) {

View File

@ -116,6 +116,8 @@ public class SkeletonJson {
boneData.rotation = boneMap.getFloat("rotation", 0);
boneData.scaleX = boneMap.getFloat("scaleX", 1);
boneData.scaleY = boneMap.getFloat("scaleY", 1);
boneData.flipX = boneMap.getBoolean("flipX", false);
boneData.flipY = boneMap.getBoolean("flipY", false);
boneData.inheritScale = boneMap.getBoolean("inheritScale", true);
boneData.inheritRotation = boneMap.getBoolean("inheritRotation", true);
@ -385,6 +387,20 @@ public class SkeletonJson {
timelines.add(timeline);
duration = Math.max(duration, timeline.getFrames()[timeline.getFrameCount() * 3 - 3]);
} else if (timelineName.equals("flipX") || timelineName.equals("flipY")) {
boolean x = timelineName.equals("flipX");
FlipXTimeline timeline = x ? new FlipXTimeline(timelineMap.size) : new FlipYTimeline(timelineMap.size);
timeline.boneIndex = boneIndex;
String field = x ? "x" : "y";
int frameIndex = 0;
for (JsonValue valueMap = timelineMap.child; valueMap != null; valueMap = valueMap.next) {
timeline.setFrame(frameIndex, valueMap.getFloat("time"), valueMap.getBoolean(field, false));
frameIndex++;
}
timelines.add(timeline);
duration = Math.max(duration, timeline.getFrames()[timeline.getFrameCount() * 2 - 2]);
} else
throw new RuntimeException("Invalid timeline type for a bone: " + timelineName + " (" + boneMap.name + ")");
}
@ -460,28 +476,9 @@ public class SkeletonJson {
}
}
// Flip timelines.
JsonValue flipMap = map.get("flipx");
if (flipMap != null) {
FlipXTimeline timeline = new FlipXTimeline(flipMap.size);
int frameIndex = 0;
for (JsonValue valueMap = flipMap.child; valueMap != null; valueMap = valueMap.next)
timeline.setFrame(frameIndex++, valueMap.getFloat("time"), valueMap.getBoolean("x", false));
timelines.add(timeline);
duration = Math.max(duration, timeline.getFrames()[timeline.getFrameCount() * 2 - 2]);
}
flipMap = map.get("flipy");
if (flipMap != null) {
FlipYTimeline timeline = new FlipYTimeline(flipMap.size);
int frameIndex = 0;
for (JsonValue valueMap = flipMap.child; valueMap != null; valueMap = valueMap.next)
timeline.setFrame(frameIndex++, valueMap.getFloat("time"), valueMap.getBoolean("y", false));
timelines.add(timeline);
duration = Math.max(duration, timeline.getFrames()[timeline.getFrameCount() * 2 - 2]);
}
// Draw order timeline.
JsonValue drawOrdersMap = map.get("draworder");
JsonValue drawOrdersMap = map.get("drawOrder");
if (drawOrdersMap == null) drawOrdersMap = map.get("draworder");
if (drawOrdersMap != null) {
DrawOrderTimeline timeline = new DrawOrderTimeline(drawOrdersMap.size);
int slotCount = skeletonData.slots.size;

View File

@ -206,8 +206,6 @@ public class SkeletonViewer extends ApplicationAdapter {
if (!ui.pauseButton.isChecked()) {
state.update(delta);
state.apply(skeleton);
ui.flipXCheckbox.setChecked(skeleton.getFlipX());
ui.flipYCheckbox.setChecked(skeleton.getFlipY());
}
skeleton.setPosition(skeletonX, skeletonY);
// skeleton.setPosition(0, 0);

View File

@ -447,7 +447,8 @@ function SkeletonJson.new (attachmentLoader)
end
end
local drawOrderValues = map["draworder"]
local drawOrderValues = map["drawOrder"]
if not drawOrderValues then drawOrderValues = map["draworder"] end
if drawOrderValues then
local timeline = Animation.DrawOrderTimeline.new(#drawOrderValues)
local slotCount = #skeletonData.slots