Stop previous stream when a new one starts; ease animations
Starting a movie now closes the current decode engine and bumps a playback generation so the stale video/audio threads stop themselves (they were overlapping the movie's canvas and audio). PlaybackEngine.close is idempotent. Animation records now honor their accelMode (linear/accel/decel easing).
This commit is contained in:
@@ -66,6 +66,7 @@ public final class PlaybackEngine implements AutoCloseable {
|
||||
|
||||
private volatile boolean eof = false;
|
||||
private volatile IOException failure = null;
|
||||
private volatile boolean closed = false;
|
||||
private final Thread decodeThread;
|
||||
|
||||
private PlaybackEngine(UmdIsoReader iso, String streamName, int audioSubstream) throws IOException {
|
||||
@@ -254,6 +255,10 @@ public final class PlaybackEngine implements AutoCloseable {
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
if (closed) {
|
||||
return;
|
||||
}
|
||||
closed = true;
|
||||
decodeThread.interrupt();
|
||||
try {
|
||||
decodeThread.join(1000);
|
||||
|
||||
@@ -26,7 +26,7 @@ public class FadeAnim extends BaseAnim {
|
||||
return;
|
||||
}
|
||||
float sa = target.alphaScale.getFloatValue();
|
||||
Animator.getInstance().add(new Tween(millis, p -> {
|
||||
Animator.getInstance().add(new Tween(millis, accelMode.getIntValue(), p -> {
|
||||
target.alphaScale.setFloatValue(sa + (ta - sa) * p);
|
||||
target.onDisplayUpdated();
|
||||
}));
|
||||
|
||||
@@ -34,7 +34,7 @@ public class MoveToAnim extends BaseAnim {
|
||||
float sx = target.animX;
|
||||
float sy = target.animY;
|
||||
float sz = target.animZ;
|
||||
Animator.getInstance().add(new Tween(millis, p -> {
|
||||
Animator.getInstance().add(new Tween(millis, accelMode.getIntValue(), p -> {
|
||||
target.animX = sx + (tx - sx) * p;
|
||||
target.animY = sy + (ty - sy) * p;
|
||||
target.animZ = sz + (tz - sz) * p;
|
||||
|
||||
@@ -38,7 +38,7 @@ public class RecolourAnim extends BaseAnim {
|
||||
float sg = target.greenScale.getFloatValue();
|
||||
float sb = target.blueScale.getFloatValue();
|
||||
float sa = target.alphaScale.getFloatValue();
|
||||
Animator.getInstance().add(new Tween(millis, p -> {
|
||||
Animator.getInstance().add(new Tween(millis, accelMode.getIntValue(), p -> {
|
||||
target.redScale.setFloatValue(sr + (tr - sr) * p);
|
||||
target.greenScale.setFloatValue(sg + (tg - sg) * p);
|
||||
target.blueScale.setFloatValue(sb + (tb - sb) * p);
|
||||
|
||||
@@ -34,7 +34,7 @@ public class ResizeAnim extends BaseAnim {
|
||||
float sw = target.scaleWidth.getFloatValue();
|
||||
float sh = target.scaleHeight.getFloatValue();
|
||||
float sd = target.scaleDepth.getFloatValue();
|
||||
Animator.getInstance().add(new Tween(millis, p -> {
|
||||
Animator.getInstance().add(new Tween(millis, accelMode.getIntValue(), p -> {
|
||||
target.scaleWidth.setFloatValue(sw + (tw - sw) * p);
|
||||
target.scaleHeight.setFloatValue(sh + (th - sh) * p);
|
||||
target.scaleDepth.setFloatValue(sd + (td - sd) * p);
|
||||
|
||||
@@ -34,7 +34,7 @@ public class RotateAnim extends BaseAnim {
|
||||
float sx = target.rotX;
|
||||
float sy = target.rotY;
|
||||
float sz = target.rotZ;
|
||||
Animator.getInstance().add(new Tween(millis, p -> {
|
||||
Animator.getInstance().add(new Tween(millis, accelMode.getIntValue(), p -> {
|
||||
target.rotX = sx + (tx - sx) * p;
|
||||
target.rotY = sy + (ty - sy) * p;
|
||||
target.rotZ = sz + (tz - sz) * p;
|
||||
|
||||
@@ -3,10 +3,17 @@ package dev.quoije.umd.rco.anim;
|
||||
|
||||
/**
|
||||
* A single interpolation from 0..1 over a duration in milliseconds. The
|
||||
* callback receives linear progress each frame until completion.
|
||||
* callback receives eased progress each frame until completion.
|
||||
*/
|
||||
public final class Tween {
|
||||
|
||||
/** Linear progress (no easing). */
|
||||
public static final int EASE_LINEAR = 0;
|
||||
/** Accelerate: slow start, fast finish. */
|
||||
public static final int EASE_IN = 1;
|
||||
/** Decelerate: fast start, slow finish. */
|
||||
public static final int EASE_OUT = 2;
|
||||
|
||||
/** Receives progress 0..1 on every animation tick. */
|
||||
@FunctionalInterface
|
||||
public interface ProgressCallback {
|
||||
@@ -15,12 +22,18 @@ public final class Tween {
|
||||
|
||||
private final long startNanos;
|
||||
private final long durationNanos;
|
||||
private final int accelMode;
|
||||
private final ProgressCallback callback;
|
||||
private boolean finished;
|
||||
|
||||
public Tween(long durationMillis, ProgressCallback callback) {
|
||||
this(durationMillis, EASE_LINEAR, callback);
|
||||
}
|
||||
|
||||
public Tween(long durationMillis, int accelMode, ProgressCallback callback) {
|
||||
this.startNanos = System.nanoTime();
|
||||
this.durationNanos = Math.max(1L, durationMillis) * 1_000_000L;
|
||||
this.accelMode = accelMode;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
@@ -31,7 +44,15 @@ public final class Tween {
|
||||
progress = 1f;
|
||||
finished = true;
|
||||
}
|
||||
callback.apply(progress);
|
||||
callback.apply(ease(progress, accelMode));
|
||||
return finished;
|
||||
}
|
||||
|
||||
private static float ease(float p, int accelMode) {
|
||||
return switch (accelMode) {
|
||||
case EASE_IN -> p * p;
|
||||
case EASE_OUT -> 1f - (1f - p) * (1f - p);
|
||||
default -> p;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user