parent
a8845a1506
commit
ce88350abf
@ -1,87 +0,0 @@ |
||||
package com.jme3.anim.tween; |
||||
|
||||
import com.jme3.anim.AnimClip; |
||||
import com.jme3.anim.TransformTrack; |
||||
import com.jme3.anim.tween.action.Action; |
||||
import com.jme3.anim.util.HasLocalTransform; |
||||
import com.jme3.anim.util.Weighted; |
||||
import com.jme3.export.InputCapsule; |
||||
import com.jme3.export.JmeExporter; |
||||
import com.jme3.export.JmeImporter; |
||||
import com.jme3.export.OutputCapsule; |
||||
import com.jme3.math.Transform; |
||||
import com.jme3.util.clone.Cloner; |
||||
import com.jme3.util.clone.JmeCloneable; |
||||
|
||||
import java.io.IOException; |
||||
|
||||
public class AnimClipTween implements Tween, Weighted, JmeCloneable { |
||||
|
||||
private AnimClip clip; |
||||
private Transform transform = new Transform(); |
||||
private float weight = 1f; |
||||
private Action parentAction; |
||||
|
||||
public AnimClipTween() { |
||||
} |
||||
|
||||
public AnimClipTween(AnimClip clip) { |
||||
this.clip = clip; |
||||
} |
||||
|
||||
@Override |
||||
public double getLength() { |
||||
return clip.getLength(); |
||||
} |
||||
|
||||
@Override |
||||
public boolean interpolate(double t) { |
||||
// Sanity check the inputs
|
||||
if (t < 0) { |
||||
return true; |
||||
} |
||||
if (parentAction != null) { |
||||
weight = parentAction.getWeightForTween(this); |
||||
} |
||||
if (weight == 0) { |
||||
//weight is 0 let's not interpolate
|
||||
return t < clip.getLength(); |
||||
} |
||||
TransformTrack[] tracks = clip.getTracks(); |
||||
for (TransformTrack track : tracks) { |
||||
HasLocalTransform target = track.getTarget(); |
||||
transform.set(target.getLocalTransform()); |
||||
track.getTransformAtTime(t, transform); |
||||
|
||||
if (weight == 1f) { |
||||
target.setLocalTransform(transform); |
||||
} else { |
||||
Transform tr = target.getLocalTransform(); |
||||
tr.interpolateTransforms(tr, transform, weight); |
||||
target.setLocalTransform(tr); |
||||
} |
||||
} |
||||
return t < clip.getLength(); |
||||
} |
||||
|
||||
|
||||
@Override |
||||
public Object jmeClone() { |
||||
try { |
||||
AnimClipTween clone = (AnimClipTween) super.clone(); |
||||
return clone; |
||||
} catch (CloneNotSupportedException ex) { |
||||
throw new AssertionError(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void cloneFields(Cloner cloner, Object original) { |
||||
clip = cloner.clone(clip); |
||||
} |
||||
|
||||
@Override |
||||
public void setParentAction(Action action) { |
||||
this.parentAction = action; |
||||
} |
||||
} |
@ -0,0 +1,6 @@ |
||||
package com.jme3.anim.tween; |
||||
|
||||
public interface ContainsTweens { |
||||
|
||||
public Tween[] getTweens(); |
||||
} |
@ -0,0 +1,40 @@ |
||||
package com.jme3.anim.tween.action; |
||||
|
||||
import com.jme3.anim.tween.ContainsTweens; |
||||
import com.jme3.anim.tween.Tween; |
||||
import com.jme3.util.SafeArrayList; |
||||
|
||||
public class BaseAction extends Action { |
||||
|
||||
private Tween tween; |
||||
private SafeArrayList<Action> subActions = new SafeArrayList<>(Action.class); |
||||
|
||||
public BaseAction(Tween tween) { |
||||
this.tween = tween; |
||||
length = tween.getLength(); |
||||
gatherActions(tween); |
||||
} |
||||
|
||||
private void gatherActions(Tween tween) { |
||||
if (tween instanceof Action) { |
||||
subActions.add((Action) tween); |
||||
} else if (tween instanceof ContainsTweens) { |
||||
Tween[] tweens = ((ContainsTweens) tween).getTweens(); |
||||
for (Tween t : tweens) { |
||||
gatherActions(t); |
||||
} |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public void setWeight(float weight) { |
||||
for (Action action : subActions.getArray()) { |
||||
action.setWeight(weight); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public boolean interpolate(double t) { |
||||
return tween.interpolate(t); |
||||
} |
||||
} |
@ -1,80 +1,129 @@ |
||||
package com.jme3.anim.tween.action; |
||||
|
||||
import com.jme3.anim.tween.Tween; |
||||
import com.jme3.anim.tween.Tweens; |
||||
import com.jme3.anim.util.HasLocalTransform; |
||||
import com.jme3.math.Transform; |
||||
|
||||
public class BlendAction extends Action { |
||||
import java.util.Collection; |
||||
import java.util.HashMap; |
||||
import java.util.Map; |
||||
|
||||
public class BlendAction extends BlendableAction { |
||||
|
||||
private Tween firstActiveTween; |
||||
private Tween secondActiveTween; |
||||
private int firstActiveIndex; |
||||
private int secondActiveIndex; |
||||
private BlendSpace blendSpace; |
||||
private float blendWeight; |
||||
private double[] timeFactor; |
||||
private Map<HasLocalTransform, Transform> targetMap = new HashMap<>(); |
||||
|
||||
public BlendAction(BlendSpace blendSpace, Tween... tweens) { |
||||
super(tweens); |
||||
public BlendAction(BlendSpace blendSpace, BlendableAction... actions) { |
||||
super(actions); |
||||
timeFactor = new double[actions.length]; |
||||
this.blendSpace = blendSpace; |
||||
blendSpace.setBlendAction(this); |
||||
|
||||
for (Tween tween : tweens) { |
||||
if (tween.getLength() > length) { |
||||
length = tween.getLength(); |
||||
for (BlendableAction action : actions) { |
||||
if (action.getLength() > length) { |
||||
length = action.getLength(); |
||||
} |
||||
Collection<HasLocalTransform> targets = action.getTargets(); |
||||
for (HasLocalTransform target : targets) { |
||||
Transform t = targetMap.get(target); |
||||
if (t == null) { |
||||
t = new Transform(); |
||||
targetMap.put(target, t); |
||||
} |
||||
} |
||||
} |
||||
|
||||
//Blending effect maybe unexpected when blended animation don't have the same length
|
||||
//Stretching any tween that doesn't have the same length.
|
||||
for (int i = 0; i < tweens.length; i++) { |
||||
if (tweens[i].getLength() != length) { |
||||
tweens[i] = Tweens.stretch(length, tweens[i]); |
||||
//Stretching any action that doesn't have the same length.
|
||||
for (int i = 0; i < this.actions.length; i++) { |
||||
this.timeFactor[i] = 1; |
||||
if (this.actions[i].getLength() != length) { |
||||
double actionLength = this.actions[i].getLength(); |
||||
if (actionLength > 0 && length > 0) { |
||||
this.timeFactor[i] = this.actions[i].getLength() / length; |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public float getWeightForTween(Tween tween) { |
||||
public void doInterpolate(double t) { |
||||
blendWeight = blendSpace.getWeight(); |
||||
if (tween == firstActiveTween) { |
||||
return 1f; |
||||
BlendableAction firstActiveAction = (BlendableAction) actions[firstActiveIndex]; |
||||
BlendableAction secondActiveAction = (BlendableAction) actions[secondActiveIndex]; |
||||
firstActiveAction.setCollectTransformDelegate(this); |
||||
secondActiveAction.setCollectTransformDelegate(this); |
||||
|
||||
//only interpolate the first action if the weight if below 1.
|
||||
if (blendWeight < 1f) { |
||||
firstActiveAction.setWeight(1f); |
||||
firstActiveAction.interpolate(t * timeFactor[firstActiveIndex]); |
||||
if (blendWeight == 0) { |
||||
for (HasLocalTransform target : targetMap.keySet()) { |
||||
collect(target, targetMap.get(target)); |
||||
} |
||||
return weight * blendWeight; |
||||
} |
||||
|
||||
@Override |
||||
public boolean doInterpolate(double t) { |
||||
if (firstActiveTween == null) { |
||||
blendSpace.getWeight(); |
||||
} |
||||
|
||||
boolean running = this.firstActiveTween.interpolate(t); |
||||
this.secondActiveTween.interpolate(t); |
||||
//Second action should be interpolated
|
||||
secondActiveAction.setWeight(blendWeight); |
||||
secondActiveAction.interpolate(t * timeFactor[secondActiveIndex]); |
||||
|
||||
firstActiveAction.setCollectTransformDelegate(null); |
||||
secondActiveAction.setCollectTransformDelegate(null); |
||||
|
||||
if (!running) { |
||||
return false; |
||||
} |
||||
|
||||
return true; |
||||
protected Action[] getActions() { |
||||
return actions; |
||||
} |
||||
|
||||
@Override |
||||
public void reset() { |
||||
public BlendSpace getBlendSpace() { |
||||
return blendSpace; |
||||
} |
||||
|
||||
protected void setFirstActiveIndex(int index) { |
||||
this.firstActiveIndex = index; |
||||
} |
||||
|
||||
protected Tween[] getTweens() { |
||||
return tweens; |
||||
protected void setSecondActiveIndex(int index) { |
||||
this.secondActiveIndex = index; |
||||
} |
||||
|
||||
public BlendSpace getBlendSpace() { |
||||
return blendSpace; |
||||
@Override |
||||
public Collection<HasLocalTransform> getTargets() { |
||||
return targetMap.keySet(); |
||||
} |
||||
|
||||
protected void setFirstActiveTween(Tween firstActiveTween) { |
||||
this.firstActiveTween = firstActiveTween; |
||||
@Override |
||||
public void collectTransform(HasLocalTransform target, Transform t, float weight, BlendableAction source) { |
||||
|
||||
Transform tr = targetMap.get(target); |
||||
if (weight == 1) { |
||||
tr.set(t); |
||||
} else if (weight > 0) { |
||||
tr.interpolateTransforms(tr, t, weight); |
||||
} |
||||
|
||||
protected void setSecondActiveTween(Tween secondActiveTween) { |
||||
this.secondActiveTween = secondActiveTween; |
||||
if (source == actions[secondActiveIndex]) { |
||||
collect(target, tr); |
||||
} |
||||
} |
||||
|
||||
private void collect(HasLocalTransform target, Transform tr) { |
||||
if (collectTransformDelegate != null) { |
||||
collectTransformDelegate.collectTransform(target, tr, this.weight, this); |
||||
} else { |
||||
if (getTransitionWeight() == 1) { |
||||
target.setLocalTransform(tr); |
||||
} else { |
||||
Transform trans = target.getLocalTransform(); |
||||
trans.interpolateTransforms(trans, tr, getTransitionWeight()); |
||||
target.setLocalTransform(trans); |
||||
} |
||||
} |
||||
} |
||||
|
||||
} |
||||
|
@ -0,0 +1,83 @@ |
||||
package com.jme3.anim.tween.action; |
||||
|
||||
import com.jme3.anim.tween.AbstractTween; |
||||
import com.jme3.anim.tween.Tween; |
||||
import com.jme3.anim.util.HasLocalTransform; |
||||
import com.jme3.math.Transform; |
||||
|
||||
import java.util.Collection; |
||||
|
||||
public abstract class BlendableAction extends Action { |
||||
|
||||
protected BlendableAction collectTransformDelegate; |
||||
private float transitionWeight = 1.0f; |
||||
private double transitionLength = 0.4f; |
||||
private TransitionTween transition = new TransitionTween(transitionLength); |
||||
|
||||
public BlendableAction(Tween... tweens) { |
||||
super(tweens); |
||||
} |
||||
|
||||
|
||||
public void setCollectTransformDelegate(BlendableAction delegate) { |
||||
this.collectTransformDelegate = delegate; |
||||
} |
||||
|
||||
@Override |
||||
public boolean interpolate(double t) { |
||||
// Sanity check the inputs
|
||||
if (t < 0) { |
||||
return true; |
||||
} |
||||
|
||||
if (collectTransformDelegate == null) { |
||||
if (transition.getLength() > getLength()) { |
||||
transition.setLength(getLength()); |
||||
} |
||||
transition.interpolate(t); |
||||
} else { |
||||
transitionWeight = 1f; |
||||
} |
||||
|
||||
if (weight == 0) { |
||||
//weight is 0 let's not interpolate
|
||||
return t < getLength(); |
||||
} |
||||
|
||||
doInterpolate(t); |
||||
|
||||
return t < getLength(); |
||||
} |
||||
|
||||
protected abstract void doInterpolate(double t); |
||||
|
||||
public abstract Collection<HasLocalTransform> getTargets(); |
||||
|
||||
public abstract void collectTransform(HasLocalTransform target, Transform t, float weight, BlendableAction source); |
||||
|
||||
public double getTransitionLength() { |
||||
return transitionLength; |
||||
} |
||||
|
||||
public void setTransitionLength(double transitionLength) { |
||||
this.transitionLength = transitionLength; |
||||
} |
||||
|
||||
protected float getTransitionWeight() { |
||||
return transitionWeight; |
||||
} |
||||
|
||||
private class TransitionTween extends AbstractTween { |
||||
|
||||
|
||||
public TransitionTween(double length) { |
||||
super(length); |
||||
} |
||||
|
||||
@Override |
||||
protected void doInterpolate(double t) { |
||||
transitionWeight = (float) t; |
||||
} |
||||
} |
||||
|
||||
} |
@ -0,0 +1,64 @@ |
||||
package com.jme3.anim.tween.action; |
||||
|
||||
import com.jme3.anim.AnimClip; |
||||
import com.jme3.anim.TransformTrack; |
||||
import com.jme3.anim.tween.AbstractTween; |
||||
import com.jme3.anim.util.HasLocalTransform; |
||||
import com.jme3.math.Transform; |
||||
|
||||
import java.util.ArrayList; |
||||
import java.util.Collection; |
||||
import java.util.List; |
||||
|
||||
public class ClipAction extends BlendableAction { |
||||
|
||||
private AnimClip clip; |
||||
private Transform transform = new Transform(); |
||||
|
||||
public ClipAction(AnimClip clip) { |
||||
this.clip = clip; |
||||
length = clip.getLength(); |
||||
} |
||||
|
||||
@Override |
||||
public void doInterpolate(double t) { |
||||
TransformTrack[] tracks = clip.getTracks(); |
||||
for (TransformTrack track : tracks) { |
||||
HasLocalTransform target = track.getTarget(); |
||||
transform.set(target.getLocalTransform()); |
||||
track.getTransformAtTime(t, transform); |
||||
|
||||
if (collectTransformDelegate != null) { |
||||
collectTransformDelegate.collectTransform(target, transform, weight, this); |
||||
} else { |
||||
this.collectTransform(target, transform, getTransitionWeight(), this); |
||||
} |
||||
} |
||||
} |
||||
|
||||
public void reset() { |
||||
|
||||
} |
||||
|
||||
@Override |
||||
public Collection<HasLocalTransform> getTargets() { |
||||
List<HasLocalTransform> targets = new ArrayList<>(clip.getTracks().length); |
||||
for (TransformTrack track : clip.getTracks()) { |
||||
targets.add(track.getTarget()); |
||||
} |
||||
return targets; |
||||
} |
||||
|
||||
@Override |
||||
public void collectTransform(HasLocalTransform target, Transform t, float weight, BlendableAction source) { |
||||
if (weight == 1f) { |
||||
target.setLocalTransform(t); |
||||
} else { |
||||
Transform tr = target.getLocalTransform(); |
||||
tr.interpolateTransforms(tr, t, weight); |
||||
target.setLocalTransform(tr); |
||||
} |
||||
} |
||||
|
||||
|
||||
} |
@ -1,75 +0,0 @@ |
||||
package com.jme3.anim.tween.action; |
||||
|
||||
import com.jme3.anim.tween.AbstractTween; |
||||
import com.jme3.anim.tween.Tween; |
||||
|
||||
public class SequenceAction extends Action { |
||||
|
||||
private int currentIndex = 0; |
||||
private double accumTime; |
||||
private double transitionTime = 0; |
||||
private float mainWeight = 1.0f; |
||||
private double transitionLength = 0.4f; |
||||
private TransitionTween transition = new TransitionTween(transitionLength); |
||||
|
||||
|
||||
public SequenceAction(Tween... tweens) { |
||||
super(tweens); |
||||
for (Tween tween : tweens) { |
||||
length += tween.getLength(); |
||||
} |
||||
} |
||||
|
||||
@Override |
||||
public float getWeightForTween(Tween tween) { |
||||
return weight * mainWeight; |
||||
} |
||||
|
||||
@Override |
||||
public boolean doInterpolate(double t) { |
||||
Tween currentTween = tweens[currentIndex]; |
||||
if (transition.getLength() > currentTween.getLength()) { |
||||
transition.setLength(currentTween.getLength()); |
||||
} |
||||
|
||||
transition.interpolate(t - transitionTime); |
||||
|
||||
boolean running = currentTween.interpolate(t - accumTime); |
||||
if (!running) { |
||||
accumTime += currentTween.getLength(); |
||||
currentIndex++; |
||||
transitionTime = accumTime; |
||||
transition.setLength(transitionLength); |
||||
} |
||||
|
||||
if (t >= length) { |
||||
reset(); |
||||
return false; |
||||
} |
||||
return true; |
||||
} |
||||
|
||||
public void reset() { |
||||
currentIndex = 0; |
||||
accumTime = 0; |
||||
transitionTime = 0; |
||||
mainWeight = 1; |
||||
} |
||||
|
||||
public void setTransitionLength(double transitionLength) { |
||||
this.transitionLength = transitionLength; |
||||
} |
||||
|
||||
private class TransitionTween extends AbstractTween { |
||||
|
||||
|
||||
public TransitionTween(double length) { |
||||
super(length); |
||||
} |
||||
|
||||
@Override |
||||
protected void doInterpolate(double t) { |
||||
mainWeight = (float) t; |
||||
} |
||||
} |
||||
} |
Loading…
Reference in new issue