mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-11 17:48:45 +08:00
Transform constraint property mapping.
This commit is contained in:
parent
a68a509076
commit
79c832793d
@ -267,7 +267,7 @@ public class Skeleton {
|
||||
|
||||
Object[] constrained = constraint.bones.items;
|
||||
int boneCount = constraint.bones.size;
|
||||
if (constraint.data.local) {
|
||||
if (constraint.data.localFrom) {
|
||||
for (int i = 0; i < boneCount; i++) {
|
||||
var child = (Bone)constrained[i];
|
||||
sortBone(child.parent);
|
||||
|
||||
@ -85,6 +85,20 @@ import com.esotericsoftware.spine.BoneData.Inherit;
|
||||
import com.esotericsoftware.spine.PathConstraintData.PositionMode;
|
||||
import com.esotericsoftware.spine.PathConstraintData.RotateMode;
|
||||
import com.esotericsoftware.spine.PathConstraintData.SpacingMode;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.FromProperty;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.FromRotate;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.FromScaleX;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.FromScaleY;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.FromShearY;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.FromX;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.FromY;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.ToProperty;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.ToRotate;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.ToScaleX;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.ToScaleY;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.ToShearY;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.ToX;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.ToY;
|
||||
import com.esotericsoftware.spine.attachments.Attachment;
|
||||
import com.esotericsoftware.spine.attachments.AttachmentLoader;
|
||||
import com.esotericsoftware.spine.attachments.AttachmentType;
|
||||
@ -269,21 +283,46 @@ public class SkeletonBinary extends SkeletonLoader {
|
||||
data.target = (BoneData)bones[input.readInt(true)];
|
||||
int flags = input.read();
|
||||
data.skinRequired = (flags & 1) != 0;
|
||||
data.local = (flags & 2) != 0;
|
||||
data.relative = (flags & 4) != 0;
|
||||
if ((flags & 8) != 0) data.offsetRotation = input.readFloat();
|
||||
if ((flags & 16) != 0) data.offsetX = input.readFloat() * scale;
|
||||
if ((flags & 32) != 0) data.offsetY = input.readFloat() * scale;
|
||||
if ((flags & 64) != 0) data.offsetScaleX = input.readFloat();
|
||||
if ((flags & 128) != 0) data.offsetScaleY = input.readFloat();
|
||||
data.localFrom = (flags & 2) != 0;
|
||||
data.localTo = (flags & 4) != 0;
|
||||
data.relative = (flags & 8) != 0;
|
||||
data.clamp = (flags & 16) != 0;
|
||||
nn = flags >> 5;
|
||||
for (int ii = 0, tn; ii < nn; ii++) {
|
||||
FromProperty from = switch (input.readByte()) {
|
||||
case 0 -> new FromRotate();
|
||||
case 1 -> new FromX();
|
||||
case 2 -> new FromY();
|
||||
case 3 -> new FromScaleX();
|
||||
case 4 -> new FromScaleY();
|
||||
case 5 -> new FromShearY();
|
||||
default -> null;
|
||||
};
|
||||
from.offset = input.readFloat() * scale;
|
||||
Object[] properties = from.to.setSize(tn = input.readInt(true));
|
||||
for (int t = 0; t < tn; t++) {
|
||||
ToProperty to = switch (input.readByte()) {
|
||||
case 0 -> new ToRotate();
|
||||
case 1 -> new ToX();
|
||||
case 2 -> new ToY();
|
||||
case 3 -> new ToScaleX();
|
||||
case 4 -> new ToScaleY();
|
||||
case 5 -> new ToShearY();
|
||||
default -> null;
|
||||
};
|
||||
to.offset = input.readFloat() * scale;
|
||||
to.max = input.readFloat() * scale;
|
||||
to.scale = input.readFloat();
|
||||
properties[i] = to;
|
||||
}
|
||||
}
|
||||
flags = input.read();
|
||||
if ((flags & 1) != 0) data.offsetShearY = input.readFloat();
|
||||
if ((flags & 2) != 0) data.mixRotate = input.readFloat();
|
||||
if ((flags & 4) != 0) data.mixX = input.readFloat();
|
||||
if ((flags & 8) != 0) data.mixY = input.readFloat();
|
||||
if ((flags & 16) != 0) data.mixScaleX = input.readFloat();
|
||||
if ((flags & 32) != 0) data.mixScaleY = input.readFloat();
|
||||
if ((flags & 64) != 0) data.mixShearY = input.readFloat();
|
||||
if ((flags & 1) != 0) data.mixRotate = input.readFloat();
|
||||
if ((flags & 2) != 0) data.mixX = input.readFloat();
|
||||
if ((flags & 4) != 0) data.mixY = input.readFloat();
|
||||
if ((flags & 8) != 0) data.mixScaleX = input.readFloat();
|
||||
if ((flags & 16) != 0) data.mixScaleY = input.readFloat();
|
||||
if ((flags & 32) != 0) data.mixShearY = input.readFloat();
|
||||
o[i] = data;
|
||||
}
|
||||
|
||||
|
||||
@ -86,6 +86,20 @@ import com.esotericsoftware.spine.BoneData.Inherit;
|
||||
import com.esotericsoftware.spine.PathConstraintData.PositionMode;
|
||||
import com.esotericsoftware.spine.PathConstraintData.RotateMode;
|
||||
import com.esotericsoftware.spine.PathConstraintData.SpacingMode;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.FromProperty;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.FromRotate;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.FromScaleX;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.FromScaleY;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.FromShearY;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.FromX;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.FromY;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.ToProperty;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.ToRotate;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.ToScaleX;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.ToScaleY;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.ToShearY;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.ToX;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.ToY;
|
||||
import com.esotericsoftware.spine.attachments.Attachment;
|
||||
import com.esotericsoftware.spine.attachments.AttachmentLoader;
|
||||
import com.esotericsoftware.spine.attachments.AttachmentType;
|
||||
@ -242,15 +256,38 @@ public class SkeletonJson extends SkeletonLoader {
|
||||
data.target = skeletonData.findBone(targetName);
|
||||
if (data.target == null) throw new SerializationException("Transform constraint target bone not found: " + targetName);
|
||||
|
||||
data.local = constraintMap.getBoolean("local", false);
|
||||
data.localFrom = constraintMap.getBoolean("localFrom", false);
|
||||
data.localTo = constraintMap.getBoolean("localTo", false);
|
||||
data.relative = constraintMap.getBoolean("relative", false);
|
||||
data.clamp = constraintMap.getBoolean("clamp", false);
|
||||
|
||||
data.offsetRotation = constraintMap.getFloat("rotation", 0);
|
||||
data.offsetX = constraintMap.getFloat("x", 0) * scale;
|
||||
data.offsetY = constraintMap.getFloat("y", 0) * scale;
|
||||
data.offsetScaleX = constraintMap.getFloat("scaleX", 0);
|
||||
data.offsetScaleY = constraintMap.getFloat("scaleY", 0);
|
||||
data.offsetShearY = constraintMap.getFloat("shearY", 0);
|
||||
for (JsonValue fromEntry = constraintMap.getChild("properties"); fromEntry != null; fromEntry = fromEntry.next) {
|
||||
FromProperty from = switch (fromEntry.name) {
|
||||
case "rotate" -> new FromRotate();
|
||||
case "x" -> new FromX();
|
||||
case "y" -> new FromY();
|
||||
case "scaleX" -> new FromScaleX();
|
||||
case "scaleY" -> new FromScaleY();
|
||||
case "shearY" -> new FromShearY();
|
||||
default -> throw new SerializationException("Invalid transform constraint from property: " + fromEntry.name);
|
||||
};
|
||||
from.offset = fromEntry.getFloat("offset", 0) * scale;
|
||||
for (JsonValue toEntry = constraintMap.getChild("to"); toEntry != null; toEntry = toEntry.next) {
|
||||
ToProperty to = switch (fromEntry.name) {
|
||||
case "rotate" -> new ToRotate();
|
||||
case "x" -> new ToX();
|
||||
case "y" -> new ToY();
|
||||
case "scaleX" -> new ToScaleX();
|
||||
case "scaleY" -> new ToScaleY();
|
||||
case "shearY" -> new ToShearY();
|
||||
default -> throw new SerializationException("Invalid transform constraint to property: " + fromEntry.name);
|
||||
};
|
||||
to.offset = toEntry.getFloat("offset", 0) * scale;
|
||||
to.max = toEntry.getFloat("max", 1) * scale;
|
||||
to.scale = toEntry.getFloat("scale");
|
||||
from.to.add(to);
|
||||
}
|
||||
}
|
||||
|
||||
data.mixRotate = constraintMap.getFloat("mixRotate", 1);
|
||||
data.mixX = constraintMap.getFloat("mixX", 1);
|
||||
|
||||
@ -29,12 +29,14 @@
|
||||
|
||||
package com.esotericsoftware.spine;
|
||||
|
||||
import static com.esotericsoftware.spine.utils.SpineUtils.*;
|
||||
import static com.badlogic.gdx.math.MathUtils.*;
|
||||
|
||||
import com.badlogic.gdx.math.Vector2;
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
import com.esotericsoftware.spine.Skeleton.Physics;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.FromProperty;
|
||||
import com.esotericsoftware.spine.TransformConstraintData.ToProperty;
|
||||
|
||||
/** Stores the current pose for a transform constraint. A transform constraint adjusts the world transform of the constrained
|
||||
* bones to match that of the target bone.
|
||||
@ -93,198 +95,31 @@ public class TransformConstraint implements Updatable {
|
||||
/** Applies the constraint to the constrained bones. */
|
||||
public void update (Physics physics) {
|
||||
if (mixRotate == 0 && mixX == 0 && mixY == 0 && mixScaleX == 0 && mixScaleY == 0 && mixShearY == 0) return;
|
||||
if (data.local) {
|
||||
if (data.relative)
|
||||
applyRelativeLocal();
|
||||
|
||||
boolean localFrom = data.localFrom, localTo = data.localTo, relative = data.relative, clamp = data.clamp;
|
||||
Bone target = this.target;
|
||||
Object[] fromItems = data.properties.items;
|
||||
int fn = data.properties.size;
|
||||
Object[] bones = this.bones.items;
|
||||
for (int i = 0, n = this.bones.size; i < n; i++) {
|
||||
var bone = (Bone)bones[i];
|
||||
for (int f = 0; f < fn; f++) {
|
||||
var from = (FromProperty)fromItems[f];
|
||||
if (from.mix(this) != 0) {
|
||||
float value = from.value(target, localFrom) - from.offset;
|
||||
Object[] toItems = from.to.items;
|
||||
for (int t = 0, tn = from.to.size; t < tn; t++) {
|
||||
var to = (ToProperty)toItems[t];
|
||||
float clamped = to.offset + value * to.scale;
|
||||
if (clamp) clamped = clamp(clamped, to.offset, to.max);
|
||||
to.apply(this, bone, clamped, localTo, relative);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (localTo)
|
||||
bone.update(null);
|
||||
else
|
||||
applyAbsoluteLocal();
|
||||
} else {
|
||||
if (data.relative)
|
||||
applyRelativeWorld();
|
||||
else
|
||||
applyAbsoluteWorld();
|
||||
}
|
||||
}
|
||||
|
||||
private void applyAbsoluteWorld () {
|
||||
float mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY, mixScaleX = this.mixScaleX,
|
||||
mixScaleY = this.mixScaleY, mixShearY = this.mixShearY;
|
||||
boolean translate = mixX != 0 || mixY != 0;
|
||||
|
||||
Bone target = this.target;
|
||||
float ta = target.a, tb = target.b, tc = target.c, td = target.d;
|
||||
float degRadReflect = ta * td - tb * tc > 0 ? degRad : -degRad;
|
||||
float offsetRotation = data.offsetRotation * degRadReflect, offsetShearY = data.offsetShearY * degRadReflect;
|
||||
|
||||
Object[] bones = this.bones.items;
|
||||
for (int i = 0, n = this.bones.size; i < n; i++) {
|
||||
Bone bone = (Bone)bones[i];
|
||||
|
||||
if (mixRotate != 0) {
|
||||
float a = bone.a, b = bone.b, c = bone.c, d = bone.d;
|
||||
float r = atan2(tc, ta) - atan2(c, a) + offsetRotation;
|
||||
if (r > PI)
|
||||
r -= PI2;
|
||||
else if (r < -PI) //
|
||||
r += PI2;
|
||||
r *= mixRotate;
|
||||
float cos = cos(r), sin = sin(r);
|
||||
bone.a = cos * a - sin * c;
|
||||
bone.b = cos * b - sin * d;
|
||||
bone.c = sin * a + cos * c;
|
||||
bone.d = sin * b + cos * d;
|
||||
}
|
||||
|
||||
if (translate) {
|
||||
Vector2 temp = this.temp;
|
||||
target.localToWorld(temp.set(data.offsetX, data.offsetY));
|
||||
bone.worldX += (temp.x - bone.worldX) * mixX;
|
||||
bone.worldY += (temp.y - bone.worldY) * mixY;
|
||||
}
|
||||
|
||||
if (mixScaleX != 0) {
|
||||
float s = (float)Math.sqrt(bone.a * bone.a + bone.c * bone.c);
|
||||
if (s != 0) s = (s + ((float)Math.sqrt(ta * ta + tc * tc) - s + data.offsetScaleX) * mixScaleX) / s;
|
||||
bone.a *= s;
|
||||
bone.c *= s;
|
||||
}
|
||||
if (mixScaleY != 0) {
|
||||
float s = (float)Math.sqrt(bone.b * bone.b + bone.d * bone.d);
|
||||
if (s != 0) s = (s + ((float)Math.sqrt(tb * tb + td * td) - s + data.offsetScaleY) * mixScaleY) / s;
|
||||
bone.b *= s;
|
||||
bone.d *= s;
|
||||
}
|
||||
|
||||
if (mixShearY > 0) {
|
||||
float b = bone.b, d = bone.d;
|
||||
float by = atan2(d, b);
|
||||
float r = atan2(td, tb) - atan2(tc, ta) - (by - atan2(bone.c, bone.a));
|
||||
if (r > PI)
|
||||
r -= PI2;
|
||||
else if (r < -PI) //
|
||||
r += PI2;
|
||||
r = by + (r + offsetShearY) * mixShearY;
|
||||
float s = (float)Math.sqrt(b * b + d * d);
|
||||
bone.b = cos(r) * s;
|
||||
bone.d = sin(r) * s;
|
||||
}
|
||||
|
||||
bone.updateAppliedTransform();
|
||||
}
|
||||
}
|
||||
|
||||
private void applyRelativeWorld () {
|
||||
float mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY, mixScaleX = this.mixScaleX,
|
||||
mixScaleY = this.mixScaleY, mixShearY = this.mixShearY;
|
||||
boolean translate = mixX != 0 || mixY != 0;
|
||||
|
||||
Bone target = this.target;
|
||||
float ta = target.a, tb = target.b, tc = target.c, td = target.d;
|
||||
float degRadReflect = ta * td - tb * tc > 0 ? degRad : -degRad;
|
||||
float offsetRotation = data.offsetRotation * degRadReflect, offsetShearY = data.offsetShearY * degRadReflect;
|
||||
|
||||
Object[] bones = this.bones.items;
|
||||
for (int i = 0, n = this.bones.size; i < n; i++) {
|
||||
Bone bone = (Bone)bones[i];
|
||||
|
||||
if (mixRotate != 0) {
|
||||
float a = bone.a, b = bone.b, c = bone.c, d = bone.d;
|
||||
float r = atan2(tc, ta) + offsetRotation;
|
||||
if (r > PI)
|
||||
r -= PI2;
|
||||
else if (r < -PI) //
|
||||
r += PI2;
|
||||
r *= mixRotate;
|
||||
float cos = cos(r), sin = sin(r);
|
||||
bone.a = cos * a - sin * c;
|
||||
bone.b = cos * b - sin * d;
|
||||
bone.c = sin * a + cos * c;
|
||||
bone.d = sin * b + cos * d;
|
||||
}
|
||||
|
||||
if (translate) {
|
||||
Vector2 temp = this.temp;
|
||||
target.localToWorld(temp.set(data.offsetX, data.offsetY));
|
||||
bone.worldX += temp.x * mixX;
|
||||
bone.worldY += temp.y * mixY;
|
||||
}
|
||||
|
||||
if (mixScaleX != 0) {
|
||||
float s = ((float)Math.sqrt(ta * ta + tc * tc) - 1 + data.offsetScaleX) * mixScaleX + 1;
|
||||
bone.a *= s;
|
||||
bone.c *= s;
|
||||
}
|
||||
if (mixScaleY != 0) {
|
||||
float s = ((float)Math.sqrt(tb * tb + td * td) - 1 + data.offsetScaleY) * mixScaleY + 1;
|
||||
bone.b *= s;
|
||||
bone.d *= s;
|
||||
}
|
||||
|
||||
if (mixShearY > 0) {
|
||||
float r = atan2(td, tb) - atan2(tc, ta);
|
||||
if (r > PI)
|
||||
r -= PI2;
|
||||
else if (r < -PI) //
|
||||
r += PI2;
|
||||
float b = bone.b, d = bone.d;
|
||||
r = atan2(d, b) + (r - PI / 2 + offsetShearY) * mixShearY;
|
||||
float s = (float)Math.sqrt(b * b + d * d);
|
||||
bone.b = cos(r) * s;
|
||||
bone.d = sin(r) * s;
|
||||
}
|
||||
|
||||
bone.updateAppliedTransform();
|
||||
}
|
||||
}
|
||||
|
||||
private void applyAbsoluteLocal () {
|
||||
float mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY, mixScaleX = this.mixScaleX,
|
||||
mixScaleY = this.mixScaleY, mixShearY = this.mixShearY;
|
||||
|
||||
Bone target = this.target;
|
||||
|
||||
Object[] bones = this.bones.items;
|
||||
for (int i = 0, n = this.bones.size; i < n; i++) {
|
||||
Bone bone = (Bone)bones[i];
|
||||
|
||||
float rotation = bone.arotation;
|
||||
if (mixRotate != 0) rotation += (target.arotation - rotation + data.offsetRotation) * mixRotate;
|
||||
|
||||
float x = bone.ax, y = bone.ay;
|
||||
x += (target.ax - x + data.offsetX) * mixX;
|
||||
y += (target.ay - y + data.offsetY) * mixY;
|
||||
|
||||
float scaleX = bone.ascaleX, scaleY = bone.ascaleY;
|
||||
if (mixScaleX != 0 && scaleX != 0)
|
||||
scaleX = (scaleX + (target.ascaleX - scaleX + data.offsetScaleX) * mixScaleX) / scaleX;
|
||||
if (mixScaleY != 0 && scaleY != 0)
|
||||
scaleY = (scaleY + (target.ascaleY - scaleY + data.offsetScaleY) * mixScaleY) / scaleY;
|
||||
|
||||
float shearY = bone.ashearY;
|
||||
if (mixShearY != 0) shearY += (target.ashearY - shearY + data.offsetShearY) * mixShearY;
|
||||
|
||||
bone.updateWorldTransform(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyRelativeLocal () {
|
||||
float mixRotate = this.mixRotate, mixX = this.mixX, mixY = this.mixY, mixScaleX = this.mixScaleX,
|
||||
mixScaleY = this.mixScaleY, mixShearY = this.mixShearY;
|
||||
|
||||
Bone target = this.target;
|
||||
|
||||
Object[] bones = this.bones.items;
|
||||
for (int i = 0, n = this.bones.size; i < n; i++) {
|
||||
Bone bone = (Bone)bones[i];
|
||||
|
||||
float rotation = bone.arotation + (target.arotation + data.offsetRotation) * mixRotate;
|
||||
float x = bone.ax + (target.ax + data.offsetX) * mixX;
|
||||
float y = bone.ay + (target.ay + data.offsetY) * mixY;
|
||||
float scaleX = bone.ascaleX * (((target.ascaleX - 1 + data.offsetScaleX) * mixScaleX) + 1);
|
||||
float scaleY = bone.ascaleY * (((target.ascaleY - 1 + data.offsetScaleY) * mixScaleY) + 1);
|
||||
float shearY = bone.ashearY + (target.ashearY + data.offsetShearY) * mixShearY;
|
||||
|
||||
bone.updateWorldTransform(x, y, rotation, scaleX, scaleY, bone.ashearX, shearY);
|
||||
bone.updateAppliedTransform();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -29,6 +29,8 @@
|
||||
|
||||
package com.esotericsoftware.spine;
|
||||
|
||||
import static com.esotericsoftware.spine.utils.SpineUtils.*;
|
||||
|
||||
import com.badlogic.gdx.utils.Array;
|
||||
|
||||
/** Stores the setup pose for a {@link TransformConstraint}.
|
||||
@ -38,8 +40,8 @@ public class TransformConstraintData extends ConstraintData {
|
||||
final Array<BoneData> bones = new Array();
|
||||
BoneData target;
|
||||
float mixRotate, mixX, mixY, mixScaleX, mixScaleY, mixShearY;
|
||||
float offsetRotation, offsetX, offsetY, offsetScaleX, offsetScaleY, offsetShearY;
|
||||
boolean relative, local;
|
||||
boolean localFrom, localTo, relative, clamp;
|
||||
final Array<FromProperty> properties = new Array();
|
||||
|
||||
public TransformConstraintData (String name) {
|
||||
super(name);
|
||||
@ -60,6 +62,11 @@ public class TransformConstraintData extends ConstraintData {
|
||||
this.target = target;
|
||||
}
|
||||
|
||||
/** The mapping of transform properties to other transform properties. */
|
||||
public Array<FromProperty> getProperties () {
|
||||
return properties;
|
||||
}
|
||||
|
||||
/** A percentage (0-1) that controls the mix between the constrained and unconstrained rotation. */
|
||||
public float getMixRotate () {
|
||||
return mixRotate;
|
||||
@ -114,58 +121,20 @@ public class TransformConstraintData extends ConstraintData {
|
||||
this.mixShearY = mixShearY;
|
||||
}
|
||||
|
||||
/** An offset added to the constrained bone rotation. */
|
||||
public float getOffsetRotation () {
|
||||
return offsetRotation;
|
||||
public boolean getLocalFrom () {
|
||||
return localFrom;
|
||||
}
|
||||
|
||||
public void setOffsetRotation (float offsetRotation) {
|
||||
this.offsetRotation = offsetRotation;
|
||||
public void setLocalFrom (boolean localFrom) {
|
||||
this.localFrom = localFrom;
|
||||
}
|
||||
|
||||
/** An offset added to the constrained bone X translation. */
|
||||
public float getOffsetX () {
|
||||
return offsetX;
|
||||
public boolean getLocalTo () {
|
||||
return localTo;
|
||||
}
|
||||
|
||||
public void setOffsetX (float offsetX) {
|
||||
this.offsetX = offsetX;
|
||||
}
|
||||
|
||||
/** An offset added to the constrained bone Y translation. */
|
||||
public float getOffsetY () {
|
||||
return offsetY;
|
||||
}
|
||||
|
||||
public void setOffsetY (float offsetY) {
|
||||
this.offsetY = offsetY;
|
||||
}
|
||||
|
||||
/** An offset added to the constrained bone scaleX. */
|
||||
public float getOffsetScaleX () {
|
||||
return offsetScaleX;
|
||||
}
|
||||
|
||||
public void setOffsetScaleX (float offsetScaleX) {
|
||||
this.offsetScaleX = offsetScaleX;
|
||||
}
|
||||
|
||||
/** An offset added to the constrained bone scaleY. */
|
||||
public float getOffsetScaleY () {
|
||||
return offsetScaleY;
|
||||
}
|
||||
|
||||
public void setOffsetScaleY (float offsetScaleY) {
|
||||
this.offsetScaleY = offsetScaleY;
|
||||
}
|
||||
|
||||
/** An offset added to the constrained bone shearY. */
|
||||
public float getOffsetShearY () {
|
||||
return offsetShearY;
|
||||
}
|
||||
|
||||
public void setOffsetShearY (float offsetShearY) {
|
||||
this.offsetShearY = offsetShearY;
|
||||
public void setLocalTo (boolean localTo) {
|
||||
this.localTo = localTo;
|
||||
}
|
||||
|
||||
public boolean getRelative () {
|
||||
@ -176,11 +145,205 @@ public class TransformConstraintData extends ConstraintData {
|
||||
this.relative = relative;
|
||||
}
|
||||
|
||||
public boolean getLocal () {
|
||||
return local;
|
||||
public boolean getClamp () {
|
||||
return clamp;
|
||||
}
|
||||
|
||||
public void setLocal (boolean local) {
|
||||
this.local = local;
|
||||
public void setClamp (boolean clamp) {
|
||||
this.clamp = clamp;
|
||||
}
|
||||
|
||||
static abstract public class FromProperty {
|
||||
public float offset;
|
||||
public final Array<ToProperty> to = new Array();
|
||||
|
||||
abstract public float value (Bone target, boolean local);
|
||||
|
||||
abstract public float mix (TransformConstraint constraint);
|
||||
}
|
||||
|
||||
static abstract public class ToProperty {
|
||||
public float offset, max, scale;
|
||||
|
||||
abstract public void apply (TransformConstraint constraint, Bone bone, float value, boolean local, boolean relative);
|
||||
}
|
||||
|
||||
static public class FromRotate extends FromProperty {
|
||||
public float value (Bone target, boolean local) {
|
||||
return local ? target.arotation : atan2(target.c, target.a) * radDeg;
|
||||
}
|
||||
|
||||
public float mix (TransformConstraint constraint) {
|
||||
return constraint.mixRotate;
|
||||
}
|
||||
}
|
||||
|
||||
static public class ToRotate extends ToProperty {
|
||||
public void apply (TransformConstraint constraint, Bone bone, float value, boolean local, boolean relative) {
|
||||
if (local) {
|
||||
if (!relative) value -= bone.arotation;
|
||||
bone.arotation += value * constraint.mixRotate;
|
||||
} else {
|
||||
float a = bone.a, b = bone.b, c = bone.c, d = bone.d;
|
||||
float r = value * degRad;
|
||||
if (!relative) r -= atan2(c, a);
|
||||
if (r > PI)
|
||||
r -= PI2;
|
||||
else if (r < -PI) //
|
||||
r += PI2;
|
||||
r *= constraint.mixRotate;
|
||||
float cos = cos(r), sin = sin(r);
|
||||
bone.a = cos * a - sin * c;
|
||||
bone.b = cos * b - sin * d;
|
||||
bone.c = sin * a + cos * c;
|
||||
bone.d = sin * b + cos * d;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static public class FromX extends FromProperty {
|
||||
public float value (Bone target, boolean local) {
|
||||
return local ? target.ax : target.worldX;
|
||||
}
|
||||
|
||||
public float mix (TransformConstraint constraint) {
|
||||
return constraint.mixX;
|
||||
}
|
||||
}
|
||||
|
||||
static public class ToX extends ToProperty {
|
||||
public void apply (TransformConstraint constraint, Bone bone, float value, boolean local, boolean relative) {
|
||||
if (local) {
|
||||
if (!relative) value -= bone.ax;
|
||||
bone.ax += value * constraint.mixX;
|
||||
} else {
|
||||
if (!relative) value -= bone.worldX;
|
||||
bone.worldX += value * constraint.mixX;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static public class FromY extends FromProperty {
|
||||
public float value (Bone target, boolean local) {
|
||||
return local ? target.ay : target.worldY;
|
||||
}
|
||||
|
||||
public float mix (TransformConstraint constraint) {
|
||||
return constraint.mixY;
|
||||
}
|
||||
}
|
||||
|
||||
static public class ToY extends ToProperty {
|
||||
public void apply (TransformConstraint constraint, Bone bone, float value, boolean local, boolean relative) {
|
||||
if (local) {
|
||||
if (!relative) value -= bone.ay;
|
||||
bone.ay += value * constraint.mixY;
|
||||
} else {
|
||||
if (!relative) value -= bone.worldY;
|
||||
bone.worldY += value * constraint.mixY;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static public class FromScaleX extends FromProperty {
|
||||
public float value (Bone target, boolean local) {
|
||||
return local ? target.arotation : (float)Math.sqrt(target.a * target.a + target.c * target.c);
|
||||
}
|
||||
|
||||
public float mix (TransformConstraint constraint) {
|
||||
return constraint.mixScaleX;
|
||||
}
|
||||
}
|
||||
|
||||
static public class ToScaleX extends ToProperty {
|
||||
public void apply (TransformConstraint constraint, Bone bone, float value, boolean local, boolean relative) {
|
||||
if (local) {
|
||||
if (relative)
|
||||
bone.ascaleX *= 1 + ((value - 1) * constraint.mixScaleX);
|
||||
else if (bone.ascaleX != 0) //
|
||||
bone.ascaleX = 1 + (value / bone.ascaleX - 1) * constraint.mixScaleX;
|
||||
} else {
|
||||
float s;
|
||||
if (relative)
|
||||
s = 1 + (value - 1) * constraint.mixScaleX;
|
||||
else {
|
||||
s = (float)Math.sqrt(bone.a * bone.a + bone.c * bone.c);
|
||||
if (s != 0) s = 1 + (value / s - 1) * constraint.mixScaleX;
|
||||
}
|
||||
bone.a *= s;
|
||||
bone.c *= s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static public class FromScaleY extends FromProperty {
|
||||
public float value (Bone target, boolean local) {
|
||||
return local ? target.arotation : (float)Math.sqrt(target.b * target.b + target.d * target.d);
|
||||
}
|
||||
|
||||
public float mix (TransformConstraint constraint) {
|
||||
return constraint.mixScaleY;
|
||||
}
|
||||
}
|
||||
|
||||
static public class ToScaleY extends ToProperty {
|
||||
public void apply (TransformConstraint constraint, Bone bone, float value, boolean local, boolean relative) {
|
||||
if (local) {
|
||||
if (relative)
|
||||
bone.ascaleY *= 1 + ((value - 1) * constraint.mixScaleY);
|
||||
else if (bone.ascaleY != 0) //
|
||||
bone.ascaleY = 1 + (value / bone.ascaleY - 1) * constraint.mixScaleY;
|
||||
} else {
|
||||
float s;
|
||||
if (relative)
|
||||
s = 1 + (value - 1) * constraint.mixScaleY;
|
||||
else {
|
||||
s = (float)Math.sqrt(bone.b * bone.b + bone.d * bone.d);
|
||||
if (s != 0) s = 1 + (value / s - 1) * constraint.mixScaleY;
|
||||
}
|
||||
bone.b *= s;
|
||||
bone.d *= s;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static public class FromShearY extends FromProperty {
|
||||
public float value (Bone target, boolean local) {
|
||||
if (local) return target.ashearY;
|
||||
float r = atan2(target.d, target.b) - atan2(target.c, target.a);
|
||||
if (r > PI)
|
||||
r -= PI2;
|
||||
else if (r < -PI) //
|
||||
r += PI2;
|
||||
return r;
|
||||
}
|
||||
|
||||
public float mix (TransformConstraint constraint) {
|
||||
return constraint.mixShearY;
|
||||
}
|
||||
}
|
||||
|
||||
static public class ToShearY extends ToProperty {
|
||||
public void apply (TransformConstraint constraint, Bone bone, float value, boolean local, boolean relative) {
|
||||
if (local) {
|
||||
if (!relative) value -= bone.ashearY;
|
||||
bone.ashearY += value * constraint.mixShearY;
|
||||
} else {
|
||||
float b = bone.b, d = bone.d, by = atan2(d, b);
|
||||
if (relative)
|
||||
value -= PI / 2;
|
||||
else {
|
||||
value -= by - atan2(bone.c, bone.a);
|
||||
if (value > PI)
|
||||
value -= PI2;
|
||||
else if (value < -PI) //
|
||||
value += PI2;
|
||||
}
|
||||
value = by + value * constraint.mixShearY;
|
||||
float s = (float)Math.sqrt(b * b + d * d);
|
||||
bone.b = cos(value) * s;
|
||||
bone.d = sin(value) * s;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user