mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-06 07:14:55 +08:00
Merge branch '3.7-beta' into 3.7-beta-cpp
This commit is contained in:
commit
f5cc2933be
@ -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;
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -65,8 +65,14 @@ 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;
|
||||
};
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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;
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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.");
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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++;
|
||||
}
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
end
|
||||
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)
|
||||
end
|
||||
|
||||
function IkConstraint:apply2 (parent, child, targetX, targetY, bendDir, stretch, alpha)
|
||||
|
||||
@ -38,7 +38,9 @@ function IkConstraintData.new (name)
|
||||
bones = {},
|
||||
target = nil,
|
||||
bendDirection = 1,
|
||||
compress = false,
|
||||
stretch = false,
|
||||
uniform = false,
|
||||
mix = 1
|
||||
}
|
||||
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
3115
spine-ts/build/spine-webgl.d.ts
vendored
3115
spine-ts/build/spine-webgl.d.ts
vendored
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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) {
|
||||
|
||||
@ -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;
|
||||
|
||||
@ -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++;
|
||||
}
|
||||
|
||||
@ -371,12 +371,16 @@ 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;
|
||||
if (EditorGUI.EndChangeCheck()) requireRepaint = true;
|
||||
|
||||
EditorGUILayout.Space();
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user