Merge branch '3.7-beta' into 3.7-beta-cpp

This commit is contained in:
badlogic 2018-08-24 11:37:12 +02:00
commit f5cc2933be
42 changed files with 11066 additions and 10839 deletions

View File

@ -452,7 +452,7 @@ typedef struct spIkConstraintTimeline {
SP_API spIkConstraintTimeline* spIkConstraintTimeline_create (int framesCount);
SP_API void spIkConstraintTimeline_setFrame (spIkConstraintTimeline* self, int frameIndex, float time, float mix, int bendDirection, int /**boolean**/ stretch);
SP_API void spIkConstraintTimeline_setFrame (spIkConstraintTimeline* self, int frameIndex, float time, float mix, int bendDirection, int /*boolean*/ compress, int /**boolean**/ stretch);
#ifdef SPINE_SHORT_NAMES
typedef spIkConstraintTimeline IkConstraintTimeline;

View File

@ -49,6 +49,7 @@ typedef struct spIkConstraint {
spBone* target;
int bendDirection;
int /*boolean*/ compress;
int /*boolean*/ stretch;
float mix;
@ -70,7 +71,7 @@ SP_API void spIkConstraint_dispose (spIkConstraint* self);
SP_API void spIkConstraint_apply (spIkConstraint* self);
SP_API void spIkConstraint_apply1 (spBone* bone, float targetX, float targetY, int /*boolean*/ stretch, float alpha);
SP_API void spIkConstraint_apply1 (spBone* bone, float targetX, float targetY, int /*boolean*/ compress, int /*boolean*/ stretch, int /*boolean*/ uniform, float alpha);
SP_API void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float targetY, int bendDirection, int /*boolean*/ stretch, float alpha);
#ifdef SPINE_SHORT_NAMES

View File

@ -46,7 +46,9 @@ typedef struct spIkConstraintData {
spBoneData* target;
int bendDirection;
int /*boolean*/ compress;
int /*boolean*/ stretch;
int /*boolean*/ uniform;
float mix;
#ifdef __cplusplus
@ -56,7 +58,9 @@ typedef struct spIkConstraintData {
bones(0),
target(0),
bendDirection(0),
compress(0),
stretch(0),
uniform(0),
mix(0) {
}
#endif

View File

@ -1282,8 +1282,8 @@ void spDrawOrderTimeline_setFrame (spDrawOrderTimeline* self, int frameIndex, fl
/**/
static const int IKCONSTRAINT_PREV_TIME = -4, IKCONSTRAINT_PREV_MIX = -3, IKCONSTRAINT_PREV_BEND_DIRECTION = -2, IKCONSTRAINT_PREV_STRETCH = -1;
static const int IKCONSTRAINT_MIX = 1, IKCONSTRAINT_BEND_DIRECTION = 2, IKCONSTRAINT_STRETCH = 3;
static const int IKCONSTRAINT_PREV_TIME = -5, IKCONSTRAINT_PREV_MIX = -4, IKCONSTRAINT_PREV_BEND_DIRECTION = -3, IKCONSTRAINT_PREV_COMPRESS = -2, IKCONSTRAINT_PREV_STRETCH = -1;
static const int IKCONSTRAINT_MIX = 1, IKCONSTRAINT_BEND_DIRECTION = 2, IKCONSTRAINT_COMPRESS = 3, IKCONSTRAINT_STRETCH = 4;
void _spIkConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skeleton, float lastTime, float time,
spEvent** firedEvents, int* eventsCount, float alpha, spMixBlend blend, spMixDirection direction) {
@ -1301,11 +1301,13 @@ void _spIkConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skel
case SP_MIX_BLEND_SETUP:
constraint->mix = constraint->data->mix;
constraint->bendDirection = constraint->data->bendDirection;
constraint->compress = constraint->data->compress;
constraint->stretch = constraint->data->stretch;
return;
case SP_MIX_BLEND_FIRST:
constraint->mix += (constraint->data->mix - constraint->mix) * alpha;
constraint->bendDirection = constraint->data->bendDirection;
constraint->compress = constraint->data->compress;
constraint->stretch = constraint->data->stretch;
case SP_MIX_BLEND_REPLACE:
case SP_MIX_BLEND_ADD:
@ -1321,15 +1323,18 @@ void _spIkConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skel
constraint->mix = constraint->data->mix + (frames[framesCount + IKCONSTRAINT_PREV_MIX] - constraint->data->mix) * alpha;
if (direction == SP_MIX_DIRECTION_OUT) {
constraint->bendDirection = constraint->data->bendDirection;
constraint->compress = constraint->data->compress;
constraint->stretch = constraint->data->stretch;
} else {
constraint->bendDirection = (int)frames[framesCount + IKCONSTRAINT_PREV_BEND_DIRECTION];
constraint->compress = frames[framesCount + IKCONSTRAINT_PREV_COMPRESS] ? 1 : 0;
constraint->stretch = frames[framesCount + IKCONSTRAINT_PREV_STRETCH] ? 1 : 0;
}
} else {
constraint->mix += (frames[framesCount + IKCONSTRAINT_PREV_MIX] - constraint->mix) * alpha;
if (direction == SP_MIX_DIRECTION_IN) {
constraint->bendDirection = (int)frames[framesCount + IKCONSTRAINT_PREV_BEND_DIRECTION];
constraint->compress = frames[framesCount + IKCONSTRAINT_PREV_COMPRESS] ? 1 : 0;
constraint->stretch = frames[framesCount + IKCONSTRAINT_PREV_STRETCH] ? 1 : 0;
}
}
@ -1346,15 +1351,18 @@ void _spIkConstraintTimeline_apply (const spTimeline* timeline, spSkeleton* skel
constraint->mix = constraint->data->mix + (mix + (frames[frame + IKCONSTRAINT_MIX] - mix) * percent - constraint->data->mix) * alpha;
if (direction == SP_MIX_DIRECTION_OUT) {
constraint->bendDirection = constraint->data->bendDirection;
constraint->compress = constraint->data->compress;
constraint->stretch = constraint->data->stretch;
} else {
constraint->bendDirection = (int)frames[frame + IKCONSTRAINT_PREV_BEND_DIRECTION];
constraint->compress = frames[frame + IKCONSTRAINT_PREV_COMPRESS] ? 1 : 0;
constraint->stretch = frames[frame + IKCONSTRAINT_PREV_STRETCH] ? 1 : 0;
}
} else {
constraint->mix += (mix + (frames[frame + IKCONSTRAINT_MIX] - mix) * percent - constraint->mix) * alpha;
if (direction == SP_MIX_DIRECTION_IN) {
constraint->bendDirection = (int)frames[frame + IKCONSTRAINT_PREV_BEND_DIRECTION];
constraint->compress = frames[frame + IKCONSTRAINT_PREV_COMPRESS] ? 1 : 0;
constraint->stretch = frames[frame + IKCONSTRAINT_PREV_STRETCH] ? 1 : 0;
}
}
@ -1372,11 +1380,12 @@ spIkConstraintTimeline* spIkConstraintTimeline_create (int framesCount) {
return (spIkConstraintTimeline*)_spBaseTimeline_create(framesCount, SP_TIMELINE_IKCONSTRAINT, IKCONSTRAINT_ENTRIES, _spIkConstraintTimeline_apply, _spIkConstraintTimeline_getPropertyId);
}
void spIkConstraintTimeline_setFrame (spIkConstraintTimeline* self, int frameIndex, float time, float mix, int bendDirection, int /*boolean*/ stretch) {
void spIkConstraintTimeline_setFrame (spIkConstraintTimeline* self, int frameIndex, float time, float mix, int bendDirection, int /*boolean*/ compress, int /*boolean*/ stretch) {
frameIndex *= IKCONSTRAINT_ENTRIES;
self->frames[frameIndex] = time;
self->frames[frameIndex + IKCONSTRAINT_MIX] = mix;
self->frames[frameIndex + IKCONSTRAINT_BEND_DIRECTION] = (float)bendDirection;
self->frames[frameIndex + IKCONSTRAINT_COMPRESS] = compress ? 1 : 0;
self->frames[frameIndex + IKCONSTRAINT_STRETCH] = stretch ? 1 : 0;
}

View File

@ -554,11 +554,11 @@ void _spAnimationState_applyRotateTimeline (spAnimationState* self, spTimeline*
/* Mix between rotations using the direction of the shortest route on the first frame while detecting crosses. */
r1 = blend == SP_MIX_BLEND_SETUP ? bone->data->rotation : bone->rotation;
diff = r2 - r1;
diff -= (16384 - (int)(16384.499999999996 - diff / 360)) * 360;
if (diff == 0) {
total = timelinesRotation[i];
} else {
float lastTotal, lastDiff;
diff -= (16384 - (int)(16384.499999999996 - diff / 360)) * 360;
if (firstFrame) {
lastTotal = 0;
lastDiff = diff;

View File

@ -39,6 +39,7 @@ spIkConstraint *spIkConstraint_create(spIkConstraintData *data, const spSkeleton
spIkConstraint *self = NEW(spIkConstraint);
CONST_CAST(spIkConstraintData*, self->data) = data;
self->bendDirection = data->bendDirection;
self->compress = data->compress;
self->stretch = data->stretch;
self->mix = data->mix;
@ -59,7 +60,7 @@ void spIkConstraint_dispose(spIkConstraint *self) {
void spIkConstraint_apply(spIkConstraint *self) {
switch (self->bonesCount) {
case 1:
spIkConstraint_apply1(self->bones[0], self->target->worldX, self->target->worldY, self->stretch, self->mix);
spIkConstraint_apply1(self->bones[0], self->target->worldX, self->target->worldY, self->compress, self->stretch, self->data->uniform, self->mix);
break;
case 2:
spIkConstraint_apply2(self->bones[0], self->bones[1], self->target->worldX, self->target->worldY, self->bendDirection, self->stretch, self->mix);
@ -67,9 +68,9 @@ void spIkConstraint_apply(spIkConstraint *self) {
}
}
void spIkConstraint_apply1 (spBone* bone, float targetX, float targetY, int /*boolean*/ stretch, float alpha) {
void spIkConstraint_apply1 (spBone* bone, float targetX, float targetY, int /*boolean*/ compress, int /*boolean*/ stretch, int /*boolean*/ uniform, float alpha) {
spBone* p = bone->parent;
float id, x, y, tx, ty, rotationIK, sx;
float id, x, y, tx, ty, rotationIK, sx, sy, s;
if (!bone->appliedValid) spBone_updateAppliedTransform(bone);
id = 1 / (p->a * p->d - p->b * p->c);
x = targetX - p->worldX, y = targetY - p->worldY;
@ -79,12 +80,17 @@ void spIkConstraint_apply1 (spBone* bone, float targetX, float targetY, int /*bo
if (rotationIK > 180) rotationIK -= 360;
else if (rotationIK < -180) rotationIK += 360;
sx = bone->ascaleX;
if (stretch) {
sy = bone->ascaleY;
if (compress || stretch) {
float b = bone->data->length * sx, dd = SQRT(tx * tx + ty * ty);
if (dd > b && b > 0.0001f) sx *= (dd / b - 1) * alpha - 1;
if ((compress && dd < b) || (stretch && dd > b) && (b > 0.0001f)) {
s = (dd / b - 1) * alpha + 1;
sx *= s;
if (uniform) sy *= s;
}
}
spBone_updateWorldTransformWith(bone, bone->ax, bone->ay, bone->arotation + rotationIK * alpha, sx,
bone->ascaleY, bone->ashearX, bone->ashearY);
sy, bone->ashearX, bone->ashearY);
}
void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float targetY, int bendDir, int /*boolean*/ stretch, float alpha) {

View File

@ -35,7 +35,9 @@ spIkConstraintData* spIkConstraintData_create (const char* name) {
spIkConstraintData* self = NEW(spIkConstraintData);
MALLOC_STR(self->name, name);
self->bendDirection = 1;
self->compress = 0;
self->stretch = 0;
self->uniform = 0;
self->mix = 1;
return self;
}

View File

@ -436,6 +436,7 @@ void spSkeleton_setBonesToSetupPose (const spSkeleton* self) {
for (i = 0; i < self->ikConstraintsCount; ++i) {
spIkConstraint* ikConstraint = self->ikConstraints[i];
ikConstraint->bendDirection = ikConstraint->data->bendDirection;
ikConstraint->compress = ikConstraint->data->compress;
ikConstraint->stretch = ikConstraint->data->stretch;
ikConstraint->mix = ikConstraint->data->mix;
}

View File

@ -392,8 +392,9 @@ static spAnimation* _spSkeletonBinary_readAnimation (spSkeletonBinary* self, con
float time = readFloat(input);
float mix = readFloat(input);
signed char bendDirection = readSByte(input);
int compress = readBoolean(input);
int stretch = readBoolean(input);
spIkConstraintTimeline_setFrame(timeline, frameIndex, time, mix, bendDirection, stretch);
spIkConstraintTimeline_setFrame(timeline, frameIndex, time, mix, bendDirection, compress, stretch);
if (frameIndex < frameCount - 1) readCurve(input, SUPER(timeline), frameIndex);
}
spTimelineArray_add(timelines, (spTimeline*)timeline);
@ -958,7 +959,9 @@ spSkeletonData* spSkeletonBinary_readSkeletonData (spSkeletonBinary* self, const
data->target = skeletonData->bones[readVarint(input, 1)];
data->mix = readFloat(input);
data->bendDirection = readSByte(input);
data->compress = readBoolean(input);
data->stretch = readBoolean(input);
data->uniform = readBoolean(input);
skeletonData->ikConstraints[i] = data;
}

View File

@ -299,7 +299,7 @@ static spAnimation* _spSkeletonJson_readAnimation (spSkeletonJson* self, Json* r
}
for (valueMap = constraintMap->child, frameIndex = 0; valueMap; valueMap = valueMap->next, ++frameIndex) {
spIkConstraintTimeline_setFrame(timeline, frameIndex, Json_getFloat(valueMap, "time", 0), Json_getFloat(valueMap, "mix", 1),
Json_getInt(valueMap, "bendPositive", 1) ? 1 : -1, Json_getInt(valueMap, "stretch", 0) ? 1 : 0);
Json_getInt(valueMap, "bendPositive", 1) ? 1 : -1, Json_getInt(valueMap, "compress", 0) ? 1 : 0, Json_getInt(valueMap, "stretch", 0) ? 1 : 0);
readCurve(valueMap, SUPER(timeline), frameIndex);
}
animation->timelines[animation->timelinesCount++] = SUPER_CAST(spTimeline, timeline);
@ -737,7 +737,9 @@ spSkeletonData* spSkeletonJson_readSkeletonData (spSkeletonJson* self, const cha
}
data->bendDirection = Json_getInt(constraintMap, "bendPositive", 1) ? 1 : -1;
data->compress = Json_getInt(constraintMap, "compress", 0) ? 1 : 0;
data->stretch = Json_getInt(constraintMap, "stretch", 0) ? 1 : 0;
data->uniform = Json_getInt(constraintMap, "uniform", 0) ? 1 : 0;
data->mix = Json_getFloat(constraintMap, "mix", 1);
skeletonData->ikConstraints[i] = data;

View File

@ -52,7 +52,7 @@ RTTI_DECL
public:
/// Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified
/// in the world coordinate system.
static void apply(Bone &bone, float targetX, float targetY, bool stretch, float alpha);
static void apply(Bone &bone, float targetX, float targetY, bool compress, bool stretch, bool uniform, float alpha);
/// Adjusts the parent and child bone rotations so the tip of the child is as close to the target position as
/// possible. The target is specified in the world coordinate system.
@ -80,6 +80,10 @@ public:
void setBendDirection(int inValue);
bool getCompress();
void setCompress(bool inValue);
bool getStretch();
void setStretch(bool inValue);
@ -92,6 +96,7 @@ private:
IkConstraintData &_data;
Vector<Bone *> _bones;
int _bendDirection;
bool _compress;
bool _stretch;
float _mix;
Bone *_target;

View File

@ -65,9 +65,15 @@ namespace spine {
int getBendDirection();
void setBendDirection(int inValue);
bool getCompress();
void setCompress(bool inValue);
bool getStretch();
void setStretch(bool inValue);
bool getUniform();
void setUniform(bool inValue);
float getMix();
void setMix(float inValue);
@ -77,7 +83,9 @@ namespace spine {
Vector<BoneData*> _bones;
BoneData* _target;
int _bendDirection;
bool _compress;
bool _stretch;
bool _uniform;
float _mix;
};
}

View File

@ -50,11 +50,11 @@ namespace spine {
virtual int getPropertyId();
/// Sets the time, mix and bend direction of the specified keyframe.
void setFrame (int frameIndex, float time, float mix, int bendDirection, bool stretch);
void setFrame (int frameIndex, float time, float mix, int bendDirection, bool compress, bool stretch);
private:
static const int PREV_TIME, PREV_MIX, PREV_BEND_DIRECTION, PREV_STRETCH;
static const int MIX, BEND_DIRECTION, STRETCH;
static const int PREV_TIME, PREV_MIX, PREV_BEND_DIRECTION, PREV_COMPRESS, PREV_STRETCH;
static const int MIX, BEND_DIRECTION, COMPRESS, STRETCH;
Vector<float> _frames;
int _ikConstraintIndex;

View File

@ -716,10 +716,10 @@ void AnimationState::applyRotateTimeline(RotateTimeline *rotateTimeline, Skeleto
// Mix between rotations using the direction of the shortest route on the first frame while detecting crosses.
float r1 = blend == MixBlend_Setup ? bone->_data._rotation : bone->_rotation;
float total, diff = r2 - r1;
diff -= (16384 - (int) (16384.499999999996 - diff / 360)) * 360;
if (diff == 0) {
total = timelinesRotation[i];
} else {
diff -= (16384 - (int) (16384.499999999996 - diff / 360)) * 360;
float lastTotal, lastDiff;
if (firstFrame) {
lastTotal = 0;

View File

@ -44,7 +44,7 @@ using namespace spine;
RTTI_IMPL(IkConstraint, Constraint)
void IkConstraint::apply(Bone &bone, float targetX, float targetY, bool stretch, float alpha) {
void IkConstraint::apply(Bone &bone, float targetX, float targetY, bool compress, bool stretch, bool uniform, float alpha) {
Bone *p = bone.getParent();
float id, x, y, tx, ty, rotationIK;
if (!bone._appliedValid) bone.updateAppliedTransform();
@ -57,12 +57,17 @@ void IkConstraint::apply(Bone &bone, float targetX, float targetY, bool stretch,
if (rotationIK > 180) rotationIK -= 360;
else if (rotationIK < -180) rotationIK += 360;
float sx = bone._ascaleX;
if (stretch) {
float sy = bone._ascaleY;
if (compress || stretch) {
float b = bone._data.getLength() * sx, dd = MathUtil::sqrt(tx * tx + ty * ty);
if (dd > b && b > 0.0001f) sx *= (dd / b - 1) * alpha + 1;
if ((compress && dd < b) || (stretch && dd > b) && b > 0.0001f) {
float s = (dd / b - 1) * alpha + 1;
sx *= s;
if (uniform) sy *= s;
}
}
bone.updateWorldTransform(bone._ax, bone._ay, bone._arotation + rotationIK * alpha, sx,
bone._ascaleY, bone._ashearX, bone._ashearY);
sy, bone._ashearX, bone._ashearY);
}
void IkConstraint::apply(Bone &parent, Bone &child, float targetX, float targetY, int bendDir, bool stretch, float alpha) {
@ -206,6 +211,7 @@ void IkConstraint::apply(Bone &parent, Bone &child, float targetX, float targetY
IkConstraint::IkConstraint(IkConstraintData &data, Skeleton &skeleton) : Constraint(),
_data(data),
_bendDirection(data.getBendDirection()),
_compress(data.getCompress()),
_stretch(data.getStretch()),
_mix(data.getMix()),
_target(skeleton.findBone(
@ -226,7 +232,7 @@ void IkConstraint::update() {
switch (_bones.size()) {
case 1: {
Bone *bone0 = _bones[0];
apply(*bone0, _target->getWorldX(), _target->getWorldY(), _stretch, _mix);
apply(*bone0, _target->getWorldX(), _target->getWorldY(), _compress, _stretch, _data._uniform, _mix);
}
break;
case 2: {
@ -281,3 +287,11 @@ bool IkConstraint::getStretch() {
void IkConstraint::setStretch(bool inValue) {
_stretch = inValue;
}
bool IkConstraint::getCompress() {
return _compress;
}
void IkConstraint::setCompress(bool inValue) {
_compress = inValue;
}

View File

@ -43,7 +43,9 @@ IkConstraintData::IkConstraintData(const String &name) :
_order(0),
_target(NULL),
_bendDirection(1),
_compress(false),
_stretch(false),
_uniform(false),
_mix(1) {
}
@ -94,3 +96,20 @@ bool IkConstraintData::getStretch() {
void IkConstraintData::setStretch(bool inValue) {
_stretch = inValue;
}
bool IkConstraintData::getCompress() {
return _compress;
}
void IkConstraintData::setCompress(bool inValue) {
_compress = inValue;
}
bool IkConstraintData::getUniform() {
return _uniform;
}
void IkConstraintData::setUniform(bool inValue) {
_uniform = inValue;
}

View File

@ -48,14 +48,16 @@ using namespace spine;
RTTI_IMPL(IkConstraintTimeline, CurveTimeline)
const int IkConstraintTimeline::ENTRIES = 4;
const int IkConstraintTimeline::PREV_TIME = -4;
const int IkConstraintTimeline::PREV_MIX = -3;
const int IkConstraintTimeline::PREV_BEND_DIRECTION = -2;
const int IkConstraintTimeline::ENTRIES = 5;
const int IkConstraintTimeline::PREV_TIME = -5;
const int IkConstraintTimeline::PREV_MIX = -4;
const int IkConstraintTimeline::PREV_BEND_DIRECTION = -3;
const int IkConstraintTimeline::PREV_COMPRESS = -2;
const int IkConstraintTimeline::PREV_STRETCH = -1;
const int IkConstraintTimeline::MIX = 1;
const int IkConstraintTimeline::BEND_DIRECTION = 2;
const int IkConstraintTimeline::STRETCH = 3;
const int IkConstraintTimeline::COMPRESS = 3;
const int IkConstraintTimeline::STRETCH = 4;
IkConstraintTimeline::IkConstraintTimeline(int frameCount) : CurveTimeline(frameCount), _ikConstraintIndex(0) {
_frames.setSize(frameCount * ENTRIES, 0);
@ -73,11 +75,13 @@ void IkConstraintTimeline::apply(Skeleton &skeleton, float lastTime, float time,
case MixBlend_Setup:
constraint._mix = constraint._data._mix;
constraint._bendDirection = constraint._data._bendDirection;
constraint._compress = constraint._data._compress;
constraint._stretch = constraint._data._stretch;
return;
case MixBlend_First:
constraint._mix += (constraint._data._mix - constraint._mix) * alpha;
constraint._bendDirection = constraint._data._bendDirection;
constraint._compress = constraint._data._compress;
constraint._stretch = constraint._data._stretch;
return;
default:
@ -92,15 +96,18 @@ void IkConstraintTimeline::apply(Skeleton &skeleton, float lastTime, float time,
constraint._data._mix + (_frames[_frames.size() + PREV_MIX] - constraint._data._mix) * alpha;
if (direction == MixDirection_Out) {
constraint._bendDirection = constraint._data._bendDirection;
constraint._compress = constraint._data._compress;
constraint._stretch = constraint._data._stretch;
} else {
constraint._bendDirection = (int) _frames[_frames.size() + PREV_BEND_DIRECTION];
constraint._compress = _frames[_frames.size() + PREV_COMPRESS] != 0;
constraint._stretch = _frames[_frames.size() + PREV_STRETCH] != 0;
}
} else {
constraint._mix += (_frames[_frames.size() + PREV_MIX] - constraint._mix) * alpha;
if (direction == MixDirection_In) {
constraint._bendDirection = (int) _frames[_frames.size() + PREV_BEND_DIRECTION];
constraint._compress = _frames[_frames.size() + PREV_COMPRESS] != 0;
constraint._stretch = _frames[_frames.size() + PREV_STRETCH] != 0;
}
}
@ -119,15 +126,18 @@ void IkConstraintTimeline::apply(Skeleton &skeleton, float lastTime, float time,
constraint._data._mix + (mix + (_frames[frame + MIX] - mix) * percent - constraint._data._mix) * alpha;
if (direction == MixDirection_Out) {
constraint._bendDirection = constraint._data._bendDirection;
constraint._compress = constraint._data._compress;
constraint._stretch = constraint._data._stretch;
} else {
constraint._bendDirection = (int) _frames[_frames.size() + PREV_BEND_DIRECTION];
constraint._stretch = _frames[_frames.size() + PREV_STRETCH] != 0;
constraint._compress = _frames[frame + PREV_COMPRESS] != 0;
constraint._stretch = _frames[frame + PREV_STRETCH] != 0;
}
} else {
constraint._mix += (mix + (_frames[frame + MIX] - mix) * percent - constraint._mix) * alpha;
if (direction == MixDirection_In) {
constraint._bendDirection = (int) _frames[frame + PREV_BEND_DIRECTION];
constraint._compress = _frames[frame + PREV_COMPRESS] != 0;
constraint._stretch = _frames[frame + PREV_STRETCH] != 0;
}
}
@ -137,10 +147,11 @@ int IkConstraintTimeline::getPropertyId() {
return ((int) TimelineType_IkConstraint << 24) + _ikConstraintIndex;
}
void IkConstraintTimeline::setFrame(int frameIndex, float time, float mix, int bendDirection, bool stretch) {
void IkConstraintTimeline::setFrame(int frameIndex, float time, float mix, int bendDirection, bool compress, bool stretch) {
frameIndex *= ENTRIES;
_frames[frameIndex] = time;
_frames[frameIndex + MIX] = mix;
_frames[frameIndex + BEND_DIRECTION] = (float)bendDirection;
_frames[frameIndex + COMPRESS] = compress ? 1 : 0;
_frames[frameIndex + STRETCH] = stretch ? 1 : 0;
}

View File

@ -230,6 +230,7 @@ void Skeleton::setBonesToSetupPose() {
IkConstraint &constraint = *constraintP;
constraint._bendDirection = constraint._data._bendDirection;
constraint._compress = constraint._data._compress;
constraint._stretch = constraint._data._stretch;
constraint._mix = constraint._data._mix;
}

View File

@ -203,7 +203,9 @@ SkeletonData *SkeletonBinary::readSkeletonData(const unsigned char *binary, cons
data->_target = skeletonData->_bones[readVarint(input, true)];
data->_mix = readFloat(input);
data->_bendDirection = readSByte(input);
data->_compress = readBoolean(input);
data->_stretch = readBoolean(input);
data->_uniform = readBoolean(input);
skeletonData->_ikConstraints[i] = data;
}
@ -781,8 +783,9 @@ Animation *SkeletonBinary::readAnimation(const String &name, DataInput *input, S
float time = readFloat(input);
float mix = readFloat(input);
signed char bendDirection = readSByte(input);
bool compress = readBoolean(input);
bool stretch = readBoolean(input);
timeline->setFrame(frameIndex, time, mix, bendDirection, stretch);
timeline->setFrame(frameIndex, time, mix, bendDirection, compress, stretch);
if (frameIndex < frameCount - 1) {
readCurve(input, frameIndex, timeline);
}

View File

@ -285,9 +285,11 @@ SkeletonData *SkeletonJson::readSkeletonData(const char *json) {
return NULL;
}
data->_bendDirection = Json::getInt(constraintMap, "bendPositive", 1) ? 1 : -1;
data->_stretch = Json::getInt(constraintMap, "stretch", 0) ? true: false;
data->_mix = Json::getFloat(constraintMap, "mix", 1);
data->_bendDirection = Json::getInt(constraintMap, "bendPositive", 1) ? 1 : -1;
data->_compress = Json::getInt(constraintMap, "compress", 0) ? true: false;
data->_stretch = Json::getInt(constraintMap, "stretch", 0) ? true: false;
data->_uniform = Json::getInt(constraintMap, "uniform", 0) ? true: false;
skeletonData->_ikConstraints[i] = data;
}
@ -932,7 +934,7 @@ Animation *SkeletonJson::readAnimation(Json *root, SkeletonData *skeletonData) {
}
for (valueMap = constraintMap->_child, frameIndex = 0; valueMap; valueMap = valueMap->_next, ++frameIndex) {
timeline->setFrame(frameIndex, Json::getFloat(valueMap, "time", 0), Json::getFloat(valueMap, "mix", 1),
Json::getInt(valueMap, "bendPositive", 1) ? 1 : -1, Json::getInt(valueMap, "stretch", 0) ? true : false);
Json::getInt(valueMap, "bendPositive", 1) ? 1 : -1, Json::getInt(valueMap, "compress", 0) ? true : false, Json::getInt(valueMap, "stretch", 0) ? true : false);
readCurve(valueMap, timeline, frameIndex);
}
timelines.add(timeline);

View File

@ -1210,15 +1210,15 @@ namespace Spine {
}
public class IkConstraintTimeline : CurveTimeline {
public const int ENTRIES = 4;
private const int PREV_TIME = -4, PREV_MIX = -3, PREV_BEND_DIRECTION = -2, PREV_STRETCH = -1;
private const int MIX = 1, BEND_DIRECTION = 2, STRETCH = 3;
public const int ENTRIES = 5;
private const int PREV_TIME = -5, PREV_MIX = -4, PREV_BEND_DIRECTION = -3, PREV_COMPRESS = -2, PREV_STRETCH = -1;
private const int MIX = 1, BEND_DIRECTION = 2, COMPRESS = 3, STRETCH = 4;
internal int ikConstraintIndex;
internal float[] frames;
public int IkConstraintIndex { get { return ikConstraintIndex; } set { ikConstraintIndex = value; } }
public float[] Frames { get { return frames; } set { frames = value; } } // time, mix, bendDirection, ...
public float[] Frames { get { return frames; } set { frames = value; } } // time, mix, bendDirection, compress, stretch ...
override public int PropertyId {
get { return ((int)TimelineType.IkConstraint << 24) + ikConstraintIndex; }
@ -1229,12 +1229,13 @@ namespace Spine {
frames = new float[frameCount * ENTRIES];
}
/// <summary>Sets the time, mix and bend direction of the specified keyframe.</summary>
public void SetFrame (int frameIndex, float time, float mix, int bendDirection, bool stretch) {
/// <summary>Sets the time, mix, bend direction, compress and stretch of the specified keyframe.</summary>
public void SetFrame (int frameIndex, float time, float mix, int bendDirection, bool compress, bool stretch) {
frameIndex *= ENTRIES;
frames[frameIndex] = time;
frames[frameIndex + MIX] = mix;
frames[frameIndex + BEND_DIRECTION] = bendDirection;
frames[frameIndex + COMPRESS] = compress ? 1 : 0;
frames[frameIndex + STRETCH] = stretch ? 1 : 0;
}
@ -1246,11 +1247,13 @@ namespace Spine {
case MixBlend.Setup:
constraint.mix = constraint.data.mix;
constraint.bendDirection = constraint.data.bendDirection;
constraint.compress = constraint.data.compress;
constraint.stretch = constraint.data.stretch;
return;
case MixBlend.First:
constraint.mix += (constraint.data.mix - constraint.mix) * alpha;
constraint.bendDirection = constraint.data.bendDirection;
constraint.compress = constraint.data.compress;
constraint.stretch = constraint.data.stretch;
return;
}
@ -1262,15 +1265,18 @@ namespace Spine {
constraint.mix = constraint.data.mix + (frames[frames.Length + PREV_MIX] - constraint.data.mix) * alpha;
if (direction == MixDirection.Out) {
constraint.bendDirection = constraint.data.bendDirection;
constraint.compress = constraint.data.compress;
constraint.stretch = constraint.data.stretch;
} else {
constraint.bendDirection = (int)frames[frames.Length + PREV_BEND_DIRECTION];
constraint.compress = frames[frames.Length + PREV_COMPRESS] != 0;
constraint.stretch = frames[frames.Length + PREV_STRETCH] != 0;
}
} else {
constraint.mix += (frames[frames.Length + PREV_MIX] - constraint.mix) * alpha;
if (direction == MixDirection.In) {
constraint.bendDirection = (int)frames[frames.Length + PREV_BEND_DIRECTION];
constraint.compress = frames[frames.Length + PREV_COMPRESS] != 0;
constraint.stretch = frames[frames.Length + PREV_STRETCH] != 0;
}
}
@ -1285,10 +1291,22 @@ namespace Spine {
if (blend == MixBlend.Setup) {
constraint.mix = constraint.data.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.data.mix) * alpha;
constraint.bendDirection = direction == MixDirection.Out ? constraint.data.bendDirection : (int)frames[frame + PREV_BEND_DIRECTION];
if (direction == MixDirection.Out) {
constraint.bendDirection = constraint.data.bendDirection;
constraint.compress = constraint.data.compress;
constraint.stretch = constraint.data.stretch;
} else {
constraint.bendDirection = (int)frames[frame + PREV_BEND_DIRECTION];
constraint.compress = frames[frame + PREV_COMPRESS] != 0;
constraint.stretch = frames[frame + PREV_STRETCH] != 0;
}
} else {
constraint.mix += (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha;
if (direction == MixDirection.In) constraint.bendDirection = (int)frames[frame + PREV_BEND_DIRECTION];
if (direction == MixDirection.In) {
constraint.bendDirection = (int)frames[frame + PREV_BEND_DIRECTION];
constraint.compress = frames[frame + PREV_COMPRESS] != 0;
constraint.stretch = frames[frame + PREV_STRETCH] != 0;
}
}
}
}

View File

@ -36,7 +36,7 @@ namespace Spine {
internal ExposedList<Bone> bones = new ExposedList<Bone>();
internal Bone target;
internal int bendDirection;
internal bool stretch;
internal bool compress, stretch;
internal float mix;
public IkConstraintData Data { get { return data; } }
@ -59,9 +59,17 @@ namespace Spine {
set { bendDirection = value; }
}
/// <summary>
/// When true and only a single bone is being constrained,
/// if the target is too close, the bone is scaled to reach it.</summary>
public bool Compress {
get { return compress; }
set { compress = value; }
}
/// <summary>
/// When true, if the target is out of range, the parent bone is scaled on the X axis to reach it.
/// IF the parent bone has nonuniform scale, stretching is not applied.</summary>
/// If the parent bone has nonuniform scale, stretching is not applied.</summary>
public bool Stretch {
get { return stretch; }
set { stretch = value; }
@ -79,6 +87,7 @@ namespace Spine {
this.data = data;
mix = data.mix;
bendDirection = data.bendDirection;
compress = data.compress;
stretch = data.stretch;
bones = new ExposedList<Bone>(data.bones.Count);
@ -97,7 +106,7 @@ namespace Spine {
ExposedList<Bone> bones = this.bones;
switch (bones.Count) {
case 1:
Apply(bones.Items[0], target.worldX, target.worldY, stretch, mix);
Apply(bones.Items[0], target.worldX, target.worldY, compress, stretch, data.uniform, mix);
break;
case 2:
Apply(bones.Items[0], bones.Items[1], target.worldX, target.worldY, bendDirection, stretch, mix);
@ -109,9 +118,8 @@ namespace Spine {
return data.name;
}
/// <summary>Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified
/// in the world coordinate system.</summary>
static public void Apply (Bone bone, float targetX, float targetY, bool stretch, float alpha) {
/// <summary>Applies 1 bone IK. The target is specified in the world coordinate system.</summary>
static public void Apply (Bone bone, float targetX, float targetY, bool compress, bool stretch, bool uniform, float alpha) {
if (!bone.appliedValid) bone.UpdateAppliedTransform();
Bone p = bone.parent;
float id = 1 / (p.a * p.d - p.b * p.c);
@ -121,14 +129,18 @@ namespace Spine {
if (bone.ascaleX < 0) rotationIK += 180;
if (rotationIK > 180)
rotationIK -= 360;
else if (rotationIK < -180)
else if (rotationIK < -180) //
rotationIK += 360;
float sx = bone.ascaleX;
if (stretch) {
float sx = bone.ascaleX, sy = bone.ascaleY;
if (compress || stretch) {
float b = bone.data.length * sx, dd = (float)Math.Sqrt(tx * tx + ty * ty);
if (dd > b && b > 0.0001f) sx *= (dd / b - 1) * alpha + 1;
if ((compress && dd < b) || (stretch && dd > b) && b > 0.0001f) {
float s = (dd / b - 1) * alpha + 1;
sx *= s;
if (uniform) sy *= s;
}
bone.UpdateWorldTransform(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, bone.ascaleY, bone.ashearX,
}
bone.UpdateWorldTransform(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, bone.ashearX,
bone.ashearY);
}

View File

@ -39,7 +39,7 @@ namespace Spine {
internal List<BoneData> bones = new List<BoneData>();
internal BoneData target;
internal int bendDirection = 1;
internal bool stretch;
internal bool compress, stretch, uniform;
internal float mix = 1;
/// <summary>The IK constraint's name, which is unique within the skeleton.</summary>
@ -63,12 +63,27 @@ namespace Spine {
set { target = value; }
}
/// <summary>
/// A percentage (0-1) that controls the mix between the constraint and unconstrained rotations.</summary>
public float Mix {
get { return mix; }
set { mix = value; }
}
/// <summary>Controls the bend direction of the IK bones, either 1 or -1.</summary>
public int BendDirection {
get { return bendDirection; }
set { bendDirection = value; }
}
/// <summary>
/// When true, and only a single bone is being constrained,
/// if the target is too close, the bone is scaled to reach it. </summary>
public bool Compress {
get { return compress; }
set { compress = value; }
}
/// <summary>
/// When true, if the target is out of range, the parent bone is scaled on the X axis to reach it.
/// If the bone has local nonuniform scale, stretching is not applied.</summary>
@ -77,7 +92,13 @@ namespace Spine {
set { stretch = value; }
}
public float Mix { get { return mix; } set { mix = value; } }
/// <summary>
/// When true, only a single bone is being constrained and Compress or Stretch is used,
/// the bone is scaled both on the X and Y axes.</summary>
public bool Uniform {
get { return uniform; }
set { uniform = value; }
}
public IkConstraintData (string name) {
if (name == null) throw new ArgumentNullException("name", "name cannot be null.");

View File

@ -308,9 +308,10 @@ namespace Spine {
var ikConstraintsItems = this.ikConstraints.Items;
for (int i = 0, n = ikConstraints.Count; i < n; i++) {
IkConstraint constraint = ikConstraintsItems[i];
constraint.bendDirection = constraint.data.bendDirection;
constraint.stretch = constraint.data.stretch;
constraint.mix = constraint.data.mix;
constraint.bendDirection = constraint.data.bendDirection;
constraint.compress = constraint.data.compress;
constraint.stretch = constraint.data.stretch;
}
var transformConstraintsItems = this.transformConstraints.Items;

View File

@ -210,7 +210,9 @@ namespace Spine {
data.target = skeletonData.bones.Items[ReadVarint(input, true)];
data.mix = ReadFloat(input);
data.bendDirection = ReadSByte(input);
data.compress = ReadBoolean(input);
data.stretch = ReadBoolean(input);
data.uniform = ReadBoolean(input);
skeletonData.ikConstraints.Add(data);
}
@ -646,10 +648,11 @@ namespace Spine {
for (int i = 0, n = ReadVarint(input, true); i < n; i++) {
int index = ReadVarint(input, true);
int frameCount = ReadVarint(input, true);
IkConstraintTimeline timeline = new IkConstraintTimeline(frameCount);
timeline.ikConstraintIndex = index;
IkConstraintTimeline timeline = new IkConstraintTimeline(frameCount) {
ikConstraintIndex = index
};
for (int frameIndex = 0; frameIndex < frameCount; frameIndex++) {
timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input), ReadSByte(input), ReadBoolean(input));
timeline.SetFrame(frameIndex, ReadFloat(input), ReadFloat(input), ReadSByte(input), ReadBoolean(input), ReadBoolean(input));
if (frameIndex < frameCount - 1) ReadCurve(input, frameIndex, timeline);
}
timelines.Add(timeline);

View File

@ -180,10 +180,11 @@ namespace Spine {
string targetName = (string)constraintMap["target"];
data.target = skeletonData.FindBone(targetName);
if (data.target == null) throw new Exception("Target bone not found: " + targetName);
data.bendDirection = GetBoolean(constraintMap, "bendPositive", true) ? 1 : -1;
data.stretch = GetBoolean(constraintMap, "stretch", false);
data.mix = GetFloat(constraintMap, "mix", 1);
data.bendDirection = GetBoolean(constraintMap, "bendPositive", true) ? 1 : -1;
data.compress = GetBoolean(constraintMap, "compress", false);
data.stretch = GetBoolean(constraintMap, "stretch", false);
data.uniform = GetBoolean(constraintMap, "uniform", false);
skeletonData.ikConstraints.Add(data);
}
@ -595,11 +596,14 @@ namespace Spine {
timeline.ikConstraintIndex = skeletonData.ikConstraints.IndexOf(constraint);
int frameIndex = 0;
foreach (Dictionary<string, Object> valueMap in values) {
float time = (float)valueMap["time"];
float mix = GetFloat(valueMap, "mix", 1);
bool bendPositive = GetBoolean(valueMap, "bendPositive", true);
bool stretch = GetBoolean(valueMap, "stretch", false);
timeline.SetFrame(frameIndex, time, mix, bendPositive ? 1 : -1, stretch);
timeline.SetFrame(
frameIndex,
(float)valueMap["time"],
GetFloat(valueMap, "mix", 1),
GetBoolean(valueMap, "bendPositive", true) ? 1 : -1,
GetBoolean(valueMap, "compress", true),
GetBoolean(valueMap, "stretch", false)
);
ReadCurve(valueMap, timeline, frameIndex);
frameIndex++;
}

View File

@ -1169,19 +1169,21 @@ function Animation.DrawOrderTimeline.new (frameCount)
end
Animation.IkConstraintTimeline = {}
Animation.IkConstraintTimeline.ENTRIES = 4
Animation.IkConstraintTimeline.ENTRIES = 5
function Animation.IkConstraintTimeline.new (frameCount)
local ENTRIES = Animation.IkConstraintTimeline.ENTRIES
local PREV_TIME = -4
local PREV_MIX = -3
local PREV_BEND_DIRECTION = -2
local PREV_TIME = -5
local PREV_MIX = -4
local PREV_BEND_DIRECTION = -3
local PREV_COMPRESS = -2
local PREV_STRETCH = -1
local MIX = 1
local BEND_DIRECTION = 2
local COMPRESS = 3
local STRETCH = 1
local self = Animation.CurveTimeline.new(frameCount)
self.frames = utils.newNumberArrayZero(frameCount * ENTRIES) -- time, mix, bendDirection, ...
self.frames = utils.newNumberArrayZero(frameCount * ENTRIES) -- time, mix, bendDirection, compress, stretch, ...
self.ikConstraintIndex = -1
self.type = TimelineType.ikConstraint
@ -1189,11 +1191,16 @@ function Animation.IkConstraintTimeline.new (frameCount)
return TimelineType.ikConstraint * SHL_24 + self.ikConstraintIndex
end
function self:setFrame (frameIndex, time, mix, bendDirection, stretch)
function self:setFrame (frameIndex, time, mix, bendDirection, compress, stretch)
frameIndex = frameIndex * ENTRIES
self.frames[frameIndex] = time
self.frames[frameIndex + MIX] = mix
self.frames[frameIndex + BEND_DIRECTION] = bendDirection
if (compress) then
self.frames[frameIndex + COMPRESS] = 1
else
self.frames[frameIndex + COMPRESS] = 0
end
if (stretch) then
self.frames[frameIndex + STRETCH] = 1
else
@ -1209,10 +1216,12 @@ function Animation.IkConstraintTimeline.new (frameCount)
if blend == MixBlend.setup then
constraint.mix = constraint.data.mix
constraint.bendDirection = constraint.data.bendDirection
constraint.compress = constraint.data.compress
constraint.stretch = constraint.data.stretch
elseif blend == MixBlend.first then
constraint.mix = constraint.mix + (constraint.data.mix - constraint.mix) * alpha
constraint.bendDirection = constraint.data.bendDirection
constraint.compress = constraint.data.compress
constraint.stretch = constraint.data.stretch
end
return
@ -1223,15 +1232,18 @@ function Animation.IkConstraintTimeline.new (frameCount)
constraint.mix = constraint.data.mix + (frames[zlen(frames) + PREV_MIX] - constraint.data.mix) * alpha
if direction == MixDirection.out then
constraint.bendDirection = constraint.data.bendDirection
constraint.compress = constraint.data.compress
constraint.stretch = constraint.data.stretch
else
constraint.bendDirection = math_floor(frames[zlen(frames) + PREV_BEND_DIRECTION]);
if (math_floor(frames[zlen(frames) + PREV_COMPRESS]) == 1) then constraint.compress = true else constraint.compress = false end
if (math_floor(frames[zlen(frames) + PREV_STRETCH]) == 1) then constraint.stretch = true else constraint.stretch = false end
end
else
constraint.mix = constraint.mix + (frames[frames.length + PREV_MIX] - constraint.mix) * alpha;
if direction == MixDirection._in then
constraint.bendDirection = math_floor(frames[zlen(frames) + PREV_BEND_DIRECTION])
if (math_floor(frames[zlen(frames) + PREV_COMPRES]) == 1) then constraint.compress = true else constraint.compress = false end
if (math_floor(frames[zlen(frames) + PREV_STRETCH]) == 1) then constraint.stretch = true else constraint.stretch = false end
end
end
@ -1249,15 +1261,18 @@ function Animation.IkConstraintTimeline.new (frameCount)
constraint.mix = constraint.data.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.data.mix) * alpha
if direction == MixDirection.out then
constraint.bendDirection = constraint.data.bendDirection
constraint.compress = constraint.data.compress
constraint.stretch = constraint.data.stretch
else
constraint.bendDirection = math_floor(frames[frame + PREV_BEND_DIRECTION])
if (math_floor(frames[frame + PREV_COMPRESS]) == 1) then constraint.compress = true else constraint.compress = false end
if (math_floor(frames[frame + PREV_STRETCH]) == 1) then constraint.stretch = true else constraint.stretch = false end
end
else
constraint.mix = constraint.mix + (mix + (frames[frame + MIX] - mix) * percent - constraint.mix) * alpha;
if direction == MixDirection._in then
constraint.bendDirection = math_floor(frames[frame + PREV_BEND_DIRECTION])
if (math_floor(frames[frame + PREV_COMPRESS]) == 1) then constraint.compress = true else constraint.compress = false end
if (math_floor(frames[frame + PREV_STRETCH]) == 1) then constraint.stretch = true else constraint.stretch = false end
end
end

View File

@ -543,10 +543,10 @@ function AnimationState:applyRotateTimeline (timeline, skeleton, time, alpha, bl
if blend == MixBlend.setup then r1 = bone.data.rotation end
local total = 0
local diff = r2 - r1
diff = diff - (16384 - math_floor(16384.499999999996 - diff / 360)) * 360
if diff == 0 then
total = timelinesRotation[i]
else
diff = diff - (16384 - math_floor(16384.499999999996 - diff / 360)) * 360
local lastTotal = 0
local lastDiff = 0
if firstFrame then

View File

@ -52,6 +52,7 @@ function IkConstraint.new (data, skeleton)
bones = {},
target = nil,
mix = data.mix,
compress = data.compress,
stretch = data.stretch,
bendDirection = data.bendDirection,
}
@ -75,13 +76,13 @@ function IkConstraint:update ()
local bones = self.bones
local boneCount = #bones
if boneCount == 1 then
self:apply1(bones[1], target.worldX, target.worldY, self.stretch, self.mix)
self:apply1(bones[1], target.worldX, target.worldY, self.compress, self.stretch, self.data.uniform, self.mix)
elseif boneCount == 2 then
self:apply2(bones[1], bones[2], target.worldX, target.worldY, self.bendDirection, self.stretch, self.mix)
end
end
function IkConstraint:apply1 (bone, targetX, targetY, stretch, alpha)
function IkConstraint:apply1 (bone, targetX, targetY, compress, stretch, uniform, alpha)
if not bone.appliedValid then bone:updateAppliedTransform() end
local p = bone.parent
local id = 1 / (p.a * p.d - p.b * p.c)
@ -97,11 +98,17 @@ function IkConstraint:apply1 (bone, targetX, targetY, stretch, alpha)
rotationIK = rotationIK + 360
end
local sx = bone.ascaleX
if stretch then
local sy = bone.ascaleY
if compress or stretch then
local b = bone.data.length * sx
local dd = math_sqrt(tx * tx + ty * ty)
if dd > bone.data.length * sx then sx = sx * ((dd / (bone.data.length * sx) - 1) * alpha + 1) end
if (compress and dd < b) or (stretch and dd > b) and b > 0.0001 then
local s = (dd / b - 1) * alpha + 1
sx = sx * s
if uniform then sy = sy * s end
end
bone:updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, bone.ascaleY, bone.ashearX, bone.ashearY)
end
bone:updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, bone.ashearX, bone.ashearY)
end
function IkConstraint:apply2 (parent, child, targetX, targetY, bendDir, stretch, alpha)

View File

@ -38,7 +38,9 @@ function IkConstraintData.new (name)
bones = {},
target = nil,
bendDirection = 1,
compress = false,
stretch = false,
uniform = false,
mix = 1
}

View File

@ -338,9 +338,10 @@ function Skeleton:setBonesToSetupPose ()
end
for _,ikConstraint in ipairs(self.ikConstraints) do
ikConstraint.bendDirection = ikConstraint.data.bendDirection
ikConstraint.stretch = ikConstraint.data.stretch
ikConstraint.mix = ikConstraint.data.mix
ikConstraint.bendDirection = ikConstraint.data.bendDirection
ikConstraint.compress = ikConstraint.data.compress
ikConstraint.stretch = ikConstraint.data.stretch
end
local transformConstraints = self.transformConstraints

View File

@ -164,9 +164,11 @@ function SkeletonJson.new (attachmentLoader)
data.target = skeletonData:findBone(targetName)
if not data.target then error("Target bone not found: " .. targetName) end
if constraintMap["bendPositive"] == false then data.bendDirection = -1 else data.bendDirection = 1 end
if constraintMap["stretch"] == false then data.stretch = false else data.stretch = true end
data.mix = getValue(constraintMap, "mix", 1)
if constraintMap["bendPositive"] == nil or constraintMap["bendPositive"] == false then data.bendDirection = -1 else data.bendDirection = 1 end
if constraintMap["compress"] == nil or constraintMap["compress"] == false then data.compress = false else data.compress = true end
if constraintMap["stretch"] == nil or constraintMap["stretch"] == false then data.stretch = false else data.stretch = true end
if constraintMap["uniform"] == nil or constraintMap["uniform"] == false then data.uniform = false else data.uniform = true end
table_insert(skeletonData.ikConstraints, data)
end
@ -613,9 +615,11 @@ function SkeletonJson.new (attachmentLoader)
if valueMap["mix"] ~= nil then mix = valueMap["mix"] end
local bendPositive = 1
if valueMap["bendPositive"] == false then bendPositive = -1 end
local stretch = true
if valueMap["stretch"] == false then stretch = false end
timeline:setFrame(frameIndex, valueMap["time"], mix, bendPositive, stretch)
local stretch = false
if valueMap["stretch"] ~= nil then stretch = valueMap["stretch"] end
local compress = false
if valueMap["compress"] ~= nil then compress = valueMap["compress"] end
timeline:setFrame(frameIndex, valueMap["time"], mix, bendPositive, compress, stretch)
readCurve(valueMap, timeline, frameIndex)
frameIndex = frameIndex + 1
end

View File

@ -16,11 +16,11 @@ declare module spine {
setup = 0,
first = 1,
replace = 2,
add = 3
add = 3,
}
enum MixDirection {
in = 0,
out = 1
out = 1,
}
enum TimelineType {
rotate = 0,
@ -37,7 +37,7 @@ declare module spine {
pathConstraintPosition = 11,
pathConstraintSpacing = 12,
pathConstraintMix = 13,
twoColor = 14
twoColor = 14,
}
abstract class CurveTimeline implements Timeline {
static LINEAR: number;
@ -176,15 +176,17 @@ declare module spine {
static PREV_TIME: number;
static PREV_MIX: number;
static PREV_BEND_DIRECTION: number;
static PREV_COMPRESS: number;
static PREV_STRETCH: number;
static MIX: number;
static BEND_DIRECTION: number;
static COMPRESS: number;
static STRETCH: number;
ikConstraintIndex: number;
frames: ArrayLike<number>;
constructor(frameCount: number);
getPropertyId(): number;
setFrame(frameIndex: number, time: number, mix: number, bendDirection: number, stretch: boolean): void;
setFrame(frameIndex: number, time: number, mix: number, bendDirection: number, compress: boolean, stretch: boolean): void;
apply(skeleton: Skeleton, lastTime: number, time: number, firedEvents: Array<Event>, alpha: number, blend: MixBlend, direction: MixDirection): void;
}
class TransformConstraintTimeline extends CurveTimeline {
@ -338,7 +340,7 @@ declare module spine {
end = 2,
dispose = 3,
complete = 4,
event = 5
event = 5,
}
interface AnimationStateListener2 {
start(entry: TrackEntry): void;
@ -377,8 +379,8 @@ declare module spine {
private toLoad;
private loaded;
constructor(textureLoader: (image: HTMLImageElement) => any, pathPrefix?: string);
private static downloadText;
private static downloadBinary;
private static downloadText(url, success, error);
private static downloadBinary(url, success, error);
loadText(path: string, success?: (path: string, text: string) => void, error?: (path: string, error: string) => void): void;
loadTexture(path: string, success?: (path: string, image: HTMLImageElement) => void, error?: (path: string, error: string) => void): void;
loadTextureData(path: string, data: string, success?: (path: string, image: HTMLImageElement) => void, error?: (path: string, error: string) => void): void;
@ -411,7 +413,7 @@ declare module spine {
Normal = 0,
Additive = 1,
Multiply = 2,
Screen = 3
Screen = 3,
}
}
declare module spine {
@ -480,7 +482,7 @@ declare module spine {
OnlyTranslation = 1,
NoRotationOrReflection = 2,
NoScale = 3,
NoScaleOrReflection = 4
NoScaleOrReflection = 4,
}
}
declare module spine {
@ -513,13 +515,14 @@ declare module spine {
bones: Array<Bone>;
target: Bone;
bendDirection: number;
compress: boolean;
stretch: boolean;
mix: number;
constructor(data: IkConstraintData, skeleton: Skeleton);
getOrder(): number;
apply(): void;
update(): void;
apply1(bone: Bone, targetX: number, targetY: number, stretch: boolean, alpha: number): void;
apply1(bone: Bone, targetX: number, targetY: number, compress: boolean, stretch: boolean, uniform: boolean, alpha: number): void;
apply2(parent: Bone, child: Bone, targetX: number, targetY: number, bendDir: number, stretch: boolean, alpha: number): void;
}
}
@ -530,7 +533,9 @@ declare module spine {
bones: BoneData[];
target: BoneData;
bendDirection: number;
compress: boolean;
stretch: boolean;
uniform: boolean;
mix: number;
constructor(name: string);
}
@ -582,17 +587,17 @@ declare module spine {
}
enum PositionMode {
Fixed = 0,
Percent = 1
Percent = 1,
}
enum SpacingMode {
Length = 0,
Fixed = 1,
Percent = 2
Percent = 2,
}
enum RotateMode {
Tangent = 0,
Chain = 1,
ChainScale = 2
ChainScale = 2,
}
}
declare module spine {
@ -603,12 +608,12 @@ declare module spine {
private rawAssets;
private errors;
constructor(pathPrefix?: string);
private queueAsset;
private queueAsset(clientId, textureLoader, path);
loadText(clientId: string, path: string): void;
loadJson(clientId: string, path: string): void;
loadTexture(clientId: string, textureLoader: (image: HTMLImageElement) => any, path: string): void;
get(clientId: string, path: string): any;
private updateClientAssets;
private updateClientAssets(clientAssets);
isLoadingComplete(clientId: string): boolean;
dispose(): void;
hasErrors(): boolean;
@ -812,12 +817,12 @@ declare module spine {
MipMapNearestNearest = 9984,
MipMapLinearNearest = 9985,
MipMapNearestLinear = 9986,
MipMapLinearLinear = 9987
MipMapLinearLinear = 9987,
}
enum TextureWrap {
MirroredRepeat = 33648,
ClampToEdge = 33071,
Repeat = 10497
Repeat = 10497,
}
class TextureRegion {
renderObject: any;
@ -844,7 +849,7 @@ declare module spine {
pages: TextureAtlasPage[];
regions: TextureAtlasRegion[];
constructor(atlasText: string, textureLoader: (path: string) => any);
private load;
private load(atlasText, textureLoader);
findRegion(name: string): TextureAtlasRegion;
dispose(): void;
}
@ -920,9 +925,9 @@ declare module spine {
private polygonIndicesPool;
triangulate(verticesArray: ArrayLike<number>): Array<number>;
decompose(verticesArray: Array<number>, triangles: Array<number>): Array<Array<number>>;
private static isConcave;
private static positiveArea;
private static winding;
private static isConcave(index, vertexCount, vertices, indices);
private static positiveArea(p1x, p1y, p2x, p2y, p3x, p3y);
private static winding(p1x, p1y, p2x, p2y, p3x, p3y);
}
}
declare module spine {
@ -1094,7 +1099,7 @@ declare module spine {
Mesh = 2,
LinkedMesh = 3,
Path = 4,
Point = 5
Point = 5,
}
}
declare module spine {
@ -1288,7 +1293,7 @@ declare module spine.webgl {
touchesPool: Pool<Touch>;
private listeners;
constructor(element: HTMLElement);
private setupCallbacks;
private setupCallbacks(element);
addListener(listener: InputListener): void;
removeListener(listener: InputListener): void;
}
@ -1397,7 +1402,7 @@ declare module spine.webgl {
drawWithOffset(shader: Shader, primitiveType: number, offset: number, count: number): void;
bind(shader: Shader): void;
unbind(shader: Shader): void;
private update;
private update();
restore(): void;
dispose(): void;
}
@ -1423,7 +1428,7 @@ declare module spine.webgl {
constructor();
}
enum VertexAttributeType {
Float = 0
Float = 0,
}
}
declare module spine.webgl {
@ -1442,7 +1447,7 @@ declare module spine.webgl {
begin(shader: Shader): void;
setBlendMode(srcBlend: number, dstBlend: number): void;
draw(texture: GLTexture, vertices: ArrayLike<number>, indices: Array<number>): void;
private flush;
private flush();
end(): void;
getDrawCalls(): number;
dispose(): void;
@ -1482,13 +1487,13 @@ declare module spine.webgl {
curve(x1: number, y1: number, cx1: number, cy1: number, cx2: number, cy2: number, x2: number, y2: number, segments: number, color?: Color): void;
end(): void;
resize(resizeMode: ResizeMode): void;
private enableRenderer;
private enableRenderer(renderer);
dispose(): void;
}
enum ResizeMode {
Stretch = 0,
Expand = 1,
Fit = 2
Fit = 2,
}
}
declare module spine.webgl {
@ -1516,9 +1521,9 @@ declare module spine.webgl {
getVertexShaderSource(): string;
getFragmentSource(): string;
constructor(context: ManagedWebGLRenderingContext | WebGLRenderingContext, vertexShader: string, fragmentShader: string);
private compile;
private compileShader;
private compileProgram;
private compile();
private compileShader(type, source);
private compileProgram(vs, fs);
restore(): void;
bind(): void;
unbind(): void;
@ -1565,16 +1570,16 @@ declare module spine.webgl {
polygon(polygonVertices: ArrayLike<number>, offset: number, count: number, color?: Color): void;
circle(filled: boolean, x: number, y: number, radius: number, color?: Color, segments?: number): void;
curve(x1: number, y1: number, cx1: number, cy1: number, cx2: number, cy2: number, x2: number, y2: number, segments: number, color?: Color): void;
private vertex;
private vertex(x, y, color);
end(): void;
private flush;
private check;
private flush();
private check(shapeType, numVertices);
dispose(): void;
}
enum ShapeType {
Point = 0,
Line = 1,
Filled = 4
Filled = 4,
}
}
declare module spine.webgl {

View File

@ -1,10 +1,7 @@
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
var extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
}
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
@ -968,11 +965,12 @@ var spine;
IkConstraintTimeline.prototype.getPropertyId = function () {
return (TimelineType.ikConstraint << 24) + this.ikConstraintIndex;
};
IkConstraintTimeline.prototype.setFrame = function (frameIndex, time, mix, bendDirection, stretch) {
IkConstraintTimeline.prototype.setFrame = function (frameIndex, time, mix, bendDirection, compress, stretch) {
frameIndex *= IkConstraintTimeline.ENTRIES;
this.frames[frameIndex] = time;
this.frames[frameIndex + IkConstraintTimeline.MIX] = mix;
this.frames[frameIndex + IkConstraintTimeline.BEND_DIRECTION] = bendDirection;
this.frames[frameIndex + IkConstraintTimeline.COMPRESS] = compress ? 1 : 0;
this.frames[frameIndex + IkConstraintTimeline.STRETCH] = stretch ? 1 : 0;
};
IkConstraintTimeline.prototype.apply = function (skeleton, lastTime, time, firedEvents, alpha, blend, direction) {
@ -983,11 +981,13 @@ var spine;
case MixBlend.setup:
constraint.mix = constraint.data.mix;
constraint.bendDirection = constraint.data.bendDirection;
constraint.compress = constraint.data.compress;
constraint.stretch = constraint.data.stretch;
return;
case MixBlend.first:
constraint.mix += (constraint.data.mix - constraint.mix) * alpha;
constraint.bendDirection = constraint.data.bendDirection;
constraint.compress = constraint.data.compress;
constraint.stretch = constraint.data.stretch;
}
return;
@ -997,10 +997,12 @@ var spine;
constraint.mix = constraint.data.mix + (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.data.mix) * alpha;
if (direction == MixDirection.out) {
constraint.bendDirection = constraint.data.bendDirection;
constraint.compress = constraint.data.compress;
constraint.stretch = constraint.data.stretch;
}
else {
constraint.bendDirection = frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION];
constraint.compress = frames[frames.length + IkConstraintTimeline.PREV_COMPRESS] != 0;
constraint.stretch = frames[frames.length + IkConstraintTimeline.PREV_STRETCH] != 0;
}
}
@ -1008,6 +1010,7 @@ var spine;
constraint.mix += (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.mix) * alpha;
if (direction == MixDirection["in"]) {
constraint.bendDirection = frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION];
constraint.compress = frames[frames.length + IkConstraintTimeline.PREV_COMPRESS] != 0;
constraint.stretch = frames[frames.length + IkConstraintTimeline.PREV_STRETCH] != 0;
}
}
@ -1021,10 +1024,12 @@ var spine;
constraint.mix = constraint.data.mix + (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.data.mix) * alpha;
if (direction == MixDirection.out) {
constraint.bendDirection = constraint.data.bendDirection;
constraint.compress = constraint.data.compress;
constraint.stretch = constraint.data.stretch;
}
else {
constraint.bendDirection = frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION];
constraint.compress = frames[frame + IkConstraintTimeline.PREV_COMPRESS] != 0;
constraint.stretch = frames[frame + IkConstraintTimeline.PREV_STRETCH] != 0;
}
}
@ -1032,18 +1037,21 @@ var spine;
constraint.mix += (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.mix) * alpha;
if (direction == MixDirection["in"]) {
constraint.bendDirection = frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION];
constraint.compress = frames[frame + IkConstraintTimeline.PREV_COMPRESS] != 0;
constraint.stretch = frames[frame + IkConstraintTimeline.PREV_STRETCH] != 0;
}
}
};
IkConstraintTimeline.ENTRIES = 4;
IkConstraintTimeline.PREV_TIME = -4;
IkConstraintTimeline.PREV_MIX = -3;
IkConstraintTimeline.PREV_BEND_DIRECTION = -2;
IkConstraintTimeline.ENTRIES = 5;
IkConstraintTimeline.PREV_TIME = -5;
IkConstraintTimeline.PREV_MIX = -4;
IkConstraintTimeline.PREV_BEND_DIRECTION = -3;
IkConstraintTimeline.PREV_COMPRESS = -2;
IkConstraintTimeline.PREV_STRETCH = -1;
IkConstraintTimeline.MIX = 1;
IkConstraintTimeline.BEND_DIRECTION = 2;
IkConstraintTimeline.STRETCH = 3;
IkConstraintTimeline.COMPRESS = 3;
IkConstraintTimeline.STRETCH = 4;
return IkConstraintTimeline;
}(CurveTimeline));
spine.IkConstraintTimeline = IkConstraintTimeline;
@ -1530,11 +1538,11 @@ var spine;
}
var r1 = blend == spine.MixBlend.setup ? bone.data.rotation : bone.rotation;
var total = 0, diff = r2 - r1;
diff -= (16384 - ((16384.499999999996 - diff / 360) | 0)) * 360;
if (diff == 0) {
total = timelinesRotation[i];
}
else {
diff -= (16384 - ((16384.499999999996 - diff / 360) | 0)) * 360;
var lastTotal = 0, lastDiff = 0;
if (firstFrame) {
lastTotal = 0;
@ -2634,6 +2642,7 @@ var spine;
var IkConstraint = (function () {
function IkConstraint(data, skeleton) {
this.bendDirection = 0;
this.compress = false;
this.stretch = false;
this.mix = 1;
if (data == null)
@ -2643,6 +2652,7 @@ var spine;
this.data = data;
this.mix = data.mix;
this.bendDirection = data.bendDirection;
this.compress = data.compress;
this.stretch = data.stretch;
this.bones = new Array();
for (var i = 0; i < data.bones.length; i++)
@ -2660,14 +2670,14 @@ var spine;
var bones = this.bones;
switch (bones.length) {
case 1:
this.apply1(bones[0], target.worldX, target.worldY, this.stretch, this.mix);
this.apply1(bones[0], target.worldX, target.worldY, this.compress, this.stretch, this.data.uniform, this.mix);
break;
case 2:
this.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.stretch, this.mix);
break;
}
};
IkConstraint.prototype.apply1 = function (bone, targetX, targetY, stretch, alpha) {
IkConstraint.prototype.apply1 = function (bone, targetX, targetY, compress, stretch, uniform, alpha) {
if (!bone.appliedValid)
bone.updateAppliedTransform();
var p = bone.parent;
@ -2681,13 +2691,17 @@ var spine;
rotationIK -= 360;
else if (rotationIK < -180)
rotationIK += 360;
var sx = bone.ascaleX;
if (stretch) {
var sx = bone.ascaleX, sy = bone.ascaleY;
if (compress || stretch) {
var b = bone.data.length * sx, dd = Math.sqrt(tx * tx + ty * ty);
if (dd > b && b > 0.0001)
sx *= (dd / b - 1) * alpha + 1;
if ((compress && dd < b) || (stretch && dd > b) && b > 0.0001) {
var s = (dd / b - 1) * alpha + 1;
sx *= s;
if (uniform)
sy *= s;
}
bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, bone.ascaleY, bone.ashearX, bone.ashearY);
}
bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, bone.ashearX, bone.ashearY);
};
IkConstraint.prototype.apply2 = function (parent, child, targetX, targetY, bendDir, stretch, alpha) {
if (alpha == 0) {
@ -2835,7 +2849,9 @@ var spine;
this.order = 0;
this.bones = new Array();
this.bendDirection = 1;
this.compress = false;
this.stretch = false;
this.uniform = false;
this.mix = 1;
this.name = name;
}
@ -3620,9 +3636,10 @@ var spine;
var ikConstraints = this.ikConstraints;
for (var i = 0, n = ikConstraints.length; i < n; i++) {
var constraint = ikConstraints[i];
constraint.bendDirection = constraint.data.bendDirection;
constraint.stretch = constraint.data.stretch;
constraint.mix = constraint.data.mix;
constraint.bendDirection = constraint.data.bendDirection;
constraint.compress = constraint.data.compress;
constraint.stretch = constraint.data.stretch;
}
var transformConstraints = this.transformConstraints;
for (var i = 0, n = transformConstraints.length; i < n; i++) {
@ -4490,9 +4507,11 @@ var spine;
data.target = skeletonData.findBone(targetName);
if (data.target == null)
throw new Error("IK target bone not found: " + targetName);
data.bendDirection = this.getValue(constraintMap, "bendPositive", true) ? 1 : -1;
data.stretch = this.getValue(constraintMap, "stretch", false);
data.mix = this.getValue(constraintMap, "mix", 1);
data.bendDirection = this.getValue(constraintMap, "bendPositive", true) ? 1 : -1;
data.compress = this.getValue(constraintMap, "compress", false);
data.stretch = this.getValue(constraintMap, "stretch", false);
data.uniform = this.getValue(constraintMap, "uniform", false);
skeletonData.ikConstraints.push(data);
}
}
@ -4862,7 +4881,7 @@ var spine;
var frameIndex = 0;
for (var i = 0; i < constraintMap.length; i++) {
var valueMap = constraintMap[i];
timeline.setFrame(frameIndex, valueMap.time, this.getValue(valueMap, "mix", 1), this.getValue(valueMap, "bendPositive", true) ? 1 : -1, this.getValue(valueMap, "stretch", false));
timeline.setFrame(frameIndex, valueMap.time, this.getValue(valueMap, "mix", 1), this.getValue(valueMap, "bendPositive", true) ? 1 : -1, this.getValue(valueMap, "compress", false), this.getValue(valueMap, "stretch", false));
this.readCurve(valueMap, timeline, frameIndex);
frameIndex++;
}

File diff suppressed because one or more lines are too long

View File

@ -1037,12 +1037,12 @@ module spine {
}
export class IkConstraintTimeline extends CurveTimeline {
static ENTRIES = 4;
static PREV_TIME = -4; static PREV_MIX = -3; static PREV_BEND_DIRECTION = -2; static PREV_STRETCH = -1;
static MIX = 1; static BEND_DIRECTION = 2; static STRETCH = 3;
static ENTRIES = 5;
static PREV_TIME = -5; static PREV_MIX = -4; static PREV_BEND_DIRECTION = -3; static PREV_COMPRESS = -2; static PREV_STRETCH = -1;
static MIX = 1; static BEND_DIRECTION = 2; static COMPRESS = 3; static STRETCH = 4;
ikConstraintIndex: number;
frames: ArrayLike<number>; // time, mix, bendDirection, ...
frames: ArrayLike<number>; // time, mix, bendDirection, compress, stretch, ...
constructor (frameCount: number) {
super(frameCount);
@ -1054,11 +1054,12 @@ module spine {
}
/** Sets the time, mix and bend direction of the specified keyframe. */
setFrame (frameIndex: number, time: number, mix: number, bendDirection: number, stretch: boolean) {
setFrame (frameIndex: number, time: number, mix: number, bendDirection: number, compress: boolean, stretch: boolean) {
frameIndex *= IkConstraintTimeline.ENTRIES;
this.frames[frameIndex] = time;
this.frames[frameIndex + IkConstraintTimeline.MIX] = mix;
this.frames[frameIndex + IkConstraintTimeline.BEND_DIRECTION] = bendDirection;
this.frames[frameIndex + IkConstraintTimeline.COMPRESS] = compress ? 1 : 0;
this.frames[frameIndex + IkConstraintTimeline.STRETCH] = stretch ? 1 : 0;
}
@ -1070,11 +1071,13 @@ module spine {
case MixBlend.setup:
constraint.mix = constraint.data.mix;
constraint.bendDirection = constraint.data.bendDirection;
constraint.compress = constraint.data.compress;
constraint.stretch = constraint.data.stretch;
return;
case MixBlend.first:
constraint.mix += (constraint.data.mix - constraint.mix) * alpha;
constraint.bendDirection = constraint.data.bendDirection;
constraint.compress = constraint.data.compress;
constraint.stretch = constraint.data.stretch;
}
return;
@ -1085,15 +1088,18 @@ module spine {
constraint.mix = constraint.data.mix + (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.data.mix) * alpha;
if (direction == MixDirection.out) {
constraint.bendDirection = constraint.data.bendDirection;
constraint.compress = constraint.data.compress;
constraint.stretch = constraint.data.stretch;
} else {
constraint.bendDirection = frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION]
constraint.compress = frames[frames.length + IkConstraintTimeline.PREV_COMPRESS] != 0;
constraint.stretch = frames[frames.length + IkConstraintTimeline.PREV_STRETCH] != 0;
}
} else {
constraint.mix += (frames[frames.length + IkConstraintTimeline.PREV_MIX] - constraint.mix) * alpha;
if (direction == MixDirection.in) {
constraint.bendDirection = frames[frames.length + IkConstraintTimeline.PREV_BEND_DIRECTION];
constraint.compress = frames[frames.length + IkConstraintTimeline.PREV_COMPRESS] != 0;
constraint.stretch = frames[frames.length + IkConstraintTimeline.PREV_STRETCH] != 0;
}
}
@ -1111,15 +1117,18 @@ module spine {
constraint.mix = constraint.data.mix + (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.data.mix) * alpha;
if (direction == MixDirection.out) {
constraint.bendDirection = constraint.data.bendDirection;
constraint.compress = constraint.data.compress;
constraint.stretch = constraint.data.stretch;
} else {
constraint.bendDirection = frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION];
constraint.compress = frames[frame + IkConstraintTimeline.PREV_COMPRESS] != 0;
constraint.stretch = frames[frame + IkConstraintTimeline.PREV_STRETCH] != 0;
}
} else {
constraint.mix += (mix + (frames[frame + IkConstraintTimeline.MIX] - mix) * percent - constraint.mix) * alpha;
if (direction == MixDirection.in) {
constraint.bendDirection = frames[frame + IkConstraintTimeline.PREV_BEND_DIRECTION];
constraint.compress = frames[frame + IkConstraintTimeline.PREV_COMPRESS] != 0;
constraint.stretch = frames[frame + IkConstraintTimeline.PREV_STRETCH] != 0;
}
}

View File

@ -304,10 +304,10 @@ module spine {
// Mix between rotations using the direction of the shortest route on the first frame while detecting crosses.
let r1 = blend == MixBlend.setup ? bone.data.rotation : bone.rotation;
let total = 0, diff = r2 - r1;
diff -= (16384 - ((16384.499999999996 - diff / 360) | 0)) * 360;
if (diff == 0) {
total = timelinesRotation[i];
} else {
diff -= (16384 - ((16384.499999999996 - diff / 360) | 0)) * 360;
let lastTotal = 0, lastDiff = 0;
if (firstFrame) {
lastTotal = 0;

View File

@ -34,6 +34,7 @@ module spine {
bones: Array<Bone>;
target: Bone;
bendDirection = 0;
compress = false;
stretch = false;
mix = 1;
@ -43,6 +44,7 @@ module spine {
this.data = data;
this.mix = data.mix;
this.bendDirection = data.bendDirection;
this.compress = data.compress;
this.stretch = data.stretch;
this.bones = new Array<Bone>();
@ -64,7 +66,7 @@ module spine {
let bones = this.bones;
switch (bones.length) {
case 1:
this.apply1(bones[0], target.worldX, target.worldY, this.stretch, this.mix);
this.apply1(bones[0], target.worldX, target.worldY, this.compress, this.stretch, this.data.uniform, this.mix);
break;
case 2:
this.apply2(bones[0], bones[1], target.worldX, target.worldY, this.bendDirection, this.stretch, this.mix);
@ -74,7 +76,7 @@ module spine {
/** Adjusts the bone rotation so the tip is as close to the target position as possible. The target is specified in the world
* coordinate system. */
apply1 (bone: Bone, targetX: number, targetY: number, stretch: boolean, alpha: number) {
apply1 (bone: Bone, targetX: number, targetY: number, compress: boolean, stretch: boolean, uniform: boolean, alpha: number) {
if (!bone.appliedValid) bone.updateAppliedTransform();
let p = bone.parent;
let id = 1 / (p.a * p.d - p.b * p.c);
@ -85,12 +87,16 @@ module spine {
if (rotationIK > 180)
rotationIK -= 360;
else if (rotationIK < -180) rotationIK += 360;
let sx = bone.ascaleX;
if (stretch) {
let sx = bone.ascaleX, sy = bone.ascaleY;
if (compress || stretch) {
let b = bone.data.length * sx, dd = Math.sqrt(tx * tx + ty * ty);
if (dd > b && b > 0.0001) sx *= (dd / b - 1) * alpha + 1;
if ((compress && dd < b) || (stretch && dd > b) && b > 0.0001) {
let s = (dd / b - 1) * alpha + 1;
sx *= s;
if (uniform) sy *= s;
}
bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, bone.ascaleY, bone.ashearX,
}
bone.updateWorldTransformWith(bone.ax, bone.ay, bone.arotation + rotationIK * alpha, sx, sy, bone.ashearX,
bone.ashearY);
}

View File

@ -35,7 +35,9 @@ module spine {
bones = new Array<BoneData>();
target: BoneData;
bendDirection = 1;
compress = false;
stretch = false;
uniform = false;
mix = 1;
constructor (name: string) {

View File

@ -286,9 +286,10 @@ module spine {
let ikConstraints = this.ikConstraints;
for (let i = 0, n = ikConstraints.length; i < n; i++) {
let constraint = ikConstraints[i];
constraint.bendDirection = constraint.data.bendDirection;
constraint.stretch = constraint.data.stretch;
constraint.mix = constraint.data.mix;
constraint.bendDirection = constraint.data.bendDirection;
constraint.compress = constraint.data.compress;
constraint.stretch = constraint.data.stretch;
}
let transformConstraints = this.transformConstraints;

View File

@ -123,9 +123,11 @@ module spine {
data.target = skeletonData.findBone(targetName);
if (data.target == null) throw new Error("IK target bone not found: " + targetName);
data.bendDirection = this.getValue(constraintMap, "bendPositive", true) ? 1 : -1;
data.stretch = this.getValue(constraintMap, "stretch", false);
data.mix = this.getValue(constraintMap, "mix", 1);
data.bendDirection = this.getValue(constraintMap, "bendPositive", true) ? 1 : -1;
data.compress = this.getValue(constraintMap, "compress", false);
data.stretch = this.getValue(constraintMap, "stretch", false);
data.uniform = this.getValue(constraintMap, "uniform", false);
skeletonData.ikConstraints.push(data);
}
@ -521,7 +523,7 @@ module spine {
for (let i = 0; i < constraintMap.length; i++) {
let valueMap = constraintMap[i];
timeline.setFrame(frameIndex, valueMap.time, this.getValue(valueMap, "mix", 1),
this.getValue(valueMap, "bendPositive", true) ? 1 : -1, this.getValue(valueMap, "stretch", false));
this.getValue(valueMap, "bendPositive", true) ? 1 : -1, this.getValue(valueMap, "compress", false), this.getValue(valueMap, "stretch", false));
this.readCurve(valueMap, timeline, frameIndex);
frameIndex++;
}

View File

@ -371,10 +371,14 @@ namespace Spine.Unity.Editor {
foreach (var c in skeleton.IkConstraints) {
EditorGUILayout.LabelField(SpineInspectorUtility.TempContent(c.Data.Name, Icons.constraintIK));
FalseDropDown("Goal", c.Data.Target.Name, Icons.bone, true);
using (new EditorGUI.DisabledGroupScope(true)) {
EditorGUILayout.Toggle(SpineInspectorUtility.TempContent("Data.Uniform", tooltip: "Uniformly scales a bone when Ik stretches or compresses."), c.Data.Uniform);
}
EditorGUI.BeginChangeCheck();
c.Mix = EditorGUILayout.Slider("Mix", c.Mix, MixMin, MixMax);
c.BendDirection = EditorGUILayout.Toggle(SpineInspectorUtility.TempContent("Bend Clockwise", tooltip: "IkConstraint.BendDirection == 1 if clockwise; -1 if counterclockwise."), c.BendDirection > 0) ? 1 : -1;
c.Compress = EditorGUILayout.Toggle(SpineInspectorUtility.TempContent("Compress", tooltip: "Compress single bone IK when the target too close. Not applied when parent bone has nonuniform scale."), c.Compress);
c.Stretch = EditorGUILayout.Toggle(SpineInspectorUtility.TempContent("Stretch", tooltip: "Stretch the parent bone when the target is out of range. Not applied when parent bone has nonuniform scale."), c.Stretch);
if (EditorGUI.EndChangeCheck()) requireRepaint = true;