From e675410a012862da9df9c7095a6a5d4db86aa065 Mon Sep 17 00:00:00 2001 From: Stephen Gold Date: Wed, 8 Feb 2023 11:43:34 -0800 Subject: [PATCH 1/2] solve issue #1806 (global FrameInterpolator violates threading model) --- .../main/java/com/jme3/anim/MorphTrack.java | 12 ++++++++--- .../java/com/jme3/anim/TransformTrack.java | 13 +++++++++--- .../anim/interpolator/FrameInterpolator.java | 21 ++++++++++++++++++- 3 files changed, 39 insertions(+), 7 deletions(-) diff --git a/jme3-core/src/main/java/com/jme3/anim/MorphTrack.java b/jme3-core/src/main/java/com/jme3/anim/MorphTrack.java index e4c6fdd233..ee767d2885 100644 --- a/jme3-core/src/main/java/com/jme3/anim/MorphTrack.java +++ b/jme3-core/src/main/java/com/jme3/anim/MorphTrack.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2021 jMonkeyEngine + * Copyright (c) 2009-2023 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -52,7 +52,11 @@ public class MorphTrack implements AnimTrack { * Weights and times for track. */ private float[] weights; - private FrameInterpolator interpolator = FrameInterpolator.DEFAULT; + /** + * The interpolator to use, or null to always use the default interpolator + * of the current thread. + */ + private FrameInterpolator interpolator = null; private float[] times; private int nbMorphTargets; @@ -219,7 +223,9 @@ public void getDataAtTime(double t, float[] store) { / (times[endFrame] - times[startFrame]); } - interpolator.interpolateWeights(blend, startFrame, weights, nbMorphTargets, store); + FrameInterpolator fi = (interpolator == null) + ? FrameInterpolator.getThreadDefault() : interpolator; + fi.interpolateWeights(blend, startFrame, weights, nbMorphTargets, store); } /** diff --git a/jme3-core/src/main/java/com/jme3/anim/TransformTrack.java b/jme3-core/src/main/java/com/jme3/anim/TransformTrack.java index b226c6d7a5..3492d17eec 100644 --- a/jme3-core/src/main/java/com/jme3/anim/TransformTrack.java +++ b/jme3-core/src/main/java/com/jme3/anim/TransformTrack.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2021 jMonkeyEngine + * Copyright (c) 2009-2023 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -50,7 +50,11 @@ public class TransformTrack implements AnimTrack { private double length; - private FrameInterpolator interpolator = FrameInterpolator.DEFAULT; + /** + * The interpolator to use, or null to always use the default interpolator + * of the current thread. + */ + private FrameInterpolator interpolator = null; private HasLocalTransform target; /** @@ -281,7 +285,10 @@ public void getDataAtTime(double t, Transform transform) { / (times[endFrame] - times[startFrame]); } - Transform interpolated = interpolator.interpolate(blend, startFrame, translations, rotations, scales, times); + FrameInterpolator fi = (interpolator == null) + ? FrameInterpolator.getThreadDefault() : interpolator; + Transform interpolated = fi.interpolate( + blend, startFrame, translations, rotations, scales, times); if (translations != null) { transform.setTranslation(interpolated.getTranslation()); diff --git a/jme3-core/src/main/java/com/jme3/anim/interpolator/FrameInterpolator.java b/jme3-core/src/main/java/com/jme3/anim/interpolator/FrameInterpolator.java index 89cde24dda..d09947fc0b 100644 --- a/jme3-core/src/main/java/com/jme3/anim/interpolator/FrameInterpolator.java +++ b/jme3-core/src/main/java/com/jme3/anim/interpolator/FrameInterpolator.java @@ -1,5 +1,5 @@ /* - * Copyright (c) 2009-2021 jMonkeyEngine + * Copyright (c) 2009-2023 jMonkeyEngine * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -38,7 +38,16 @@ * Created by nehon on 15/04/17. */ public class FrameInterpolator { + /** + * A global default instance of this class, for compatibility with JME v3.5. + * Due to issue #1806, use of this instance is discouraged. + */ public static final FrameInterpolator DEFAULT = new FrameInterpolator(); + /** + * The per-thread default instances of this class. + */ + private static final ThreadLocal THREAD_DEFAULT + = ThreadLocal.withInitial(() -> new FrameInterpolator()); private AnimInterpolator timeInterpolator; private AnimInterpolator translationInterpolator = AnimInterpolators.LinearVec3f; @@ -52,6 +61,16 @@ public class FrameInterpolator { final private Transform transforms = new Transform(); + /** + * Obtain the default interpolator for the current thread. + * + * @return the pre-existing instance (not null) + */ + public static FrameInterpolator getThreadDefault() { + FrameInterpolator result = THREAD_DEFAULT.get(); + return result; + } + public Transform interpolate(float t, int currentIndex, CompactVector3Array translations, CompactQuaternionArray rotations, CompactVector3Array scales, float[] times) { timesReader.setData(times); From 487998637583758870ac9f1a85cf7f3092c89c57 Mon Sep 17 00:00:00 2001 From: Stephen Gold Date: Wed, 8 Feb 2023 11:53:28 -0800 Subject: [PATCH 2/2] FrameInterpolator: deprecate the global instance --- .../java/com/jme3/anim/interpolator/FrameInterpolator.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/jme3-core/src/main/java/com/jme3/anim/interpolator/FrameInterpolator.java b/jme3-core/src/main/java/com/jme3/anim/interpolator/FrameInterpolator.java index d09947fc0b..13c7d2f183 100644 --- a/jme3-core/src/main/java/com/jme3/anim/interpolator/FrameInterpolator.java +++ b/jme3-core/src/main/java/com/jme3/anim/interpolator/FrameInterpolator.java @@ -41,7 +41,10 @@ public class FrameInterpolator { /** * A global default instance of this class, for compatibility with JME v3.5. * Due to issue #1806, use of this instance is discouraged. + * + * @deprecated use {@link #getThreadDefault()} */ + @Deprecated public static final FrameInterpolator DEFAULT = new FrameInterpolator(); /** * The per-thread default instances of this class.