mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-04 14:24:53 +08:00
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:
parent
6ce7a62245
commit
22b2086f39
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -43,6 +43,7 @@ struct spBoneData {
|
||||
float x, y;
|
||||
float rotation;
|
||||
float scaleX, scaleY;
|
||||
int/*bool*/flipX, flipY;
|
||||
int/*bool*/inheritScale, inheritRotation;
|
||||
};
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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; } }
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user