mirror of
https://github.com/EsotericSoftware/spine-runtimes.git
synced 2026-02-04 14:24:53 +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<TransformConstraint> transformConstraints;
|
||||
final Array<PathConstraint> pathConstraints;
|
||||
private final Array<Updatable> updateCache = new Array();
|
||||
final Array<Updatable> updateCache = new Array();
|
||||
Skin skin;
|
||||
final Color color;
|
||||
float time;
|
||||
|
||||
@ -43,7 +43,7 @@ public class BoundingBoxAttachment extends VertexAttachment {
|
||||
}
|
||||
|
||||
public void computeWorldVertices (Slot slot, float[] worldVertices) {
|
||||
super.computeWorldVertices(slot, worldVertices);
|
||||
computeWorldVertices(slot, 0, worldVerticesLength, worldVertices, 0);
|
||||
}
|
||||
|
||||
public Color getColor () {
|
||||
|
||||
@ -40,7 +40,7 @@ public class PathAttachment extends VertexAttachment {
|
||||
final Color color = new Color(1, 0.5f, 0, 1);
|
||||
|
||||
float[] worldVertices, lengths;
|
||||
boolean closed;
|
||||
boolean closed, constantSpeed;
|
||||
|
||||
public PathAttachment (String name) {
|
||||
super(name);
|
||||
@ -54,111 +54,147 @@ public class PathAttachment extends VertexAttachment {
|
||||
// BOZO - Remove check?
|
||||
if (worldVerticesLength < 12) return;
|
||||
|
||||
float[] worldVertices = this.worldVertices;
|
||||
super.computeWorldVertices(slot, worldVertices);
|
||||
// BOZO - Path constraint rotation.
|
||||
// BOZO - Closed paths.
|
||||
// BOZO - Before/after open paths.
|
||||
|
||||
// Determine curve containing position.
|
||||
float pathLength = pathLengths(worldVertices);
|
||||
float[] lengths = this.lengths;
|
||||
float target = pathLength * position, distance = 0, t = 0;
|
||||
int curve = 0;
|
||||
for (;; curve++) {
|
||||
float length = lengths[curve];
|
||||
float nextDistance = distance + length;
|
||||
if (nextDistance >= target) {
|
||||
t = (target - distance) / length;
|
||||
break;
|
||||
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;
|
||||
super.computeWorldVertices(slot, curve * 6 + 2, 8, worldVertices, 0);
|
||||
|
||||
x1 = worldVertices[0];
|
||||
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 length = 0;
|
||||
x1 = worldVertices[0];
|
||||
y1 = worldVertices[1];
|
||||
float tmpx, tmpy, dddfx, dddfy, ddfx, ddfy, dfx, dfy;
|
||||
for (int i = 0, w = 2; w < verticesLength; i++, w += 6) {
|
||||
cx1 = worldVertices[w];
|
||||
cy1 = worldVertices[w + 1];
|
||||
cx2 = worldVertices[w + 2];
|
||||
cy2 = worldVertices[w + 3];
|
||||
x2 = worldVertices[w + 4];
|
||||
y2 = worldVertices[w + 5];
|
||||
tmpx = (x1 - cx1 * 2 + cx2) * 0.1875f;
|
||||
tmpy = (y1 - cy1 * 2 + cy2) * 0.1875f;
|
||||
dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.09375f;
|
||||
dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.09375f;
|
||||
ddfx = tmpx * 2 + dddfx;
|
||||
ddfy = tmpy * 2 + dddfy;
|
||||
dfx = (cx1 - x1) * 0.75f + tmpx + dddfx * 0.16666667f;
|
||||
dfy = (cy1 - y1) * 0.75f + tmpy + dddfy * 0.16666667f;
|
||||
length += (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
dfx += ddfx;
|
||||
dfy += ddfy;
|
||||
ddfx += dddfx;
|
||||
ddfy += dddfy;
|
||||
length += (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
dfx += ddfx;
|
||||
dfy += ddfy;
|
||||
length += (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
dfx += ddfx + dddfx;
|
||||
dfy += ddfy + dddfy;
|
||||
length += (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
lengths[i] = length;
|
||||
x1 = x2;
|
||||
y1 = y2;
|
||||
}
|
||||
distance = nextDistance;
|
||||
}
|
||||
curve *= 6;
|
||||
|
||||
// Adjust t for constant speed using lengths of curves as weights.
|
||||
t *= curveLengths(curve, worldVertices);
|
||||
for (int i = 1;; i++) {
|
||||
float length = lengths[i];
|
||||
if (t >= length) {
|
||||
t = 1 - 0.1f * i + 0.1f * (t - length) / (lengths[i - 1] - length);
|
||||
break;
|
||||
// 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;
|
||||
}
|
||||
|
||||
// Curve segment lengths.
|
||||
x1 = worldVertices[curve];
|
||||
y1 = worldVertices[curve + 1];
|
||||
cx1 = worldVertices[curve + 2];
|
||||
cy1 = worldVertices[curve + 3];
|
||||
cx2 = worldVertices[curve + 4];
|
||||
cy2 = worldVertices[curve + 5];
|
||||
x2 = worldVertices[curve + 6];
|
||||
y2 = worldVertices[curve + 7];
|
||||
tmpx = (x1 - cx1 * 2 + cx2) * 0.03f;
|
||||
tmpy = (y1 - cy1 * 2 + cy2) * 0.03f;
|
||||
dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.006f;
|
||||
dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.006f;
|
||||
ddfx = tmpx * 2 + dddfx;
|
||||
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;
|
||||
dfy += ddfy;
|
||||
ddfx += dddfx;
|
||||
ddfy += dddfy;
|
||||
length += (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
lengths[i] = length;
|
||||
}
|
||||
dfx += ddfx;
|
||||
dfy += ddfy;
|
||||
length += (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
lengths[8] = length;
|
||||
dfx += ddfx + dddfx;
|
||||
dfy += ddfy + dddfy;
|
||||
length += (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
lengths[9] = length;
|
||||
|
||||
// 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 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;
|
||||
dfy += ddfy;
|
||||
ddfx += dddfx;
|
||||
ddfy += dddfy;
|
||||
length += (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
dfx += ddfx;
|
||||
dfy += ddfy;
|
||||
length += (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
dfx += ddfx + dddfx;
|
||||
dfy += ddfy + dddfy;
|
||||
length += (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
total += length;
|
||||
lengths[i] = length;
|
||||
x1 = x2;
|
||||
y1 = y2;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
|
||||
private float curveLengths (int curve, float[] worldVertices) {
|
||||
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 tmpx = (x1 - cx1 * 2 + cx2) * 0.03f, tmpy = (y1 - cy1 * 2 + cy2) * 0.03f;
|
||||
float dddfx = ((cx1 - cx2) * 3 - x1 + x2) * 0.006f, dddfy = ((cy1 - cy2) * 3 - y1 + y2) * 0.006f;
|
||||
float ddfx = tmpx * 2 + dddfx, ddfy = tmpy * 2 + dddfy;
|
||||
float dfx = (cx1 - x1) * 0.3f + tmpx + dddfx * 0.16666667f, dfy = (cy1 - y1) * 0.3f + tmpy + dddfy * 0.16666667f;
|
||||
float[] lengths = this.lengths;
|
||||
lengths[10] = 0;
|
||||
float total = 0;
|
||||
for (int i = 9; i > 2; i--) {
|
||||
total += (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
lengths[i] = total;
|
||||
dfx += ddfx;
|
||||
dfy += ddfy;
|
||||
ddfx += dddfx;
|
||||
ddfy += dddfy;
|
||||
}
|
||||
total += (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
lengths[2] = total;
|
||||
dfx += ddfx;
|
||||
dfy += ddfy;
|
||||
total += (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
lengths[1] = total;
|
||||
dfx += ddfx + dddfx;
|
||||
dfy += ddfy + dddfy;
|
||||
total += (float)Math.sqrt(dfx * dfx + dfy * dfy);
|
||||
lengths[0] = total;
|
||||
return total;
|
||||
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 () {
|
||||
@ -173,10 +209,18 @@ public class PathAttachment extends VertexAttachment {
|
||||
this.closed = closed;
|
||||
}
|
||||
|
||||
public boolean getConstantSpeed () {
|
||||
return constantSpeed;
|
||||
}
|
||||
|
||||
public void setConstantSpeed (boolean constantSpeed) {
|
||||
this.constantSpeed = constantSpeed;
|
||||
}
|
||||
|
||||
public void setWorldVerticesLength (int worldVerticesLength) {
|
||||
super.setWorldVerticesLength(worldVerticesLength);
|
||||
// BOZO! - Don't reallocate for editor.
|
||||
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) {
|
||||
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();
|
||||
float x = skeleton.getX(), y = skeleton.getY();
|
||||
FloatArray deformArray = slot.getAttachmentVertices();
|
||||
float[] vertices = this.vertices;
|
||||
int[] bones = this.bones;
|
||||
if (bones == null) {
|
||||
int verticesLength = vertices.length;
|
||||
if (deformArray.size > 0) vertices = deformArray.items;
|
||||
Bone bone = slot.getBone();
|
||||
x += bone.getWorldX();
|
||||
y += bone.getWorldY();
|
||||
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];
|
||||
worldVertices[v] = vx * a + vy * b + x;
|
||||
worldVertices[v + 1] = vx * c + vy * d + y;
|
||||
worldVertices[w] = vx * a + vy * b + x;
|
||||
worldVertices[w + 1] = vx * c + vy * d + y;
|
||||
}
|
||||
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;
|
||||
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;
|
||||
int nn = bones[v++] + v;
|
||||
for (; v < nn; v++, b += 3) {
|
||||
for (int n = bones[v++] + v; v < n; v++, b += 3) {
|
||||
Bone bone = (Bone)skeletonBones[bones[v]];
|
||||
float vx = vertices[b], vy = vertices[b + 1], weight = vertices[b + 2];
|
||||
wx += (vx * bone.getA() + vy * bone.getB() + bone.getWorldX()) * weight;
|
||||
@ -82,10 +96,9 @@ public class VertexAttachment extends Attachment {
|
||||
}
|
||||
} else {
|
||||
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;
|
||||
int nn = bones[v++] + v;
|
||||
for (; v < nn; v++, b += 3, f += 2) {
|
||||
for (int n = bones[v++] + v; v < n; v++, b += 3, f += 2) {
|
||||
Bone bone = (Bone)skeletonBones[bones[v]];
|
||||
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;
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user