Skip to content

Commit

Permalink
Create AnimLayers in the SceneComposer and play animations
Browse files Browse the repository at this point in the history
  • Loading branch information
neph1 committed Aug 22, 2024
1 parent 828da64 commit 1ab296f
Show file tree
Hide file tree
Showing 10 changed files with 303 additions and 88 deletions.
36 changes: 12 additions & 24 deletions jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/JmeControl.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2016 jMonkeyEngine
* Copyright (c) 2009-2024jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -37,7 +37,6 @@
import com.jme3.scene.control.AbstractControl;
import com.jme3.scene.control.Control;
import java.io.IOException;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import javax.swing.Action;
import org.openide.actions.DeleteAction;
Expand Down Expand Up @@ -97,17 +96,12 @@ public void destroy() throws IOException {
final Spatial spat = getParentNode().getLookup().lookup(Spatial.class);
try {
fireSave(true);
SceneApplication.getApplication().enqueue(new Callable<Void>() {

public Void call() throws Exception {
spat.removeControl(control);
return null;
}
SceneApplication.getApplication().enqueue(() -> {
spat.removeControl(control);
return null;
}).get();
((AbstractSceneExplorerNode) getParentNode()).refresh(true);
} catch (InterruptedException ex) {
Exceptions.printStackTrace(ex);
} catch (ExecutionException ex) {
} catch (InterruptedException | ExecutionException ex) {
Exceptions.printStackTrace(ex);
}
}
Expand All @@ -116,9 +110,8 @@ public Void call() throws Exception {
@Override
public void fireSave(boolean modified) {
super.fireSave(true);
Node parent = getParentNode();
if (parent instanceof AbstractSceneExplorerNode) {
AbstractSceneExplorerNode par=(AbstractSceneExplorerNode)parent;
final Node parent = getParentNode();
if (parent instanceof AbstractSceneExplorerNode par) {
par.fireSave(modified);
}
}
Expand All @@ -128,23 +121,18 @@ public void fireSave(boolean modified) {
* This only works for extended AbstractControls!!
* Also see: {@link #isEnabled() }
* @param enabled Whether the Control should be enabled or disabled
* @return If we had success (false when an Exception occured or no {@link Control} assigned or not of type {@link AbstractControl} )
* @return If we had success (false when an Exception occurred or no {@link Control} assigned or not of type {@link AbstractControl} )
*/
public boolean setEnabled(final boolean enabled) {
if (!isEnableable())
return false;
try {
SceneApplication.getApplication().enqueue(new Callable<Void>() {
public Void call() throws Exception {
((AbstractControl)control).setEnabled(enabled);
return null;
}
SceneApplication.getApplication().enqueue(() -> {
((AbstractControl)control).setEnabled(enabled);
return null;
}).get();

} catch (InterruptedException ex) {
Exceptions.printStackTrace(ex);
return false;
} catch (ExecutionException ex) {
} catch (InterruptedException | ExecutionException ex) {
Exceptions.printStackTrace(ex);
return false;
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2020 jMonkeyEngine
* Copyright (c) 2009-2024 jMonkeyEngine
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
Expand Down Expand Up @@ -43,6 +43,8 @@
import java.awt.event.ActionListener;
import java.beans.PropertyChangeEvent;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutionException;
import javax.swing.Action;
import javax.swing.SwingUtilities;
Expand All @@ -58,7 +60,7 @@

/**
* Visual representation of the AnimClip Class in the Scene Explorer
* @author MeFisto94
* @author MeFisto94, neph1
*/
@org.openide.util.lookup.ServiceProvider(service = SceneExplorerNode.class)
@SuppressWarnings({"unchecked", "rawtypes"})
Expand All @@ -67,7 +69,6 @@ public class JmeAnimClip extends AbstractSceneExplorerNode {
private AnimClip animClip;
private Image icon;
private JmeAnimComposer jmeControl;
private boolean playing = false;

public JmeAnimClip() {
}
Expand Down Expand Up @@ -103,7 +104,7 @@ public Image getOpenedIcon(int type) {
}

public void toggleIcon(boolean enabled) {
if (!playing) {
if (!enabled) {
icon = IconList.animation.getImage();
} else {
icon = IconList.animationPlay.getImage();
Expand All @@ -113,13 +114,12 @@ public void toggleIcon(boolean enabled) {

@Override
public Action getPreferredAction() {
return Actions.alwaysEnabled(new PlayAction(), "Play", "", false);
return Actions.alwaysEnabled(new PlayAction(AnimComposer.DEFAULT_LAYER), "Play", "", false);
}

private void play() {
playing = !playing;
toggleIcon(playing);
jmeControl.setAnimClip(this);
private void play(String layer) {
toggleIcon(true);
jmeControl.setAnimClip(layer, this);
}

@Override
Expand All @@ -142,13 +142,25 @@ public void setChanged() {

@Override
public Action[] getActions(boolean context) {
return new Action[]{Actions.alwaysEnabled(new PlayAction(), playing ? "Stop" : "Play", "", false),
SystemAction.get(RenameAction.class),
SystemAction.get(DeleteAction.class),
//Actions.alwaysEnabled(new EffectTrackWizardAction(jmeControl.getLookup().lookup(AnimComposer.class).getSpatial(), this), "Add Effect Track", "", false),
//Actions.alwaysEnabled(new AudioTrackWizardAction(jmeControl.getLookup().lookup(AnimComposer.class).getSpatial(), this), "Add Audio Track", "", false),
// @TODO: not working yet, Actions.alwaysEnabled(new ExtractAnimationAction(), "Extract sub-animation", "", true)
};
final AnimComposer control = jmeControl.getLookup().lookup(AnimComposer.class);
if(control == null) {
return new Action[]{
Actions.alwaysEnabled(new PlayAction(AnimComposer.DEFAULT_LAYER), jmeControl.getPlaying(AnimComposer.DEFAULT_LAYER) == this ? "Stop" : "Play", "", false),
SystemAction.get(RenameAction.class),
SystemAction.get(DeleteAction.class),
};
}
final String[] layers = control.getLayerNames().stream().toArray(String[] ::new);

List<Action> playActions = new ArrayList<>();

for(String layer: layers) {
playActions.add(Actions.alwaysEnabled(new PlayAction(layer), jmeControl.getPlaying(layer) == this ? "Stop " + layer : "Play " + layer, "", false));
}
playActions.add(SystemAction.get(RenameAction.class));
playActions.add(SystemAction.get(DeleteAction.class));
final Action[] actions = new Action[playActions.size()];
return playActions.toArray(actions);
}

@Override
Expand All @@ -157,19 +169,19 @@ public boolean canDestroy() {
}

public void stop() {
playing = false;
toggleIcon(playing);
toggleIcon(false);
}

@Override
public void destroy() throws IOException {
super.destroy();
final AnimComposer control = jmeControl.getLookup().lookup(AnimComposer.class);
if (playing) {

if (jmeControl.getPlaying(AnimComposer.DEFAULT_LAYER) == this) {
control.removeCurrentAction(AnimComposer.DEFAULT_LAYER);
jmeControl.setAnimClip(null);

jmeControl.setAnimClip(AnimComposer.DEFAULT_LAYER, null);
}

lookupContents.remove(JmeAnimClip.this.animClip);
lookupContents.remove(this);
SceneApplication.getApplication().enqueue( () -> {
Expand Down Expand Up @@ -202,6 +214,13 @@ public Node[] createNodes(Object key, DataObject key2, boolean cookie) {
}

class PlayAction implements ActionListener {

private final String layer;

public PlayAction(String layer) {
this.layer = layer;
}

@Override
public void actionPerformed(ActionEvent e) {
final AnimComposer control = jmeControl.getLookup().lookup(AnimComposer.class);
Expand All @@ -211,14 +230,14 @@ public void actionPerformed(ActionEvent e) {

try {
SceneApplication.getApplication().enqueue(() -> {
if (playing) { // Stop Playing
control.removeCurrentAction(AnimComposer.DEFAULT_LAYER);
jmeControl.setAnimClip(null);
if (jmeControl.getPlaying(layer) == JmeAnimClip.this) { // Stop Playing
control.removeCurrentAction(layer);
jmeControl.setAnimClip(layer, null);
return null;
} else {
control.setCurrentAction(animClip.getName());
control.setCurrentAction(animClip.getName(), layer);
java.awt.EventQueue.invokeLater(() -> {
play();
play(layer);
});
return null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,12 @@
import com.jme3.gde.core.sceneexplorer.nodes.actions.ControlsPopup;
import com.jme3.gde.core.sceneexplorer.nodes.actions.animation.AnimClipProperty;
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import javax.swing.AbstractAction;
import javax.swing.Action;
import org.openide.actions.DeleteAction;
import org.openide.loaders.DataObject;
Expand All @@ -56,13 +61,13 @@
@SuppressWarnings({"unchecked", "rawtypes"})
public class JmeAnimComposer extends JmeControl {
private AnimComposer animComposer;
private JmeAnimClip playingAnimation = null;
private Map<String, JmeAnimClip> playingAnimation = new HashMap<>();
private static Image smallImage = IconList.animControl.getImage();

public JmeAnimComposer() {
}

public JmeAnimComposer(AnimComposer animComposer, JmeAnimClipChildren children, DataObject obj) {
public JmeAnimComposer(AnimComposer animComposer, JmeAnimComposerChildren children, DataObject obj) {
super(children);
dataObject = obj;
children.setDataObject(dataObject);
Expand Down Expand Up @@ -100,15 +105,15 @@ protected Sheet createSheet() {
return sheet;
}

public boolean isPlaying() {
return playingAnimation != null;
public JmeAnimClip getPlaying(String layer) {
return playingAnimation.get(layer);
}

public void setAnimClip(JmeAnimClip anim) {
if (playingAnimation != null) {
playingAnimation.stop();
public void setAnimClip(String layer, JmeAnimClip anim) {
if (playingAnimation.get(layer) != null) {
playingAnimation.get(layer).stop();
}
playingAnimation = anim;
playingAnimation.put(layer, anim);
}

public float getGlobalSpeed() {
Expand All @@ -130,7 +135,8 @@ public void setGlobalSpeed(final float speed) {
public Action[] getActions(boolean context) {
return new Action[]{
new ControlsPopup(this),
SystemAction.get(DeleteAction.class)
new StopAllAction(),
SystemAction.get(DeleteAction.class),
};
}

Expand All @@ -146,13 +152,24 @@ public Class getExplorerNodeClass() {

@Override
public Node[] createNodes(Object key, DataObject key2, boolean cookie) {
JmeAnimClipChildren children = new JmeAnimClipChildren(this);
JmeAnimComposerChildren children = new JmeAnimComposerChildren(this);
return new Node[]{ new JmeAnimComposer((AnimComposer)key, children, key2)};
}

@Override
public void refresh(boolean immediate) {
((JmeAnimClipChildren) jmeChildren).refreshChildren(immediate);
((JmeAnimComposerChildren) jmeChildren).refreshChildren(immediate);
super.refresh(immediate);
}

private class StopAllAction extends AbstractAction {

@Override
public void actionPerformed(ActionEvent e) {
for(JmeAnimClip layer: JmeAnimComposer.this.playingAnimation.values()) {
layer.stop();
}
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -33,30 +33,34 @@

import com.jme3.anim.AnimClip;
import com.jme3.anim.AnimComposer;
import com.jme3.anim.AnimLayer;
import com.jme3.gde.core.scene.SceneApplication;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.ExecutionException;
import org.openide.loaders.DataObject;
import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.util.Exceptions;

/**
* Representation of multiple Animations in the Scene Explorer
* @author MeFisto94
* Representation of an AnimComposers AnimClips and AnimLayers in the Scene Explorer
* @author MeFisto94, neph1
*/
public class JmeAnimClipChildren extends Children.Keys<Object> {
public class JmeAnimComposerChildren extends Children.Keys<Object> {
protected JmeAnimComposer jmeAnimComposer;
protected boolean readOnly = true;
protected HashMap<Object, Node> map = new HashMap<>();
private DataObject dataObject;

public JmeAnimClipChildren() {
public JmeAnimComposerChildren() {
}

public JmeAnimClipChildren(JmeAnimComposer jmeAnimComposer) {
public JmeAnimComposerChildren(JmeAnimComposer jmeAnimComposer) {
this.jmeAnimComposer = jmeAnimComposer;
}

Expand All @@ -82,6 +86,12 @@ protected List<Object> createKeys() {
AnimComposer composer = jmeAnimComposer.getLookup().lookup(AnimComposer.class);
if (composer != null) {
keys.addAll(composer.getAnimClips());
final Set<String> layerNames = composer.getLayerNames();
final List<AnimLayer> layers = new ArrayList<>();
for(String s: layerNames) {
layers.add(composer.getLayer(s));
}
keys.addAll(layers);
}

return keys;
Expand All @@ -96,7 +106,10 @@ protected List<Object> createKeys() {
protected Node[] createNodes(Object key) {
if (key instanceof AnimClip animClip) {
return new Node[]{ new JmeAnimClip(jmeAnimComposer, animClip, dataObject).setReadOnly(readOnly)};
} else {
} else if (key instanceof AnimLayer animLayer) {
return new Node[]{ new JmeAnimLayer(jmeAnimComposer, animLayer, dataObject).setReadOnly(readOnly)};
}
else {
return new Node[]{ Node.EMPTY };
}
}
Expand Down
Loading

0 comments on commit 1ab296f

Please sign in to comment.