Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Refactor SingleLayerInfluenceMask to support import and export #2376

Closed
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
145 changes: 67 additions & 78 deletions jme3-core/src/main/java/com/jme3/anim/SingleLayerInfluenceMask.java
Original file line number Diff line number Diff line change
Expand Up @@ -31,8 +31,14 @@
*/
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.scene.Spatial;

import java.io.IOException;

/**
* Mask that excludes joints from participating in the layer
* if a higher layer is using those joints in an animation.
Expand All @@ -41,88 +47,83 @@
*/
public class SingleLayerInfluenceMask extends ArmatureMask {

private final String layer;
private final AnimComposer anim;
private final SkinningControl skin;
private boolean checkUpperLayers = true;

private String layer;
private AnimComposer anim;

/**
* @param layer The layer this mask is targeted for. It is important
* that this match the name of the layer this mask is (or will be) part of. You
* can use {@link makeLayer} to ensure this.
* @param spatial Spatial containing necessary controls ({@link AnimComposer} and {@link SkinningControl})
* Serialization only.
*/
public SingleLayerInfluenceMask(String layer, Spatial spatial) {
super();
this.layer = layer;
anim = spatial.getControl(AnimComposer.class);
skin = spatial.getControl(SkinningControl.class);
}
public SingleLayerInfluenceMask() {}

/**
* @param layer The layer this mask is targeted for. It is important
* that this match the name of the layer this mask is (or will be) part of. You
* can use {@link makeLayer} to ensure this.
* @param anim anim composer this mask is assigned to
* @param skin skinning control complimenting the anim composer.
* can use {@link #makeLayer(AnimComposer)} to ensure this.
*/
public SingleLayerInfluenceMask(String layer, AnimComposer anim, SkinningControl skin) {
public SingleLayerInfluenceMask(String layer) {
super();
this.layer = layer;
this.anim = anim;
this.skin = skin;
}

/**
* Makes a layer from this mask.
*
* @param anim AnimComposer to use
* @return this instance
*/
public void makeLayer() {
anim.makeLayer(layer, this);
public SingleLayerInfluenceMask makeLayer(AnimComposer anim) {
this.anim = anim;
if (this.anim != null) {
anim.makeLayer(layer, this);
}
return this;
}

/**
* Adds all joints to this mask.
* @return this.instance
* Makes a layer from this mask.
*
* @return this instance
*/
public SingleLayerInfluenceMask addAll() {
for (Joint j : skin.getArmature().getJointList()) {
super.addBones(skin.getArmature(), j.getName());
}
public SingleLayerInfluenceMask makeLayer() {
anim.makeLayer(layer, this);
return this;
}

/**
* Adds the given joint and all its children to this mask.
* @param joint
* Adds all joints to this mask.
*
* @param armature
* @return this instance
*/
public SingleLayerInfluenceMask addFromJoint(String joint) {
super.addFromJoint(skin.getArmature(), joint);
public SingleLayerInfluenceMask addAll(Armature armature) {
for (Joint j : armature.getJointList()) {
super.addBones(armature, j.getName());
}
return this;
}

/**
* Adds the given joints to this mask.
*
* @param joints
* @return this instance
*/
public SingleLayerInfluenceMask addJoints(String... joints) {
super.addBones(skin.getArmature(), joints);
public SingleLayerInfluenceMask addJoints(Armature armature, String... joints) {
super.addBones(armature, joints);
return this;
}

/**
* Makes this mask check if each joint is being used by a higher layer
* before it uses them.
* <p>Not checking is more efficient, but checking can avoid some
* interpolation issues between layers. Default=true
* @param check
* @return this instance
* Sets the AnimComposer used by this mask to determine joint use.
* <p>If null, joint use check will be skipped and any higher that may
* have been using the joint may be overriden.</p>
*
* @param anim
*/
public SingleLayerInfluenceMask setCheckUpperLayers(boolean check) {
checkUpperLayers = check;
return this;
public void setAnimComposer(AnimComposer anim) {
this.anim = anim;
}

/**
* Get the layer this mask is targeted for.
* <p>It is extremely important that this value match the actual layer
Expand All @@ -133,7 +134,7 @@ public SingleLayerInfluenceMask setCheckUpperLayers(boolean check) {
public String getTargetLayer() {
return layer;
}

/**
* Get the {@link AnimComposer} this mask is for.
* @return anim composer
Expand All @@ -142,27 +143,11 @@ public AnimComposer getAnimComposer() {
return anim;
}

/**
* Get the {@link SkinningControl} this mask is for.
* @return skinning control
*/
public SkinningControl getSkinningControl() {
return skin;
}

/**
* Returns true if this mask is checking upper layers for joint use.
* @return
*/
public boolean isCheckUpperLayers() {
return checkUpperLayers;
}

@Override
public boolean contains(Object target) {
return simpleContains(target) && (!checkUpperLayers || !isAffectedByUpperLayers(target));
return simpleContains(target) && (anim == null || !isAffectedByUpperLayers(target));
}

private boolean simpleContains(Object target) {
return super.contains(target);
}
Expand Down Expand Up @@ -192,26 +177,30 @@ else if (lyr.getMask().contains(target)) {
}
return false;
}

/**
* Creates an {@code SingleLayerInfluenceMask} for all joints.
* @param layer layer the returned mask is, or will be, be assigned to
* @param spatial spatial containing anim composer and skinning control
* @return new mask
*/
public static SingleLayerInfluenceMask all(String layer, Spatial spatial) {
return new SingleLayerInfluenceMask(layer, spatial).addAll();

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

@Override
public void read(JmeImporter im) throws IOException {
super.read(im);
InputCapsule in = im.getCapsule(this);
layer = in.readString("layer", null);
}

/**
* Creates an {@code SingleLayerInfluenceMask} for all joints.
* @param layer layer the returned mask is, or will be, assigned to
* @param anim anim composer
* @param skin skinning control
* @param armature armature
* @return new mask
*/
public static SingleLayerInfluenceMask all(String layer, AnimComposer anim, SkinningControl skin) {
return new SingleLayerInfluenceMask(layer, anim, skin).addAll();
public static SingleLayerInfluenceMask all(String layer, AnimComposer anim, Armature armature) {
return new SingleLayerInfluenceMask(layer).makeLayer(anim).addAll(armature);
}

}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -118,11 +118,9 @@ private void setupModel() {
skin = model.getControl(SkinningControl.class);

if (useSLIMask) {
SingleLayerInfluenceMask walkLayer = new SingleLayerInfluenceMask("idleLayer", anim, skin);
walkLayer.addAll();
SingleLayerInfluenceMask walkLayer = SingleLayerInfluenceMask.all("idleLayer", anim, skin.getArmature());
walkLayer.makeLayer();
SingleLayerInfluenceMask danceLayer = new SingleLayerInfluenceMask("danceLayer", anim, skin);
danceLayer.addAll();
SingleLayerInfluenceMask danceLayer = SingleLayerInfluenceMask.all("danceLayer", anim, skin.getArmature());
danceLayer.makeLayer();
} else {
anim.makeLayer("idleLayer", ArmatureMask.createMask(skin.getArmature(), "Root"));
Expand Down