[libgdx] Fixed RGB2 and RGBA2 timeline flicker.

Also the `alpha != 1 && blend == setup` was incorrect.

related EsotericSoftware/spine-editor#931
This commit is contained in:
Nathan Sweet 2026-03-10 21:23:45 -04:00
parent 1cef1397c0
commit 604a09b3fb

View File

@ -1072,21 +1072,18 @@ public class Animation {
if (time < frames[0]) {
Color setup = slot.data.setup.color;
switch (blend) {
case setup -> {
case setup:
color.r = setup.r;
color.g = setup.g;
color.b = setup.b;
// Fall through.
default:
return;
}
case first -> {
case first:
r = color.r + (setup.r - color.r) * alpha;
g = color.g + (setup.g - color.g) * alpha;
b = color.b + (setup.b - color.b) * alpha;
}
default -> {
return;
}
}
} else {
int i = search(frames, time, ENTRIES), curveType = (int)curves[i >> 2];
switch (curveType) {
@ -1156,14 +1153,13 @@ public class Animation {
if (time < frames[0]) {
Color setup = slot.data.setup.color;
switch (blend) {
case setup -> {
case setup:
color.a = setup.a;
// Fall through.
default:
return;
}
case first -> a = color.a + (setup.a - color.a) * alpha;
default -> {
return;
}
case first:
a = color.a + (setup.a - color.a) * alpha;
}
} else {
a = getCurveValue(time);
@ -1211,89 +1207,91 @@ public class Animation {
}
protected void apply (Slot slot, SlotPose pose, float time, float alpha, MixBlend blend) {
float[] frames = this.frames;
Color light = pose.color, dark = pose.darkColor;
float r2, g2, b2;
float[] frames = this.frames;
if (time < frames[0]) {
SlotPose setup = slot.data.setup;
Color setupLight = setup.color, setupDark = setup.darkColor;
switch (blend) {
case setup -> {
case setup:
light.set(setupLight);
dark.r = setupDark.r;
dark.g = setupDark.g;
dark.b = setupDark.b;
}
case first -> {
// Fall through.
default:
return;
case first:
light.add((setupLight.r - light.r) * alpha, (setupLight.g - light.g) * alpha, (setupLight.b - light.b) * alpha,
(setupLight.a - light.a) * alpha);
dark.r += (setupDark.r - dark.r) * alpha;
dark.g += (setupDark.g - dark.g) * alpha;
dark.b += (setupDark.b - dark.b) * alpha;
r2 = dark.r + (setupDark.r - dark.r) * alpha;
g2 = dark.g + (setupDark.g - dark.g) * alpha;
b2 = dark.b + (setupDark.b - dark.b) * alpha;
}
}
return;
}
float r, g, b, a, r2, g2, b2;
int i = search(frames, time, ENTRIES), curveType = (int)curves[i >> 3];
switch (curveType) {
case LINEAR -> {
float before = frames[i];
r = frames[i + R];
g = frames[i + G];
b = frames[i + B];
a = frames[i + A];
r2 = frames[i + R2];
g2 = frames[i + G2];
b2 = frames[i + B2];
float t = (time - before) / (frames[i + ENTRIES] - before);
r += (frames[i + ENTRIES + R] - r) * t;
g += (frames[i + ENTRIES + G] - g) * t;
b += (frames[i + ENTRIES + B] - b) * t;
a += (frames[i + ENTRIES + A] - a) * t;
r2 += (frames[i + ENTRIES + R2] - r2) * t;
g2 += (frames[i + ENTRIES + G2] - g2) * t;
b2 += (frames[i + ENTRIES + B2] - b2) * t;
}
case STEPPED -> {
r = frames[i + R];
g = frames[i + G];
b = frames[i + B];
a = frames[i + A];
r2 = frames[i + R2];
g2 = frames[i + G2];
b2 = frames[i + B2];
}
default -> {
r = getBezierValue(time, i, R, curveType - BEZIER);
g = getBezierValue(time, i, G, curveType + BEZIER_SIZE - BEZIER);
b = getBezierValue(time, i, B, curveType + BEZIER_SIZE * 2 - BEZIER);
a = getBezierValue(time, i, A, curveType + BEZIER_SIZE * 3 - BEZIER);
r2 = getBezierValue(time, i, R2, curveType + BEZIER_SIZE * 4 - BEZIER);
g2 = getBezierValue(time, i, G2, curveType + BEZIER_SIZE * 5 - BEZIER);
b2 = getBezierValue(time, i, B2, curveType + BEZIER_SIZE * 6 - BEZIER);
}
}
if (alpha == 1) {
light.set(r, g, b, a);
dark.r = r2;
dark.g = g2;
dark.b = b2;
} else {
if (blend == setup) {
SlotPose setup = slot.data.setup;
light.set(setup.color);
Color setupDark = setup.darkColor;
dark.r = setupDark.r;
dark.g = setupDark.g;
dark.b = setupDark.b;
float r, g, b, a;
int i = search(frames, time, ENTRIES), curveType = (int)curves[i >> 3];
switch (curveType) {
case LINEAR -> {
float before = frames[i];
r = frames[i + R];
g = frames[i + G];
b = frames[i + B];
a = frames[i + A];
r2 = frames[i + R2];
g2 = frames[i + G2];
b2 = frames[i + B2];
float t = (time - before) / (frames[i + ENTRIES] - before);
r += (frames[i + ENTRIES + R] - r) * t;
g += (frames[i + ENTRIES + G] - g) * t;
b += (frames[i + ENTRIES + B] - b) * t;
a += (frames[i + ENTRIES + A] - a) * t;
r2 += (frames[i + ENTRIES + R2] - r2) * t;
g2 += (frames[i + ENTRIES + G2] - g2) * t;
b2 += (frames[i + ENTRIES + B2] - b2) * t;
}
case STEPPED -> {
r = frames[i + R];
g = frames[i + G];
b = frames[i + B];
a = frames[i + A];
r2 = frames[i + R2];
g2 = frames[i + G2];
b2 = frames[i + B2];
}
default -> {
r = getBezierValue(time, i, R, curveType - BEZIER);
g = getBezierValue(time, i, G, curveType + BEZIER_SIZE - BEZIER);
b = getBezierValue(time, i, B, curveType + BEZIER_SIZE * 2 - BEZIER);
a = getBezierValue(time, i, A, curveType + BEZIER_SIZE * 3 - BEZIER);
r2 = getBezierValue(time, i, R2, curveType + BEZIER_SIZE * 4 - BEZIER);
g2 = getBezierValue(time, i, G2, curveType + BEZIER_SIZE * 5 - BEZIER);
b2 = getBezierValue(time, i, B2, curveType + BEZIER_SIZE * 6 - BEZIER);
}
}
if (alpha == 1)
light.set(r, g, b, a);
else if (blend == setup) {
SlotPose setupPose = slot.data.setup;
Color setup = setupPose.color;
light.set(setup.r + (r - setup.r) * alpha, setup.g + (g - setup.g) * alpha, setup.b + (b - setup.b) * alpha,
setup.a + (a - setup.a) * alpha);
setup = setupPose.darkColor;
r2 = setup.r + (r2 - setup.r) * alpha;
g2 = setup.g + (g2 - setup.g) * alpha;
b2 = setup.b + (b2 - setup.b) * alpha;
} else {
light.add((r - light.r) * alpha, (g - light.g) * alpha, (b - light.b) * alpha, (a - light.a) * alpha);
r2 = dark.r + (r2 - dark.r) * alpha;
g2 = dark.g + (g2 - dark.g) * alpha;
b2 = dark.b + (b2 - dark.b) * alpha;
}
light.add((r - light.r) * alpha, (g - light.g) * alpha, (b - light.b) * alpha, (a - light.a) * alpha);
dark.r += (r2 - dark.r) * alpha;
dark.g += (g2 - dark.g) * alpha;
dark.b += (b2 - dark.b) * alpha;
}
dark.r = r2 < 0 ? 0 : (r2 > 1 ? 1 : r2);
dark.g = g2 < 0 ? 0 : (g2 > 1 ? 1 : g2);
dark.b = b2 < 0 ? 0 : (b2 > 1 ? 1 : b2);
}
}
@ -1327,94 +1325,95 @@ public class Animation {
}
protected void apply (Slot slot, SlotPose pose, float time, float alpha, MixBlend blend) {
float[] frames = this.frames;
Color light = pose.color, dark = pose.darkColor;
float r, g, b, r2, g2, b2;
float[] frames = this.frames;
if (time < frames[0]) {
SlotPose setup = slot.data.setup;
Color setupLight = setup.color, setupDark = setup.darkColor;
switch (blend) {
case setup -> {
case setup:
light.r = setupLight.r;
light.g = setupLight.g;
light.b = setupLight.b;
dark.r = setupDark.r;
dark.g = setupDark.g;
dark.b = setupDark.b;
// Fall through.
default:
return;
case first:
r = light.r + (setupLight.r - light.r) * alpha;
g = light.g + (setupLight.g - light.g) * alpha;
b = light.b + (setupLight.b - light.b) * alpha;
r2 = dark.r + (setupDark.r - dark.r) * alpha;
g2 = dark.g + (setupDark.g - dark.g) * alpha;
b2 = dark.b + (setupDark.b - dark.b) * alpha;
}
case first -> {
light.r += (setupLight.r - light.r) * alpha;
light.g += (setupLight.g - light.g) * alpha;
light.b += (setupLight.b - light.b) * alpha;
dark.r += (setupDark.r - dark.r) * alpha;
dark.g += (setupDark.g - dark.g) * alpha;
dark.b += (setupDark.b - dark.b) * alpha;
}
}
return;
}
float r, g, b, r2, g2, b2;
int i = search(frames, time, ENTRIES), curveType = (int)curves[i / ENTRIES];
switch (curveType) {
case LINEAR -> {
float before = frames[i];
r = frames[i + R];
g = frames[i + G];
b = frames[i + B];
r2 = frames[i + R2];
g2 = frames[i + G2];
b2 = frames[i + B2];
float t = (time - before) / (frames[i + ENTRIES] - before);
r += (frames[i + ENTRIES + R] - r) * t;
g += (frames[i + ENTRIES + G] - g) * t;
b += (frames[i + ENTRIES + B] - b) * t;
r2 += (frames[i + ENTRIES + R2] - r2) * t;
g2 += (frames[i + ENTRIES + G2] - g2) * t;
b2 += (frames[i + ENTRIES + B2] - b2) * t;
}
case STEPPED -> {
r = frames[i + R];
g = frames[i + G];
b = frames[i + B];
r2 = frames[i + R2];
g2 = frames[i + G2];
b2 = frames[i + B2];
}
default -> {
r = getBezierValue(time, i, R, curveType - BEZIER);
g = getBezierValue(time, i, G, curveType + BEZIER_SIZE - BEZIER);
b = getBezierValue(time, i, B, curveType + BEZIER_SIZE * 2 - BEZIER);
r2 = getBezierValue(time, i, R2, curveType + BEZIER_SIZE * 3 - BEZIER);
g2 = getBezierValue(time, i, G2, curveType + BEZIER_SIZE * 4 - BEZIER);
b2 = getBezierValue(time, i, B2, curveType + BEZIER_SIZE * 5 - BEZIER);
}
}
if (alpha == 1) {
light.r = r;
light.g = g;
light.b = b;
dark.r = r2;
dark.g = g2;
dark.b = b2;
} else {
if (blend == setup) {
SlotPose setup = slot.data.setup;
Color setupLight = setup.color, setupDark = setup.darkColor;
light.r = setupLight.r;
light.g = setupLight.g;
light.b = setupLight.b;
dark.r = setupDark.r;
dark.g = setupDark.g;
dark.b = setupDark.b;
int i = search(frames, time, ENTRIES), curveType = (int)curves[i / ENTRIES];
switch (curveType) {
case LINEAR -> {
float before = frames[i];
r = frames[i + R];
g = frames[i + G];
b = frames[i + B];
r2 = frames[i + R2];
g2 = frames[i + G2];
b2 = frames[i + B2];
float t = (time - before) / (frames[i + ENTRIES] - before);
r += (frames[i + ENTRIES + R] - r) * t;
g += (frames[i + ENTRIES + G] - g) * t;
b += (frames[i + ENTRIES + B] - b) * t;
r2 += (frames[i + ENTRIES + R2] - r2) * t;
g2 += (frames[i + ENTRIES + G2] - g2) * t;
b2 += (frames[i + ENTRIES + B2] - b2) * t;
}
case STEPPED -> {
r = frames[i + R];
g = frames[i + G];
b = frames[i + B];
r2 = frames[i + R2];
g2 = frames[i + G2];
b2 = frames[i + B2];
}
default -> {
r = getBezierValue(time, i, R, curveType - BEZIER);
g = getBezierValue(time, i, G, curveType + BEZIER_SIZE - BEZIER);
b = getBezierValue(time, i, B, curveType + BEZIER_SIZE * 2 - BEZIER);
r2 = getBezierValue(time, i, R2, curveType + BEZIER_SIZE * 3 - BEZIER);
g2 = getBezierValue(time, i, G2, curveType + BEZIER_SIZE * 4 - BEZIER);
b2 = getBezierValue(time, i, B2, curveType + BEZIER_SIZE * 5 - BEZIER);
}
}
if (alpha != 1) {
if (blend == setup) {
SlotPose setupPose = slot.data.setup;
Color setup = setupPose.color;
r = setup.r + (r - setup.r) * alpha;
g = setup.g + (g - setup.g) * alpha;
b = setup.b + (b - setup.b) * alpha;
setup = setupPose.darkColor;
r2 = setup.r + (r2 - setup.r) * alpha;
g2 = setup.g + (g2 - setup.g) * alpha;
b2 = setup.b + (b2 - setup.b) * alpha;
} else {
r = light.r + (r - light.r) * alpha;
g = light.g + (g - light.g) * alpha;
b = light.b + (b - light.b) * alpha;
r2 = dark.r + (r2 - dark.r) * alpha;
g2 = dark.g + (g2 - dark.g) * alpha;
b2 = dark.b + (b2 - dark.b) * alpha;
}
}
light.r += (r - light.r) * alpha;
light.g += (g - light.g) * alpha;
light.b += (b - light.b) * alpha;
dark.r += (r2 - dark.r) * alpha;
dark.g += (g2 - dark.g) * alpha;
dark.b += (b2 - dark.b) * alpha;
}
light.r = r < 0 ? 0 : (r > 1 ? 1 : r);
light.g = g < 0 ? 0 : (g > 1 ? 1 : g);
light.b = b < 0 ? 0 : (b > 1 ? 1 : b);
dark.r = r2 < 0 ? 0 : (r2 > 1 ? 1 : r2);
dark.g = g2 < 0 ? 0 : (g2 > 1 ? 1 : g2);
dark.b = b2 < 0 ? 0 : (b2 > 1 ? 1 : b2);
}
}