Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions jme3-core/src/main/java/com/jme3/anim/AnimComposer.java
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public class AnimComposer extends AbstractControl {
* Instantiate a composer with a single layer, no actions, and no clips.
*/
public AnimComposer() {
layers.put(DEFAULT_LAYER, new AnimLayer(this, DEFAULT_LAYER, null));
layers.put(DEFAULT_LAYER, new AnimLayer(DEFAULT_LAYER, null));
}

/**
Expand Down Expand Up @@ -314,7 +314,7 @@ public Action removeAction(String name) {
* @param mask the desired mask for the new layer (alias created)
*/
public void makeLayer(String name, AnimationMask mask) {
AnimLayer l = new AnimLayer(this, name, mask);
AnimLayer l = new AnimLayer(name, mask);
layers.put(name, l);
}

Expand Down Expand Up @@ -399,7 +399,7 @@ public Set<String> getAnimClipsNames() {
@Override
protected void controlUpdate(float tpf) {
for (AnimLayer layer : layers.values()) {
layer.update(tpf);
layer.update(tpf, globalSpeed);
}
}

Expand Down Expand Up @@ -542,6 +542,7 @@ public void read(JmeImporter im) throws IOException {
InputCapsule ic = im.getCapsule(this);
animClipMap = (Map<String, AnimClip>) ic.readStringSavableMap("animClipMap", new HashMap<String, AnimClip>());
globalSpeed = ic.readFloat("globalSpeed", 1f);
layers = (Map<String, AnimLayer>) ic.readStringSavableMap("layers", new HashMap<String, AnimLayer>());
}

/**
Expand All @@ -557,5 +558,6 @@ public void write(JmeExporter ex) throws IOException {
OutputCapsule oc = ex.getCapsule(this);
oc.writeStringSavableMap(animClipMap, "animClipMap", new HashMap<String, AnimClip>());
oc.write(globalSpeed, "globalSpeed", 1f);
oc.writeStringSavableMap(layers, "layers", new HashMap<String, AnimLayer>());
}
}
53 changes: 37 additions & 16 deletions jme3-core/src/main/java/com/jme3/anim/AnimLayer.java
Copy link
Contributor Author

@neph1 neph1 Aug 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I decided to only save name and mask. The other fields felt like they're only interesting for runtime.

Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,14 @@
package com.jme3.anim;

import com.jme3.anim.tween.action.Action;
import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.export.Savable;
import com.jme3.util.clone.Cloner;
import com.jme3.util.clone.JmeCloneable;
import java.io.IOException;

/**
* A named portion of an AnimComposer that can run (at most) one Action at a
Expand All @@ -48,7 +54,7 @@
* <p>Animation time may advance at a different rate from application time,
* based on speedup factors in the composer and the current Action.
*/
public class AnimLayer implements JmeCloneable {
public class AnimLayer implements JmeCloneable, Savable {
/**
* The Action currently running on this layer, or null if none.
*/
Expand All @@ -57,16 +63,12 @@ public class AnimLayer implements JmeCloneable {
* The name of Action currently running on this layer, or null if none.
*/
private String currentActionName;
/**
* The composer that owns this layer. Were it not for cloning, this field
* would be final.
*/
private AnimComposer composer;
Copy link
Contributor Author

@neph1 neph1 Aug 22, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redundant field


/**
* Limits the portion of the model animated by this layer. If null, this
* layer can animate the entire model.
*/
private final AnimationMask mask;
private AnimationMask mask;
/**
* The current animation time, in scaled seconds. Always non-negative.
*/
Expand All @@ -79,23 +81,26 @@ public class AnimLayer implements JmeCloneable {
/**
* The name of this layer.
*/
final private String name;
private String name;

private boolean loop = true;

/**
* For serialization only. Do not use.
*/
protected AnimLayer() {

}

/**
* Instantiates a layer without a manager or a current Action, owned by the
* specified composer.
*
* @param composer the owner (not null, alias created)
* @param name the layer name (not null)
* @param mask the AnimationMask (alias created) or null to allow this layer
* to animate the entire model
*/
AnimLayer(AnimComposer composer, String name, AnimationMask mask) {
assert composer != null;
this.composer = composer;

AnimLayer(String name, AnimationMask mask) {
assert name != null;
this.name = name;

Expand Down Expand Up @@ -248,14 +253,15 @@ public void setLooping(boolean loop) {
*
* @param appDeltaTimeInSeconds the amount application time to advance the
* current Action, in seconds
* @param globalSpeed the global speed applied to all layers.
*/
void update(float appDeltaTimeInSeconds) {
void update(float appDeltaTimeInSeconds, float globalSpeed) {
Action action = currentAction;
if (action == null) {
return;
}

double speedup = action.getSpeed() * composer.getGlobalSpeed();
double speedup = action.getSpeed() * globalSpeed;
double scaledDeltaTime = speedup * appDeltaTimeInSeconds;
time += scaledDeltaTime;

Expand Down Expand Up @@ -292,7 +298,6 @@ void update(float appDeltaTimeInSeconds) {
*/
@Override
public void cloneFields(Cloner cloner, Object original) {
composer = cloner.clone(composer);
currentAction = null;
currentActionName = null;
}
Expand All @@ -306,4 +311,20 @@ public Object jmeClone() {
throw new AssertionError();
}
}

@Override
public void write(JmeExporter ex) throws IOException {
OutputCapsule oc = ex.getCapsule(this);
oc.write(name, "name", null);
if (mask instanceof Savable) {
oc.write((Savable) mask, "mask", null);
}
}

@Override
public void read(JmeImporter im) throws IOException {
InputCapsule ic = im.getCapsule(this);
name = ic.readString("name", null);
mask = (AnimationMask) ic.readSavable("mask", null);
}
}
22 changes: 20 additions & 2 deletions jme3-core/src/main/java/com/jme3/anim/ArmatureMask.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,14 +31,20 @@
*/
package com.jme3.anim;

import com.jme3.export.InputCapsule;
import com.jme3.export.JmeExporter;
import com.jme3.export.JmeImporter;
import com.jme3.export.OutputCapsule;
import com.jme3.export.Savable;
import java.io.IOException;
import java.util.BitSet;

/**
* An AnimationMask to select joints from a single Armature.
*/
public class ArmatureMask implements AnimationMask {
public class ArmatureMask implements AnimationMask, Savable {

final private BitSet affectedJoints = new BitSet();
private BitSet affectedJoints = new BitSet();

/**
* Instantiate a mask that affects no joints.
Expand Down Expand Up @@ -206,4 +212,16 @@ public ArmatureMask removeAncestors(Joint start) {

return this;
}

@Override
public void write(JmeExporter ex) throws IOException {
OutputCapsule oc = ex.getCapsule(this);
oc.write(affectedJoints, "affectedJoints", null);
}

@Override
public void read(JmeImporter im) throws IOException {
InputCapsule ic = im.getCapsule(this);
affectedJoints = ic.readBitSet("affectedJoints", null);
}
}
33 changes: 33 additions & 0 deletions jme3-core/src/test/java/com/jme3/anim/AnimComposerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,9 @@
*/
package com.jme3.anim;

import com.jme3.anim.tween.action.Action;
import java.util.Set;
import java.util.TreeSet;
import org.junit.Assert;
import org.junit.Test;

Expand All @@ -54,6 +57,36 @@ public void testGetAnimClipsNames() {
Assert.assertNotNull(composer.getAnimClipsNames());
Assert.assertEquals(0, composer.getAnimClipsNames().size());
}

@Test
public void testMakeLayer() {
AnimComposer composer = new AnimComposer();

final String layerName = "TestLayer";

composer.makeLayer(layerName, null);

final Set<String> layers = new TreeSet<>();
layers.add("Default");
layers.add(layerName);

Assert.assertNotNull(composer.getLayer(layerName));
Assert.assertEquals(layers, composer.getLayerNames());
}

@Test
public void testMakeAction() {
AnimComposer composer = new AnimComposer();

final String animName = "TestClip";

final AnimClip anim = new AnimClip(animName);
composer.addAnimClip(anim);

final Action action = composer.makeAction(animName);

Assert.assertNotNull(action);
}

@Test(expected = UnsupportedOperationException.class)
public void testGetAnimClipsIsNotModifiable() {
Expand Down