mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-03-26 22:49:01 +08:00
Improved vertex attachment, paths.
This commit is contained in:
parent
c976f8038b
commit
c406e44785
@ -46,7 +46,7 @@ public class Skeleton {
|
|||||||
final Array<IkConstraint> ikConstraints;
|
final Array<IkConstraint> ikConstraints;
|
||||||
final Array<TransformConstraint> transformConstraints;
|
final Array<TransformConstraint> transformConstraints;
|
||||||
final Array<PathConstraint> pathConstraints;
|
final Array<PathConstraint> pathConstraints;
|
||||||
private final Array<Updatable> updateCache = new Array();
|
final Array<Updatable> updateCache = new Array();
|
||||||
Skin skin;
|
Skin skin;
|
||||||
final Color color;
|
final Color color;
|
||||||
float time;
|
float time;
|
||||||
|
|||||||
@ -43,7 +43,7 @@ public class BoundingBoxAttachment extends VertexAttachment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void computeWorldVertices (Slot slot, float[] worldVertices) {
|
public void computeWorldVertices (Slot slot, float[] worldVertices) {
|
||||||
super.computeWorldVertices(slot, worldVertices);
|
computeWorldVertices(slot, 0, worldVerticesLength, worldVertices, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Color getColor () {
|
public Color getColor () {
|
||||||
|
|||||||
@ -40,7 +40,7 @@ public class PathAttachment extends VertexAttachment {
|
|||||||
final Color color = new Color(1, 0.5f, 0, 1);
|
final Color color = new Color(1, 0.5f, 0, 1);
|
||||||
|
|
||||||
float[] worldVertices, lengths;
|
float[] worldVertices, lengths;
|
||||||
boolean closed;
|
boolean closed, constantSpeed;
|
||||||
|
|
||||||
public PathAttachment (String name) {
|
public PathAttachment (String name) {
|
||||||
super(name);
|
super(name);
|
||||||
@ -54,61 +54,55 @@ public class PathAttachment extends VertexAttachment {
|
|||||||
// BOZO - Remove check?
|
// BOZO - Remove check?
|
||||||
if (worldVerticesLength < 12) return;
|
if (worldVerticesLength < 12) return;
|
||||||
|
|
||||||
|
// BOZO - Path constraint rotation.
|
||||||
|
// BOZO - Closed paths.
|
||||||
|
// BOZO - Before/after open paths.
|
||||||
|
|
||||||
|
float x1, y1, cx1, cy1, cx2, cy2, x2, y2;
|
||||||
|
if (!constantSpeed) {
|
||||||
|
int curves = worldVerticesLength / 6 - 1;
|
||||||
|
int curve = position < 1 ? (int)(curves * position) : curves - 1;
|
||||||
|
position = (position - curve / (float)curves) * curves;
|
||||||
|
|
||||||
float[] worldVertices = this.worldVertices;
|
float[] worldVertices = this.worldVertices;
|
||||||
super.computeWorldVertices(slot, worldVertices);
|
super.computeWorldVertices(slot, curve * 6 + 2, 8, worldVertices, 0);
|
||||||
|
|
||||||
// Determine curve containing position.
|
x1 = worldVertices[0];
|
||||||
float pathLength = pathLengths(worldVertices);
|
y1 = worldVertices[1];
|
||||||
|
cx1 = worldVertices[2];
|
||||||
|
cy1 = worldVertices[3];
|
||||||
|
cx2 = worldVertices[4];
|
||||||
|
cy2 = worldVertices[5];
|
||||||
|
x2 = worldVertices[6];
|
||||||
|
y2 = worldVertices[7];
|
||||||
|
} else {
|
||||||
|
// BOZO - Use offset and count for all attachment compute methods.
|
||||||
|
float[] worldVertices = this.worldVertices;
|
||||||
|
int verticesLength = worldVerticesLength - 4;
|
||||||
|
super.computeWorldVertices(slot, 2, verticesLength, worldVertices, 0);
|
||||||
|
|
||||||
|
// Curve lengths.
|
||||||
float[] lengths = this.lengths;
|
float[] lengths = this.lengths;
|
||||||
float target = pathLength * position, distance = 0, t = 0;
|
float length = 0;
|
||||||
int curve = 0;
|
x1 = worldVertices[0];
|
||||||
for (;; curve++) {
|
y1 = worldVertices[1];
|
||||||
float length = lengths[curve];
|
float tmpx, tmpy, dddfx, dddfy, ddfx, ddfy, dfx, dfy;
|
||||||
float nextDistance = distance + length;
|
for (int i = 0, w = 2; w < verticesLength; i++, w += 6) {
|
||||||
if (nextDistance >= target) {
|
cx1 = worldVertices[w];
|
||||||
t = (target - distance) / length;
|
cy1 = worldVertices[w + 1];
|
||||||
break;
|
cx2 = worldVertices[w + 2];
|
||||||
}
|
cy2 = worldVertices[w + 3];
|
||||||
distance = nextDistance;
|
x2 = worldVertices[w + 4];
|
||||||
}
|
y2 = worldVertices[w + 5];
|
||||||
curve *= 6;
|
tmpx = (x1 - cx1 * 2 + cx2) * 0.1875f;
|
||||||
|
tmpy = (y1 - cy1 * 2 + cy2) * 0.1875f;
|
||||||
// Adjust t for constant speed using lengths of curves as weights.
|
dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375f;
|
||||||
t *= curveLengths(curve, worldVertices);
|
dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375f;
|
||||||
for (int i = 1;; i++) {
|
ddfx = tmpx * 2 + dddfx;
|
||||||
float length = lengths[i];
|
ddfy = tmpy * 2 + dddfy;
|
||||||
if (t >= length) {
|
dfx = (cx1 - x1) * 0.75f + tmpx + dddfx * 0.16666667f;
|
||||||
t = 1 - 0.1f * i + 0.1f * (t - length) / (lengths[i - 1] - length);
|
dfy = (cy1 - y1) * 0.75f + tmpy + dddfy * 0.16666667f;
|
||||||
break;
|
length += (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate point.
|
|
||||||
float x1 = worldVertices[curve], y1 = worldVertices[curve + 1];
|
|
||||||
float cx1 = worldVertices[curve + 4], cy1 = worldVertices[curve + 5];
|
|
||||||
float x2 = worldVertices[curve + 6], y2 = worldVertices[curve + 7];
|
|
||||||
float cx2 = worldVertices[curve + 8], cy2 = worldVertices[curve + 9];
|
|
||||||
float tt = t * t, ttt = tt * t, t3 = t * 3;
|
|
||||||
float x = (x1 + t * (-x1 * 3 + t * (3 * x1 - x1 * t))) + t * (3 * cx1 + t * (-6 * cx1 + cx1 * t3))
|
|
||||||
+ tt * (cx2 * 3 - cx2 * t3) + x2 * ttt;
|
|
||||||
float y = (y1 + t * (-y1 * 3 + t * (3 * y1 - y1 * t))) + t * (3 * cy1 + t * (-6 * cy1 + cy1 * t3))
|
|
||||||
+ tt * (cy2 * 3 - cy2 * t3) + y2 * ttt;
|
|
||||||
out.set(x, y);
|
|
||||||
}
|
|
||||||
|
|
||||||
private float pathLengths (float[] worldVertices) {
|
|
||||||
float[] lengths = this.lengths;
|
|
||||||
float total = 0;
|
|
||||||
float x1 = worldVertices[0], y1 = worldVertices[1];
|
|
||||||
for (int i = 0, w = 4, n = 4 + worldVerticesLength - 6; w < n; i++, w += 6) {
|
|
||||||
float cx1 = worldVertices[w], cy1 = worldVertices[w + 1];
|
|
||||||
float x2 = worldVertices[w + 2], y2 = worldVertices[w + 3];
|
|
||||||
float cx2 = worldVertices[w + 4], cy2 = worldVertices[w + 5];
|
|
||||||
float tmpx = (x1 - cx1 * 2 + cx2) * 0.1875f, tmpy = (y1 - cy1 * 2 + cy2) * 0.1875f;
|
|
||||||
float dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375f, dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375f;
|
|
||||||
float ddfx = tmpx * 2 + dddfx, ddfy = tmpy * 2 + dddfy;
|
|
||||||
float dfx = (cx1 - x1) * 0.75f + tmpx + dddfx * 0.16666667f, dfy = (cy1 - y1) * 0.75f + tmpy + dddfy * 0.16666667f;
|
|
||||||
float length = (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
|
||||||
dfx += ddfx;
|
dfx += ddfx;
|
||||||
dfy += ddfy;
|
dfy += ddfy;
|
||||||
ddfx += dddfx;
|
ddfx += dddfx;
|
||||||
@ -120,45 +114,87 @@ public class PathAttachment extends VertexAttachment {
|
|||||||
dfx += ddfx + dddfx;
|
dfx += ddfx + dddfx;
|
||||||
dfy += ddfy + dddfy;
|
dfy += ddfy + dddfy;
|
||||||
length += (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
length += (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
||||||
total += length;
|
|
||||||
lengths[i] = length;
|
lengths[i] = length;
|
||||||
x1 = x2;
|
x1 = x2;
|
||||||
y1 = y2;
|
y1 = y2;
|
||||||
}
|
}
|
||||||
return total;
|
|
||||||
|
// Determine curve containing position.
|
||||||
|
int curve;
|
||||||
|
position *= length;
|
||||||
|
length = lengths[0];
|
||||||
|
if (position <= length) {
|
||||||
|
curve = 0;
|
||||||
|
position /= length;
|
||||||
|
} else {
|
||||||
|
for (curve = 1;; curve++) {
|
||||||
|
length = lengths[curve];
|
||||||
|
if (position <= length) {
|
||||||
|
float prev = lengths[curve - 1];
|
||||||
|
position = (position - prev) / (length - prev);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
curve *= 6;
|
||||||
}
|
}
|
||||||
|
|
||||||
private float curveLengths (int curve, float[] worldVertices) {
|
// Curve segment lengths.
|
||||||
float x1 = worldVertices[curve], y1 = worldVertices[curve + 1];
|
x1 = worldVertices[curve];
|
||||||
float cx1 = worldVertices[curve + 4], cy1 = worldVertices[curve + 5];
|
y1 = worldVertices[curve + 1];
|
||||||
float x2 = worldVertices[curve + 6], y2 = worldVertices[curve + 7];
|
cx1 = worldVertices[curve + 2];
|
||||||
float cx2 = worldVertices[curve + 8], cy2 = worldVertices[curve + 9];
|
cy1 = worldVertices[curve + 3];
|
||||||
float tmpx = (x1 - cx1 * 2 + cx2) * 0.03f, tmpy = (y1 - cy1 * 2 + cy2) * 0.03f;
|
cx2 = worldVertices[curve + 4];
|
||||||
float dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.006f, dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.006f;
|
cy2 = worldVertices[curve + 5];
|
||||||
float ddfx = tmpx * 2 + dddfx, ddfy = tmpy * 2 + dddfy;
|
x2 = worldVertices[curve + 6];
|
||||||
float dfx = (cx1 - x1) * 0.3f + tmpx + dddfx * 0.16666667f, dfy = (cy1 - y1) * 0.3f + tmpy + dddfy * 0.16666667f;
|
y2 = worldVertices[curve + 7];
|
||||||
float[] lengths = this.lengths;
|
tmpx = (x1 - cx1 * 2 + cx2) * 0.03f;
|
||||||
lengths[10] = 0;
|
tmpy = (y1 - cy1 * 2 + cy2) * 0.03f;
|
||||||
float total = 0;
|
dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.006f;
|
||||||
for (int i = 9; i > 2; i--) {
|
dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.006f;
|
||||||
total += (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
ddfx = tmpx * 2 + dddfx;
|
||||||
lengths[i] = total;
|
ddfy = tmpy * 2 + dddfy;
|
||||||
|
dfx = (cx1 - x1) * 0.3f + tmpx + dddfx * 0.16666667f;
|
||||||
|
dfy = (cy1 - y1) * 0.3f + tmpy + dddfy * 0.16666667f;
|
||||||
|
length = (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
||||||
|
lengths[0] = length;
|
||||||
|
for (int i = 1; i < 8; i++) {
|
||||||
dfx += ddfx;
|
dfx += ddfx;
|
||||||
dfy += ddfy;
|
dfy += ddfy;
|
||||||
ddfx += dddfx;
|
ddfx += dddfx;
|
||||||
ddfy += dddfy;
|
ddfy += dddfy;
|
||||||
|
length += (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
||||||
|
lengths[i] = length;
|
||||||
}
|
}
|
||||||
total += (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
|
||||||
lengths[2] = total;
|
|
||||||
dfx += ddfx;
|
dfx += ddfx;
|
||||||
dfy += ddfy;
|
dfy += ddfy;
|
||||||
total += (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
length += (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
||||||
lengths[1] = total;
|
lengths[8] = length;
|
||||||
dfx += ddfx + dddfx;
|
dfx += ddfx + dddfx;
|
||||||
dfy += ddfy + dddfy;
|
dfy += ddfy + dddfy;
|
||||||
total += (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
length += (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
||||||
lengths[0] = total;
|
lengths[9] = length;
|
||||||
return total;
|
|
||||||
|
// Weight by segment length.
|
||||||
|
position *= length;
|
||||||
|
length = lengths[0];
|
||||||
|
if (position <= length)
|
||||||
|
position = 0.1f * position / length;
|
||||||
|
else {
|
||||||
|
for (int i = 1;; i++) {
|
||||||
|
length = lengths[i];
|
||||||
|
if (position <= length) {
|
||||||
|
float prev = lengths[i - 1];
|
||||||
|
position = 0.1f * (i + (position - prev) / (length - prev));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calculate point.
|
||||||
|
float ttt = position * position * position, u = 1 - position;
|
||||||
|
float uuu = u * u * u, ut3 = u * position * 3, uut3 = u * ut3, utt3 = position * ut3;
|
||||||
|
out.set(x1 * uuu + cx1 * uut3 + cx2 * utt3 + x2 * ttt, y1 * uuu + cy1 * uut3 + cy2 * utt3 + y2 * ttt);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Color getColor () {
|
public Color getColor () {
|
||||||
@ -173,10 +209,18 @@ public class PathAttachment extends VertexAttachment {
|
|||||||
this.closed = closed;
|
this.closed = closed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public boolean getConstantSpeed () {
|
||||||
|
return constantSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setConstantSpeed (boolean constantSpeed) {
|
||||||
|
this.constantSpeed = constantSpeed;
|
||||||
|
}
|
||||||
|
|
||||||
public void setWorldVerticesLength (int worldVerticesLength) {
|
public void setWorldVerticesLength (int worldVerticesLength) {
|
||||||
super.setWorldVerticesLength(worldVerticesLength);
|
super.setWorldVerticesLength(worldVerticesLength);
|
||||||
// BOZO! - Don't reallocate for editor.
|
// BOZO! - Don't reallocate for editor.
|
||||||
worldVertices = new float[Math.max(2, worldVerticesLength)];
|
worldVertices = new float[Math.max(2, worldVerticesLength)];
|
||||||
lengths = new float[Math.max(11, worldVerticesLength >> 1)];
|
lengths = new float[Math.max(10, worldVerticesLength / 6 - 1)];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -47,31 +47,45 @@ public class VertexAttachment extends Attachment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected void computeWorldVertices (Slot slot, float[] worldVertices) {
|
protected void computeWorldVertices (Slot slot, float[] worldVertices) {
|
||||||
|
computeWorldVertices(slot, 0, worldVerticesLength, worldVertices, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Transforms local vertices to world coordinates.
|
||||||
|
* @param start The index of the first local vertex value to transform. Each vertex has 2 values, x and y.
|
||||||
|
* @param count The number of world vertex values to output. Must be <= {@link #getWorldVerticesLength()} - start.
|
||||||
|
* @param worldVertices The output world vertices. Must have a length >= offset + count.
|
||||||
|
* @param offset The worldVertices index to begin writing values. */
|
||||||
|
protected void computeWorldVertices (Slot slot, int start, int count, float[] worldVertices, int offset) {
|
||||||
|
count += offset;
|
||||||
Skeleton skeleton = slot.getSkeleton();
|
Skeleton skeleton = slot.getSkeleton();
|
||||||
float x = skeleton.getX(), y = skeleton.getY();
|
float x = skeleton.getX(), y = skeleton.getY();
|
||||||
FloatArray deformArray = slot.getAttachmentVertices();
|
FloatArray deformArray = slot.getAttachmentVertices();
|
||||||
float[] vertices = this.vertices;
|
float[] vertices = this.vertices;
|
||||||
int[] bones = this.bones;
|
int[] bones = this.bones;
|
||||||
if (bones == null) {
|
if (bones == null) {
|
||||||
int verticesLength = vertices.length;
|
|
||||||
if (deformArray.size > 0) vertices = deformArray.items;
|
if (deformArray.size > 0) vertices = deformArray.items;
|
||||||
Bone bone = slot.getBone();
|
Bone bone = slot.getBone();
|
||||||
x += bone.getWorldX();
|
x += bone.getWorldX();
|
||||||
y += bone.getWorldY();
|
y += bone.getWorldY();
|
||||||
float a = bone.getA(), b = bone.getB(), c = bone.getC(), d = bone.getD();
|
float a = bone.getA(), b = bone.getB(), c = bone.getC(), d = bone.getD();
|
||||||
for (int v = 0; v < verticesLength; v += 2) {
|
for (int v = start, w = offset; w < count; v += 2, w += 2) {
|
||||||
float vx = vertices[v], vy = vertices[v + 1];
|
float vx = vertices[v], vy = vertices[v + 1];
|
||||||
worldVertices[v] = vx * a + vy * b + x;
|
worldVertices[w] = vx * a + vy * b + x;
|
||||||
worldVertices[v + 1] = vx * c + vy * d + y;
|
worldVertices[w + 1] = vx * c + vy * d + y;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
int v = 0, skip = 0;
|
||||||
|
for (int i = 0; i < start; i += 2) {
|
||||||
|
int n = bones[v];
|
||||||
|
v += n + 1;
|
||||||
|
skip += n;
|
||||||
|
}
|
||||||
Object[] skeletonBones = skeleton.getBones().items;
|
Object[] skeletonBones = skeleton.getBones().items;
|
||||||
if (deformArray.size == 0) {
|
if (deformArray.size == 0) {
|
||||||
for (int w = 0, v = 0, b = 0, n = bones.length; v < n; w += 2) {
|
for (int w = offset, b = skip * 3; w < count; w += 2) {
|
||||||
float wx = x, wy = y;
|
float wx = x, wy = y;
|
||||||
int nn = bones[v++] + v;
|
for (int n = bones[v++] + v; v < n; v++, b += 3) {
|
||||||
for (; v < nn; v++, b += 3) {
|
|
||||||
Bone bone = (Bone)skeletonBones[bones[v]];
|
Bone bone = (Bone)skeletonBones[bones[v]];
|
||||||
float vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2];
|
float vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2];
|
||||||
wx += (vx * bone.getA() + vy * bone.getB() + bone.getWorldX()) * weight;
|
wx += (vx * bone.getA() + vy * bone.getB() + bone.getWorldX()) * weight;
|
||||||
@ -82,10 +96,9 @@ public class VertexAttachment extends Attachment {
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
float[] deform = deformArray.items;
|
float[] deform = deformArray.items;
|
||||||
for (int w = 0, v = 0, b = 0, f = 0, n = bones.length; v < n; w += 2) {
|
for (int w = offset, b = skip * 3, f = skip << 1; w < count; w += 2) {
|
||||||
float wx = x, wy = y;
|
float wx = x, wy = y;
|
||||||
int nn = bones[v++] + v;
|
for (int n = bones[v++] + v; v < n; v++, b += 3, f += 2) {
|
||||||
for (; v < nn; v++, b += 3, f += 2) {
|
|
||||||
Bone bone = (Bone)skeletonBones[bones[v]];
|
Bone bone = (Bone)skeletonBones[bones[v]];
|
||||||
float vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2];
|
float vx = vertices[b] + deform[f], vy = vertices[b + 1] + deform[f + 1], weight = vertices[b + 2];
|
||||||
wx += (vx * bone.getA() + vy * bone.getB() + bone.getWorldX()) * weight;
|
wx += (vx * bone.getA() + vy * bone.getB() + bone.getWorldX()) * weight;
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user