[c] 4.0 porting, constraints & skeleton

This commit is contained in:
badlogic 2021-03-18 14:44:38 +01:00
parent f0255427aa
commit 1fa5545f19
10 changed files with 268 additions and 260 deletions

View File

@ -55,23 +55,6 @@ struct spBone {
int/*bool*/ sorted;
int/*bool*/ active;
#ifdef __cplusplus
spBone() :
data(0),
skeleton(0),
parent(0),
childrenCount(0), children(0),
x(0), y(0), rotation(0), scaleX(0), scaleY(0),
ax(0), ay(0), arotation(0), ascaleX(0), ascaleY(0), ashearX(0), ashearY(0),
appliedValid(0),
a(0), b(0), worldX(0),
c(0), d(0), worldY(0),
sorted(0), active(0) {
}
#endif
};
SP_API void spBone_setYDown (int/*bool*/yDown);

View File

@ -59,7 +59,7 @@ typedef struct spIkConstraint {
SP_API spIkConstraint* spIkConstraint_create (spIkConstraintData* data, const struct spSkeleton* skeleton);
SP_API void spIkConstraint_dispose (spIkConstraint* self);
SP_API void spIkConstraint_apply (spIkConstraint* self);
SP_API void spIkConstraint_update (spIkConstraint* self);
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 softness, float alpha);

View File

@ -47,7 +47,8 @@ typedef struct spPathConstraint {
int bonesCount;
spBone** const bones;
spSlot* target;
float position, spacing, rotateMix, translateMix;
float position, spacing;
float mixRotate, mixX, mixY;
int spacesCount;
float* spaces;
@ -74,8 +75,8 @@ typedef struct spPathConstraint {
SP_API spPathConstraint* spPathConstraint_create (spPathConstraintData* data, const struct spSkeleton* skeleton);
SP_API void spPathConstraint_dispose (spPathConstraint* self);
SP_API void spPathConstraint_apply (spPathConstraint* self);
SP_API float* spPathConstraint_computeWorldPositions(spPathConstraint* self, spPathAttachment* path, int spacesCount, int/*bool*/ tangents, int/*bool*/percentPosition, int/**/percentSpacing);
SP_API void spPathConstraint_update (spPathConstraint* self);
SP_API float* spPathConstraint_computeWorldPositions(spPathConstraint* self, spPathAttachment* path, int spacesCount, int/*bool*/ tangents);
#ifdef __cplusplus
}

View File

@ -43,7 +43,7 @@ typedef enum {
} spPositionMode;
typedef enum {
SP_SPACING_MODE_LENGTH, SP_SPACING_MODE_FIXED, SP_SPACING_MODE_PERCENT
SP_SPACING_MODE_LENGTH, SP_SPACING_MODE_FIXED, SP_SPACING_MODE_PERCENT, SP_SPACING_MODE_PROPORTIONAL
} spSpacingMode;
typedef enum {
@ -61,7 +61,8 @@ typedef struct spPathConstraintData {
spSpacingMode spacingMode;
spRotateMode rotateMode;
float offsetRotation;
float position, spacing, rotateMix, translateMix;
float position, spacing;
float mixRotate, mixX, mixY;
} spPathConstraintData;
SP_API spPathConstraintData* spPathConstraintData_create (const char* name);

View File

@ -45,14 +45,14 @@ typedef struct spTransformConstraint {
int bonesCount;
spBone** const bones;
spBone* target;
float rotateMix, translateMix, scaleMix, shearMix;
float mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY;
int /*boolean*/ active;
} spTransformConstraint;
SP_API spTransformConstraint* spTransformConstraint_create (spTransformConstraintData* data, const struct spSkeleton* skeleton);
SP_API void spTransformConstraint_dispose (spTransformConstraint* self);
SP_API void spTransformConstraint_apply (spTransformConstraint* self);
SP_API void spTransformConstraint_update (spTransformConstraint* self);
#ifdef __cplusplus
}

View File

@ -44,7 +44,7 @@ typedef struct spTransformConstraintData {
int bonesCount;
spBoneData** const bones;
spBoneData* target;
float rotateMix, translateMix, scaleMix, shearMix;
float mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY;
float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY;
int /*boolean*/ relative;
int /*boolean*/ local;

View File

@ -57,7 +57,8 @@ void spIkConstraint_dispose(spIkConstraint *self) {
FREE(self);
}
void spIkConstraint_apply(spIkConstraint *self) {
void spIkConstraint_update(spIkConstraint *self) {
if (self->mix == 0) return;
switch (self->bonesCount) {
case 1:
spIkConstraint_apply1(self->bones[0], self->target->worldX, self->target->worldY, self->compress, self->stretch, self->data->uniform, self->mix);
@ -131,10 +132,7 @@ void spIkConstraint_apply2 (spBone* parent, spBone* child, float targetX, float
float tx, ty, dd, dx, dy, l1, l2, a1, a2, r, td, sd, p;
float id, x, y;
float aa, bb, ll, ta, c0, c1, c2;
if (alpha == 0) {
spBone_updateWorldTransform(child);
return;
}
if (!parent->appliedValid) spBone_updateAppliedTransform(parent);
if (!child->appliedValid) spBone_updateAppliedTransform(child);
px = parent->ax; py = parent->ay; psx = parent->ascaleX; sx = psx; psy = parent->ascaleY; csx = child->ascaleX;

View File

@ -47,8 +47,9 @@ spPathConstraint* spPathConstraint_create (spPathConstraintData* data, const spS
self->target = spSkeleton_findSlot(skeleton, self->data->target->name);
self->position = data->position;
self->spacing = data->spacing;
self->rotateMix = data->rotateMix;
self->translateMix = data->translateMix;
self->mixRotate = data->mixRotate;
self->mixX = data->mixX;
self->mixY = data->mixY;
self->spacesCount = 0;
self->spaces = 0;
self->positionsCount = 0;
@ -72,26 +73,23 @@ void spPathConstraint_dispose (spPathConstraint* self) {
FREE(self);
}
void spPathConstraint_apply (spPathConstraint* self) {
void spPathConstraint_update (spPathConstraint* self) {
int i, p, n;
float length, setupLength, x, y, dx, dy, s;
float length, setupLength, x, y, dx, dy, s, sum;
float* spaces, *lengths, *positions;
float spacing;
float boneX, boneY, offsetRotation;
int/*bool*/tip;
float rotateMix = self->rotateMix, translateMix = self->translateMix;
int/*bool*/ translate = translateMix > 0, rotate = rotateMix > 0;
float mixRotate = self->mixRotate, mixX = self->mixX, mixY = self->mixY;
int lengthSpacing;
spPathAttachment* attachment = (spPathAttachment*)self->target->attachment;
spPathConstraintData* data = self->data;
int percentSpacing = data->spacingMode == SP_SPACING_MODE_PERCENT;
spRotateMode rotateMode = data->rotateMode;
int tangents = rotateMode == SP_ROTATE_MODE_TANGENT, scale = rotateMode == SP_ROTATE_MODE_CHAIN_SCALE;
int tangents = data->rotateMode == SP_ROTATE_MODE_TANGENT, scale = data->rotateMode == SP_ROTATE_MODE_CHAIN_SCALE;
int boneCount = self->bonesCount, spacesCount = tangents ? boneCount : boneCount + 1;
spBone** bones = self->bones;
spBone* pa;
if (!translate && !rotate) return;
if (mixRotate == 0 && mixX == 0 && mixY == 0) return;
if ((attachment == 0) || (attachment->super.super.type != SP_ATTACHMENT_PATH)) return;
if (self->spacesCount != spacesCount) {
@ -103,48 +101,77 @@ void spPathConstraint_apply (spPathConstraint* self) {
spaces[0] = 0;
lengths = 0;
spacing = self->spacing;
if (scale || !percentSpacing) {
if (scale) {
if (self->lengthsCount != boneCount) {
if (self->lengths) FREE(self->lengths);
self->lengths = MALLOC(float, boneCount);
self->lengthsCount = boneCount;
}
lengths = self->lengths;
}
lengthSpacing = data->spacingMode == SP_SPACING_MODE_LENGTH;
for (i = 0, n = spacesCount - 1; i < n;) {
spBone *bone = bones[i];
setupLength = bone->data->length;
if (setupLength < EPSILON) {
if (scale) lengths[i] = 0;
spaces[++i] = 0;
} else if (percentSpacing) {
if (scale) {
x = setupLength * bone->a, y = setupLength * bone->c;
length = SQRT(x * x + y * y);
lengths[i] = length;
}
spaces[++i] = spacing;
} else {
x = setupLength * bone->a, y = setupLength * bone->c;
length = SQRT(x * x + y * y);
if (scale) lengths[i] = length;
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength;
}
}
} else {
for (i = 1; i < spacesCount; i++) {
spaces[i] = spacing;
}
}
positions = spPathConstraint_computeWorldPositions(self, attachment, spacesCount, tangents,
data->positionMode == SP_POSITION_MODE_PERCENT, percentSpacing);
if (scale) {
if (self->lengthsCount != boneCount) {
if (self->lengths) FREE(self->lengths);
self->lengths = MALLOC(float, boneCount);
self->lengthsCount = boneCount;
}
lengths = self->lengths;
}
switch (data->spacingMode) {
case SP_SPACING_MODE_PERCENT:
if (scale) {
for (i = 0, n = spacesCount - 1; i < n; i++) {
spBone* bone = bones[i];
setupLength = bone->data->length;
if (setupLength < EPSILON)
lengths[i] = 0;
else {
x = setupLength * bone->a;
y = setupLength * bone->c;
lengths[i] = SQRT(x * x + y * y);
}
}
}
for (i = 1, n = spacesCount; i < n; i++) spaces[i] = spacing;
break;
case SP_SPACING_MODE_PROPORTIONAL:
sum = 0;
for (i = 0; i < boneCount;) {
spBone* bone = bones[i];
setupLength = bone->data->length;
if (setupLength < EPSILON) {
if (scale) lengths[i] = 0;
spaces[++i] = spacing;
} else {
x = setupLength * bone->a, y = setupLength * bone->c;
length = SQRT(x * x + y * y);
if (scale) lengths[i] = length;
spaces[++i] = length;
sum += length;
}
}
if (sum > 0) {
sum = spacesCount / sum * spacing;
for (i = 1; i < spacesCount; i++)
spaces[i] *= sum;
}
break;
default:
lengthSpacing = data->spacingMode == SP_SPACING_MODE_LENGTH;
for (i = 0, n = spacesCount - 1; i < n;) {
spBone* bone = bones[i];
setupLength = bone->data->length;
if (setupLength < EPSILON) {
if (scale) lengths[i] = 0;
spaces[++i] = spacing;
} else {
x = setupLength * bone->a, y = setupLength * bone->c;
length = SQRT(x * x + y * y);
if (scale) lengths[i] = length;
spaces[++i] = (lengthSpacing ? setupLength + spacing : spacing) * length / setupLength;
}
}
}
positions = spPathConstraint_computeWorldPositions(self, attachment, spacesCount, tangents);
boneX = positions[0], boneY = positions[1], offsetRotation = self->data->offsetRotation;
tip = 0;
if (offsetRotation == 0)
tip = rotateMode == SP_ROTATE_MODE_CHAIN;
tip = data->rotateMode == SP_ROTATE_MODE_CHAIN;
else {
tip = 0;
pa = self->target->bone;
@ -152,20 +179,20 @@ void spPathConstraint_apply (spPathConstraint* self) {
}
for (i = 0, p = 3; i < boneCount; i++, p += 3) {
spBone* bone = bones[i];
CONST_CAST(float, bone->worldX) += (boneX - bone->worldX) * translateMix;
CONST_CAST(float, bone->worldY) += (boneY - bone->worldY) * translateMix;
CONST_CAST(float, bone->worldX) += (boneX - bone->worldX) * mixX;
CONST_CAST(float, bone->worldY) += (boneY - bone->worldY) * mixY;
x = positions[p], y = positions[p + 1], dx = x - boneX, dy = y - boneY;
if (scale) {
length = lengths[i];
if (length != 0) {
s = (SQRT(dx * dx + dy * dy) / length - 1) * rotateMix + 1;
s = (SQRT(dx * dx + dy * dy) / length - 1) * mixRotate + 1;
CONST_CAST(float, bone->a) *= s;
CONST_CAST(float, bone->c) *= s;
}
}
boneX = x;
boneY = y;
if (rotate) {
if (mixRotate > 0) {
float a = bone->a, b = bone->b, c = bone->c, d = bone->d, r, cosine, sine;
if (tangents)
r = positions[p - 1];
@ -178,15 +205,15 @@ void spPathConstraint_apply (spPathConstraint* self) {
cosine = COS(r);
sine = SIN(r);
length = bone->data->length;
boneX += (length * (cosine * a - sine * c) - dx) * rotateMix;
boneY += (length * (sine * a + cosine * c) - dy) * rotateMix;
boneX += (length * (cosine * a - sine * c) - dx) * mixRotate;
boneY += (length * (sine * a + cosine * c) - dy) * mixRotate;
} else
r += offsetRotation;
if (r > PI)
r -= PI2;
else if (r < -PI)
r += PI2;
r *= rotateMix;
r *= mixRotate;
cosine = COS(r);
sine = SIN(r);
CONST_CAST(float, bone->a) = cosine * a - sine * c;
@ -236,11 +263,11 @@ static void _addCurvePosition (float p, float x1, float y1, float cx1, float cy1
}
}
float* spPathConstraint_computeWorldPositions(spPathConstraint* self, spPathAttachment* path, int spacesCount, int/*bool*/ tangents, int/*bool*/percentPosition, int/**/percentSpacing) {
float* spPathConstraint_computeWorldPositions(spPathConstraint* self, spPathAttachment* path, int spacesCount, int/*bool*/ tangents) {
int i, o, w, curve, segment, /*bool*/closed, verticesLength, curveCount, prevCurve;
float* out, *curves, *segments;
float tmpx, tmpy, dddfx, dddfy, ddfx, ddfy, dfx, dfy, pathLength, curveLength, p;
float x1, y1, cx1, cy1, cx2, cy2, x2, y2;
float x1, y1, cx1, cy1, cx2, cy2, x2, y2, multiplier;
spSlot* target = self->target;
float position = self->position;
float* spaces = self->spaces, *world = 0;
@ -257,11 +284,18 @@ float* spPathConstraint_computeWorldPositions(spPathConstraint* self, spPathAtta
float* lengths = path->lengths;
curveCount -= closed ? 1 : 2;
pathLength = lengths[curveCount];
if (percentPosition) position *= pathLength;
if (percentSpacing) {
for (i = 1; i < spacesCount; i++)
spaces[i] *= pathLength;
}
if (self->data->positionMode == SP_POSITION_MODE_PERCENT) position += pathLength;
switch (self->data->spacingMode) {
case SP_SPACING_MODE_PERCENT:
multiplier = pathLength;
break;
case SP_SPACING_MODE_PROPORTIONAL:
multiplier = pathLength / spacesCount;
break;
default:
multiplier = 1;
}
if (self->worldCount != 8) {
if (self->world) FREE(self->world);
self->world = MALLOC(float, 8);
@ -269,7 +303,7 @@ float* spPathConstraint_computeWorldPositions(spPathConstraint* self, spPathAtta
}
world = self->world;
for (i = 0, o = 0, curve = 0; i < spacesCount; i++, o += 3) {
float space = spaces[i];
float space = spaces[i] * multiplier;
position += space;
p = position;
@ -384,19 +418,24 @@ float* spPathConstraint_computeWorldPositions(spPathConstraint* self, spPathAtta
x1 = x2;
y1 = y2;
}
if (percentPosition)
position *= pathLength;
else
position *= pathLength / path->lengths[curveCount - 1];
if (percentSpacing) {
for (i = 1; i < spacesCount; i++)
spaces[i] *= pathLength;
}
if (self->data->positionMode == SP_POSITION_MODE_PERCENT) position *= pathLength;
switch (self->data->spacingMode) {
case SP_SPACING_MODE_PERCENT:
multiplier = pathLength;
break;
case SP_SPACING_MODE_PROPORTIONAL:
multiplier = pathLength / spacesCount;
break;
default:
multiplier = 1;
}
segments = self->segments;
curveLength = 0;
for (i = 0, o = 0, curve = 0, segment = 0; i < spacesCount; i++, o += 3) {
float space = spaces[i];
float space = spaces[i] * multiplier;
position += space;
p = position;

View File

@ -47,10 +47,6 @@ typedef struct {
int updateCacheCount;
int updateCacheCapacity;
_spUpdate* updateCache;
int updateCacheResetCount;
int updateCacheResetCapacity;
spBone** updateCacheReset;
} _spSkeleton;
spSkeleton* spSkeleton_create (spSkeletonData* data) {
@ -133,7 +129,6 @@ void spSkeleton_dispose (spSkeleton* self) {
_spSkeleton* internal = SUB_CAST(_spSkeleton, self);
FREE(internal->updateCache);
FREE(internal->updateCacheReset);
for (i = 0; i < self->bonesCount; ++i)
spBone_dispose(self->bones[i]);
@ -171,15 +166,6 @@ static void _addToUpdateCache(_spSkeleton* const internal, _spUpdateType type, v
++internal->updateCacheCount;
}
static void _addToUpdateCacheReset(_spSkeleton* const internal, spBone* bone) {
if (internal->updateCacheResetCount == internal->updateCacheResetCapacity) {
internal->updateCacheResetCapacity *= 2;
internal->updateCacheReset = (spBone**)realloc(internal->updateCacheReset, sizeof(spBone*) * internal->updateCacheResetCapacity);
}
internal->updateCacheReset[internal->updateCacheResetCount] = bone;
++internal->updateCacheResetCount;
}
static void _sortBone(_spSkeleton* const internal, spBone* bone) {
if (bone->sorted) return;
if (bone->parent) _sortBone(internal, bone->parent);
@ -199,11 +185,13 @@ static void _sortPathConstraintAttachmentBones(_spSkeleton* const internal, spAt
else {
spBone** bones = internal->super.bones;
int i = 0, n;
while (i < pathBonesCount) {
int boneCount = pathBones[i++];
for (n = i + boneCount; i < n; i++)
_sortBone(internal, bones[pathBones[i]]);
}
for (i = 0, n = pathBonesCount; i < n;) {
int nn = pathBones[i++];
nn += i;
while (i < nn)
_sortBone(internal, bones[pathBones[i++]]);
}
}
}
@ -241,23 +229,18 @@ static void _sortIkConstraint (_spSkeleton* const internal, spIkConstraint* cons
parent = constrained[0];
_sortBone(internal, parent);
if (constraint->bonesCount > 1) {
if (constraint->bonesCount == 1) {
_addToUpdateCache(internal, SP_UPDATE_IK_CONSTRAINT, constraint);
_sortReset(parent->children, parent->childrenCount);
} else {
spBone* child = constrained[constraint->bonesCount - 1];
contains = 0;
for (i = 0; i < internal->updateCacheCount; i++) {
_spUpdate update = internal->updateCache[i];
if (update.object == child) {
contains = -1;
break;
}
}
if (!contains) _addToUpdateCacheReset(internal, child);
_sortBone(internal, child);
_addToUpdateCache(internal, SP_UPDATE_IK_CONSTRAINT, constraint);
_sortReset(parent->children, parent->childrenCount);
child->sorted = 1;
}
_addToUpdateCache(internal, SP_UPDATE_IK_CONSTRAINT, constraint);
_sortReset(parent->children, parent->childrenCount);
constrained[constraint->bonesCount-1]->sorted = 1;
}
static void _sortPathConstraint(_spSkeleton* const internal, spPathConstraint* constraint) {
@ -310,16 +293,8 @@ static void _sortTransformConstraint(_spSkeleton* const internal, spTransformCon
if (constraint->data->local) {
for (i = 0; i < boneCount; i++) {
child = constrained[i];
_sortBone(internal, child->parent);
_sortBone(internal, child);
contains = 0;
for (i = 0; i < internal->updateCacheCount; i++) {
_spUpdate update = internal->updateCache[i];
if (update.object == child) {
contains = -1;
break;
}
}
if (!contains) _addToUpdateCacheReset(internal, child);
}
} else {
for (i = 0; i < boneCount; i++)
@ -348,11 +323,6 @@ void spSkeleton_updateCache (spSkeleton* self) {
internal->updateCache = MALLOC(_spUpdate, internal->updateCacheCapacity);
internal->updateCacheCount = 0;
internal->updateCacheResetCapacity = self->bonesCount;
FREE(internal->updateCacheReset);
internal->updateCacheReset = MALLOC(spBone*, internal->updateCacheResetCapacity);
internal->updateCacheResetCount = 0;
bones = self->bones;
for (i = 0; i < self->bonesCount; ++i) {
spBone* bone = bones[i];
@ -417,19 +387,6 @@ void spSkeleton_updateCache (spSkeleton* self) {
void spSkeleton_updateWorldTransform (const spSkeleton* self) {
int i;
_spSkeleton* internal = SUB_CAST(_spSkeleton, self);
spBone** updateCacheReset = internal->updateCacheReset;
for (i = 0; i < internal->updateCacheResetCount; i++) {
spBone* bone = updateCacheReset[i];
CONST_CAST(float, bone->ax) = bone->x;
CONST_CAST(float, bone->ay) = bone->y;
CONST_CAST(float, bone->arotation) = bone->rotation;
CONST_CAST(float, bone->ascaleX) = bone->scaleX;
CONST_CAST(float, bone->ascaleY) = bone->scaleY;
CONST_CAST(float, bone->ashearX) = bone->shearX;
CONST_CAST(float, bone->ashearY) = bone->shearY;
CONST_CAST(int, bone->appliedValid) = 1;
}
for (i = 0; i < internal->updateCacheCount; ++i) {
_spUpdate* update = internal->updateCache + i;
switch (update->type) {
@ -437,18 +394,60 @@ void spSkeleton_updateWorldTransform (const spSkeleton* self) {
spBone_updateWorldTransform((spBone*)update->object);
break;
case SP_UPDATE_IK_CONSTRAINT:
spIkConstraint_apply((spIkConstraint*)update->object);
spIkConstraint_update((spIkConstraint *) update->object);
break;
case SP_UPDATE_TRANSFORM_CONSTRAINT:
spTransformConstraint_apply((spTransformConstraint*)update->object);
spTransformConstraint_update((spTransformConstraint *) update->object);
break;
case SP_UPDATE_PATH_CONSTRAINT:
spPathConstraint_apply((spPathConstraint*)update->object);
spPathConstraint_update((spPathConstraint *) update->object);
break;
}
}
}
void spSkeleton_updateWorldTransformWith (const spSkeleton* self, const spBone *parent) {
/* Apply the parent bone transform to the root bone. The root bone always inherits scale, rotation and reflection. */
int i, n;
float rotationY, la, lb, lc, ld;
_spUpdate *updateCache;
_spSkeleton* internal = SUB_CAST(_spSkeleton, self);
spBone *rootBone = self->root;
float pa = parent->a, pb = parent->b, pc = parent->c, pd = parent->d;
CONST_CAST(float, rootBone->worldX) = pa * self->x + pb * self->y + parent->worldX;
CONST_CAST(float, rootBone->worldY) = pc * self->x + pd * self->y + parent->worldY;
rotationY = rootBone->rotation + 90 + rootBone->shearY;
la = COS_DEG(rootBone->rotation + rootBone->shearX) * rootBone->scaleX;
lb = COS_DEG(rotationY) * rootBone->scaleY;
lc = SIN_DEG(rootBone->rotation + rootBone->shearX) * rootBone->scaleX;
ld = SIN_DEG(rotationY) * rootBone->scaleY;
CONST_CAST(float, rootBone->a) = (pa * la + pb * lc) * self->scaleX;
CONST_CAST(float, rootBone->b) = (pa * lb + pb * ld) * self->scaleX;
CONST_CAST(float, rootBone->c) = (pc * la + pd * lc) * self->scaleY;
CONST_CAST(float, rootBone->d) = (pc * lb + pd * ld) * self->scaleY;
/* Update everything except root bone. */
updateCache = internal->updateCache;
for (i = 0; i < internal->updateCacheCount; ++i) {
_spUpdate* update = internal->updateCache + i;
switch (update->type) {
case SP_UPDATE_BONE:
if ((spBone*)update->object != rootBone) spBone_updateWorldTransform((spBone*)update->object);
break;
case SP_UPDATE_IK_CONSTRAINT:
spIkConstraint_update((spIkConstraint *) update->object);
break;
case SP_UPDATE_TRANSFORM_CONSTRAINT:
spTransformConstraint_update((spTransformConstraint *) update->object);
break;
case SP_UPDATE_PATH_CONSTRAINT:
spPathConstraint_update((spPathConstraint *) update->object);
break;
}
}
}
void spSkeleton_setToSetupPose (const spSkeleton* self) {
spSkeleton_setBonesToSetupPose(self);
spSkeleton_setSlotsToSetupPose(self);
@ -471,10 +470,12 @@ void spSkeleton_setBonesToSetupPose (const spSkeleton* self) {
for (i = 0; i < self->transformConstraintsCount; ++i) {
spTransformConstraint* constraint = self->transformConstraints[i];
spTransformConstraintData* data = constraint->data;
constraint->rotateMix = data->rotateMix;
constraint->translateMix = data->translateMix;
constraint->scaleMix = data->scaleMix;
constraint->shearMix = data->shearMix;
constraint->mixRotate = data->mixRotate;
constraint->mixX = data->mixX;
constraint->mixY = data->mixY;
constraint->mixScaleX = data->mixScaleX;
constraint->mixScaleY = data->mixScaleY;
constraint->mixShearY = data->mixShearY;
}
for (i = 0; i < self->pathConstraintsCount; ++i) {
@ -482,8 +483,9 @@ void spSkeleton_setBonesToSetupPose (const spSkeleton* self) {
spPathConstraintData* data = constraint->data;
constraint->position = data->position;
constraint->spacing = data->spacing;
constraint->rotateMix = data->rotateMix;
constraint->translateMix = data->translateMix;
constraint->mixRotate = data->mixRotate;
constraint->mixX = data->mixX;
constraint->mixY = data->mixY;
}
}

View File

@ -35,10 +35,12 @@ spTransformConstraint* spTransformConstraint_create (spTransformConstraintData*
int i;
spTransformConstraint* self = NEW(spTransformConstraint);
CONST_CAST(spTransformConstraintData*, self->data) = data;
self->rotateMix = data->rotateMix;
self->translateMix = data->translateMix;
self->scaleMix = data->scaleMix;
self->shearMix = data->shearMix;
self->mixRotate = data->mixRotate;
self->mixX = data->mixX;
self->mixY = data->mixY;
self->mixScaleX = data->mixScaleX;
self->mixScaleY = data->mixScaleY;
self->mixShearY = data->mixShearY;
self->bonesCount = data->bonesCount;
CONST_CAST(spBone**, self->bones) = MALLOC(spBone*, self->bonesCount);
for (i = 0; i < self->bonesCount; ++i)
@ -53,134 +55,128 @@ void spTransformConstraint_dispose (spTransformConstraint* self) {
}
void _spTransformConstraint_applyAbsoluteWorld (spTransformConstraint* self) {
float rotateMix = self->rotateMix, translateMix = self->translateMix, scaleMix = self->scaleMix, shearMix = self->shearMix;
float mixRotate = self->mixRotate, mixX = self->mixX, mixY = self->mixY, mixScaleX = self->mixScaleX,
mixScaleY = self->mixScaleY, mixShearY = self->mixShearY;
int /*bool*/ translate = mixX != 0 || mixY != 0;
spBone* target = self->target;
float ta = target->a, tb = target->b, tc = target->c, td = target->d;
float degRadReflect = ta * td - tb * tc > 0 ? DEG_RAD : -DEG_RAD;
float offsetRotation = self->data->offsetRotation * degRadReflect, offsetShearY = self->data->offsetShearY * degRadReflect;
int /*bool*/ modified;
int i;
float a, b, c, d, r, cosine, sine, x, y, s, ts, by;
for (i = 0; i < self->bonesCount; ++i) {
spBone* bone = self->bones[i];
modified = 0;
if (rotateMix != 0) {
if (mixRotate != 0) {
a = bone->a, b = bone->b, c = bone->c, d = bone->d;
r = ATAN2(tc, ta) - ATAN2(c, a) + offsetRotation;
if (r > PI) r -= PI2;
else if (r < -PI) r += PI2;
r *= rotateMix;
r *= mixRotate;
cosine = COS(r);
sine = SIN(r);
CONST_CAST(float, bone->a) = cosine * a - sine * c;
CONST_CAST(float, bone->b) = cosine * b - sine * d;
CONST_CAST(float, bone->c) = sine * a + cosine * c;
CONST_CAST(float, bone->d) = sine * b + cosine * d;
modified = 1;
}
if (translateMix != 0) {
if (translate) {
spBone_localToWorld(target, self->data->offsetX, self->data->offsetY, &x, &y);
CONST_CAST(float, bone->worldX) += (x - bone->worldX) * translateMix;
CONST_CAST(float, bone->worldY) += (y - bone->worldY) * translateMix;
modified = 1;
CONST_CAST(float, bone->worldX) += (x - bone->worldX) * mixX;
CONST_CAST(float, bone->worldY) += (y - bone->worldY) * mixY;
}
if (scaleMix > 0) {
s = SQRT(bone->a * bone->a + bone->c * bone->c);
ts = SQRT(ta * ta + tc * tc);
if (s > 0.00001f) s = (s + (ts - s + self->data->offsetScaleX) * scaleMix) / s;
CONST_CAST(float, bone->a) *= s;
CONST_CAST(float, bone->c) *= s;
s = SQRT(bone->b * bone->b + bone->d * bone->d);
ts = SQRT(tb * tb + td * td);
if (s > 0.00001f) s = (s + (ts - s + self->data->offsetScaleY) * scaleMix) / s;
CONST_CAST(float, bone->b) *= s;
CONST_CAST(float, bone->d) *= s;
modified = 1;
if (mixScaleX > 0) {
s = SQRT(bone->a * bone->a + bone->c * bone->c);
if (s != 0) s = (s + (SQRT(ta * ta + tc * tc) - s + self->data->offsetScaleX) * mixScaleX) / s;
CONST_CAST(float, bone->a) *= s;
CONST_CAST(float, bone->c) *= s;
}
if (mixScaleY != 0) {
s = SQRT(bone->b * bone->b + bone->d * bone->d);
if (s != 0) s = (s + (SQRT(tb * tb + td * td) - s + self->data->offsetScaleY) * mixScaleY) / s;
CONST_CAST(float, bone->b) *= s;
CONST_CAST(float, bone->d) *= s;
}
if (shearMix > 0) {
if (mixShearY > 0) {
b = bone->b, d = bone->d;
by = ATAN2(d, b);
r = ATAN2(td, tb) - ATAN2(tc, ta) - (by - ATAN2(bone->c, bone->a));
s = SQRT(b * b + d * d);
if (r > PI) r -= PI2;
else if (r < -PI) r += PI2;
r = by + (r + offsetShearY) * shearMix;
r = by + (r + offsetShearY) * mixShearY;
CONST_CAST(float, bone->b) = COS(r) * s;
CONST_CAST(float, bone->d) = SIN(r) * s;
modified = 1;
}
if (modified) CONST_CAST(int, bone->appliedValid) = 0;
CONST_CAST(int, bone->appliedValid) = 0;
}
}
void _spTransformConstraint_applyRelativeWorld (spTransformConstraint* self) {
float rotateMix = self->rotateMix, translateMix = self->translateMix, scaleMix = self->scaleMix, shearMix = self->shearMix;
float mixRotate = self->mixRotate, mixX = self->mixX, mixY = self->mixY, mixScaleX = self->mixScaleX,
mixScaleY = self->mixScaleY, mixShearY = self->mixShearY;
int /*bool*/ translate = mixX != 0 || mixY != 0;
spBone* target = self->target;
float ta = target->a, tb = target->b, tc = target->c, td = target->d;
float degRadReflect = ta * td - tb * tc > 0 ? DEG_RAD : -DEG_RAD;
float offsetRotation = self->data->offsetRotation * degRadReflect, offsetShearY = self->data->offsetShearY * degRadReflect;
int /*bool*/ modified;
int i;
float a, b, c, d, r, cosine, sine, x, y, s;
for (i = 0; i < self->bonesCount; ++i) {
spBone* bone = self->bones[i];
modified = 0;
if (rotateMix != 0) {
if (mixRotate != 0) {
a = bone->a, b = bone->b, c = bone->c, d = bone->d;
r = ATAN2(tc, ta) + offsetRotation;
if (r > PI) r -= PI2;
else if (r < -PI) r += PI2;
r *= rotateMix;
r *= mixRotate;
cosine = COS(r);
sine = SIN(r);
CONST_CAST(float, bone->a) = cosine * a - sine * c;
CONST_CAST(float, bone->b) = cosine * b - sine * d;
CONST_CAST(float, bone->c) = sine * a + cosine * c;
CONST_CAST(float, bone->d) = sine * b + cosine * d;
modified = 1;
}
if (translateMix != 0) {
if (translate != 0) {
spBone_localToWorld(target, self->data->offsetX, self->data->offsetY, &x, &y);
CONST_CAST(float, bone->worldX) += (x * translateMix);
CONST_CAST(float, bone->worldY) += (y * translateMix);
modified = 1;
CONST_CAST(float, bone->worldX) += (x * mixX);
CONST_CAST(float, bone->worldY) += (y * mixY);
}
if (scaleMix > 0) {
s = (SQRT(ta * ta + tc * tc) - 1 + self->data->offsetScaleX) * scaleMix + 1;
CONST_CAST(float, bone->a) *= s;
CONST_CAST(float, bone->c) *= s;
s = (SQRT(tb * tb + td * td) - 1 + self->data->offsetScaleY) * scaleMix + 1;
if (mixScaleX != 0) {
s = (SQRT(ta * ta + tc * tc) - 1 + self->data->offsetScaleX) * mixScaleX + 1;
CONST_CAST(float, bone->a) *= s;
CONST_CAST(float, bone->c) *= s;
}
if (mixScaleY > 0) {
s = (SQRT(tb * tb + td * td) - 1 + self->data->offsetScaleY) * mixScaleY + 1;
CONST_CAST(float, bone->b) *= s;
CONST_CAST(float, bone->d) *= s;
modified = 1;
}
if (shearMix > 0) {
if (mixShearY > 0) {
r = ATAN2(td, tb) - ATAN2(tc, ta);
if (r > PI) r -= PI2;
else if (r < -PI) r += PI2;
b = bone->b, d = bone->d;
r = ATAN2(d, b) + (r - PI / 2 + offsetShearY) * shearMix;
r = ATAN2(d, b) + (r - PI / 2 + offsetShearY) * mixShearY;
s = SQRT(b * b + d * d);
CONST_CAST(float, bone->b) = COS(r) * s;
CONST_CAST(float, bone->d) = SIN(r) * s;
modified = 1;
}
if (modified) CONST_CAST(int, bone->appliedValid) = 0;
CONST_CAST(int, bone->appliedValid) = 0;
}
}
void _spTransformConstraint_applyAbsoluteLocal (spTransformConstraint* self) {
float rotateMix = self->rotateMix, translateMix = self->translateMix, scaleMix = self->scaleMix, shearMix = self->shearMix;
float mixRotate = self->mixRotate, mixX = self->mixX, mixY = self->mixY, mixScaleX = self->mixScaleX,
mixScaleY = self->mixScaleY, mixShearY = self->mixShearY;
spBone* target = self->target;
int i;
float rotation, r, x, y, scaleX, scaleY, shearY;
@ -191,29 +187,27 @@ void _spTransformConstraint_applyAbsoluteLocal (spTransformConstraint* self) {
if (!bone->appliedValid) spBone_updateAppliedTransform(bone);
rotation = bone->arotation;
if (rotateMix != 0) {
if (mixRotate != 0) {
r = target->arotation - rotation + self->data->offsetRotation;
r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360;
rotation += r * rotateMix;
rotation += r * mixRotate;
}
x = bone->ax, y = bone->ay;
if (translateMix != 0) {
x += (target->ax - x + self->data->offsetX) * translateMix;
y += (target->ay - y + self->data->offsetY) * translateMix;
}
x += (target->ax - x + self->data->offsetX) * mixX;
y += (target->ay - y + self->data->offsetY) * mixY;
scaleX = bone->ascaleX, scaleY = bone->ascaleY;
if (scaleMix != 0) {
if (scaleX > 0.00001) scaleX = (scaleX + (target->ascaleX - scaleX + self->data->offsetScaleX) * scaleMix) / scaleX;
if (scaleY > 0.00001) scaleY = (scaleY + (target->ascaleY - scaleY + self->data->offsetScaleY) * scaleMix) / scaleY;
}
if (mixScaleX != 0 && scaleX != 0)
scaleX = (scaleX + (target->ascaleX - scaleX + self->data->offsetScaleX) * mixScaleX) / scaleX;
if (mixScaleY != 0 && scaleY != 0)
scaleY = (scaleY + (target->ascaleY - scaleY + self->data->offsetScaleY) * mixScaleY) / scaleY;
shearY = bone->ashearY;
if (shearMix != 0) {
if (mixShearY != 0) {
r = target->ashearY - shearY + self->data->offsetShearY;
r -= (16384 - (int)(16384.499999999996 - r / 360)) * 360;
bone->shearY += r * shearMix;
shearY += r * mixShearY;
}
spBone_updateWorldTransformWith(bone, x, y, rotation, scaleX, scaleY, bone->ashearX, shearY);
@ -221,7 +215,8 @@ void _spTransformConstraint_applyAbsoluteLocal (spTransformConstraint* self) {
}
void _spTransformConstraint_applyRelativeLocal (spTransformConstraint* self) {
float rotateMix = self->rotateMix, translateMix = self->translateMix, scaleMix = self->scaleMix, shearMix = self->shearMix;
float mixRotate = self->mixRotate, mixX = self->mixX, mixY = self->mixY, mixScaleX = self->mixScaleX,
mixScaleY = self->mixScaleY, mixShearY = self->mixShearY;
spBone* target = self->target;
int i;
float rotation, x, y, scaleX, scaleY, shearY;
@ -232,32 +227,21 @@ void _spTransformConstraint_applyRelativeLocal (spTransformConstraint* self) {
spBone* bone = self->bones[i];
if (!bone->appliedValid) spBone_updateAppliedTransform(bone);
rotation = bone->arotation;
if (rotateMix != 0) rotation += (target->arotation + self->data->offsetRotation) * rotateMix;
rotation = bone->arotation + (target->arotation + self->data->offsetRotation) * mixRotate;
x = bone->ax + (target->ax + self->data->offsetX) * mixX;
y = bone->ay + (target->ay + self->data->offsetY) * mixY;
scaleX = (bone->ascaleX * ((target->ascaleX - 1 + self->data->offsetScaleX) * mixScaleX) + 1);
scaleY = (bone->ascaleY * ((target->ascaleY - 1 + self->data->offsetScaleY) * mixScaleY) + 1);
shearY = bone->ashearY + (target->ashearY + self->data-> offsetShearY) * mixShearY;
x = bone->ax;
y = bone->ay;
if (translateMix != 0) {
x += (target->ax + self->data->offsetX) * translateMix;
y += (target->ay + self->data->offsetY) * translateMix;
}
scaleX = bone->ascaleX;
scaleY = bone->ascaleY;
if (scaleMix != 0) {
if (scaleX > 0.00001f) scaleX *= ((target->ascaleX - 1 + self->data->offsetScaleX) * scaleMix) + 1;
if (scaleY > 0.00001f) scaleY *= ((target->ascaleY - 1 + self->data->offsetScaleY) * scaleMix) + 1;
}
shearY = bone->ashearY;
if (shearMix != 0) shearY += (target->ashearY + self->data->offsetShearY) * shearMix;
spBone_updateWorldTransformWith(bone, x, y, rotation, scaleX, scaleY, bone->ashearX, shearY);
spBone_updateWorldTransformWith(bone, x, y, rotation, scaleX, scaleY, bone->ashearX, shearY);
}
}
void spTransformConstraint_apply (spTransformConstraint* self) {
if (self->data->local) {
void spTransformConstraint_update (spTransformConstraint* self) {
if (self->mixRotate == 0 && self->mixX == 0 && self->mixY == 0 && self->mixScaleX == 0 && self->mixScaleX == 0 && self->mixShearY == 0) return;
if (self->data->local) {
if (self->data->relative)
_spTransformConstraint_applyRelativeLocal(self);
else