Skip to content

Commit e5b33e8

Browse files
authored
Merge pull request #612 from neph1/AnimLayers
Create AnimLayers in the SceneComposer and play animations
2 parents 77a8ae1 + 7b2bebb commit e5b33e8

File tree

10 files changed

+307
-88
lines changed

10 files changed

+307
-88
lines changed

jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/JmeControl.java

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2009-2016 jMonkeyEngine
2+
* Copyright (c) 2009-2024jMonkeyEngine
33
* All rights reserved.
44
*
55
* Redistribution and use in source and binary forms, with or without
@@ -37,7 +37,6 @@
3737
import com.jme3.scene.control.AbstractControl;
3838
import com.jme3.scene.control.Control;
3939
import java.io.IOException;
40-
import java.util.concurrent.Callable;
4140
import java.util.concurrent.ExecutionException;
4241
import javax.swing.Action;
4342
import org.openide.actions.DeleteAction;
@@ -97,17 +96,12 @@ public void destroy() throws IOException {
9796
final Spatial spat = getParentNode().getLookup().lookup(Spatial.class);
9897
try {
9998
fireSave(true);
100-
SceneApplication.getApplication().enqueue(new Callable<Void>() {
101-
102-
public Void call() throws Exception {
103-
spat.removeControl(control);
104-
return null;
105-
}
99+
SceneApplication.getApplication().enqueue(() -> {
100+
spat.removeControl(control);
101+
return null;
106102
}).get();
107103
((AbstractSceneExplorerNode) getParentNode()).refresh(true);
108-
} catch (InterruptedException ex) {
109-
Exceptions.printStackTrace(ex);
110-
} catch (ExecutionException ex) {
104+
} catch (InterruptedException | ExecutionException ex) {
111105
Exceptions.printStackTrace(ex);
112106
}
113107
}
@@ -116,9 +110,8 @@ public Void call() throws Exception {
116110
@Override
117111
public void fireSave(boolean modified) {
118112
super.fireSave(true);
119-
Node parent = getParentNode();
120-
if (parent instanceof AbstractSceneExplorerNode) {
121-
AbstractSceneExplorerNode par=(AbstractSceneExplorerNode)parent;
113+
final Node parent = getParentNode();
114+
if (parent instanceof AbstractSceneExplorerNode par) {
122115
par.fireSave(modified);
123116
}
124117
}
@@ -128,23 +121,18 @@ public void fireSave(boolean modified) {
128121
* This only works for extended AbstractControls!!
129122
* Also see: {@link #isEnabled() }
130123
* @param enabled Whether the Control should be enabled or disabled
131-
* @return If we had success (false when an Exception occured or no {@link Control} assigned or not of type {@link AbstractControl} )
124+
* @return If we had success (false when an Exception occurred or no {@link Control} assigned or not of type {@link AbstractControl} )
132125
*/
133126
public boolean setEnabled(final boolean enabled) {
134127
if (!isEnableable())
135128
return false;
136129
try {
137-
SceneApplication.getApplication().enqueue(new Callable<Void>() {
138-
public Void call() throws Exception {
139-
((AbstractControl)control).setEnabled(enabled);
140-
return null;
141-
}
130+
SceneApplication.getApplication().enqueue(() -> {
131+
((AbstractControl)control).setEnabled(enabled);
132+
return null;
142133
}).get();
143134

144-
} catch (InterruptedException ex) {
145-
Exceptions.printStackTrace(ex);
146-
return false;
147-
} catch (ExecutionException ex) {
135+
} catch (InterruptedException | ExecutionException ex) {
148136
Exceptions.printStackTrace(ex);
149137
return false;
150138
}

jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/animation/JmeAnimClip.java

Lines changed: 45 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2009-2020 jMonkeyEngine
2+
* Copyright (c) 2009-2024 jMonkeyEngine
33
* All rights reserved.
44
*
55
* Redistribution and use in source and binary forms, with or without
@@ -43,6 +43,8 @@
4343
import java.awt.event.ActionListener;
4444
import java.beans.PropertyChangeEvent;
4545
import java.io.IOException;
46+
import java.util.ArrayList;
47+
import java.util.List;
4648
import java.util.concurrent.ExecutionException;
4749
import javax.swing.Action;
4850
import javax.swing.SwingUtilities;
@@ -58,7 +60,7 @@
5860

5961
/**
6062
* Visual representation of the AnimClip Class in the Scene Explorer
61-
* @author MeFisto94
63+
* @author MeFisto94, neph1
6264
*/
6365
@org.openide.util.lookup.ServiceProvider(service = SceneExplorerNode.class)
6466
@SuppressWarnings({"unchecked", "rawtypes"})
@@ -67,7 +69,6 @@ public class JmeAnimClip extends AbstractSceneExplorerNode {
6769
private AnimClip animClip;
6870
private Image icon;
6971
private JmeAnimComposer jmeControl;
70-
private boolean playing = false;
7172

7273
public JmeAnimClip() {
7374
}
@@ -103,7 +104,7 @@ public Image getOpenedIcon(int type) {
103104
}
104105

105106
public void toggleIcon(boolean enabled) {
106-
if (!playing) {
107+
if (!enabled) {
107108
icon = IconList.animation.getImage();
108109
} else {
109110
icon = IconList.animationPlay.getImage();
@@ -113,13 +114,12 @@ public void toggleIcon(boolean enabled) {
113114

114115
@Override
115116
public Action getPreferredAction() {
116-
return Actions.alwaysEnabled(new PlayAction(), "Play", "", false);
117+
return Actions.alwaysEnabled(new PlayAction(AnimComposer.DEFAULT_LAYER), "Play", "", false);
117118
}
118119

119-
private void play() {
120-
playing = !playing;
121-
toggleIcon(playing);
122-
jmeControl.setAnimClip(this);
120+
private void play(String layer) {
121+
toggleIcon(true);
122+
jmeControl.setAnimClip(layer, this);
123123
}
124124

125125
@Override
@@ -142,13 +142,25 @@ public void setChanged() {
142142

143143
@Override
144144
public Action[] getActions(boolean context) {
145-
return new Action[]{Actions.alwaysEnabled(new PlayAction(), playing ? "Stop" : "Play", "", false),
146-
SystemAction.get(RenameAction.class),
147-
SystemAction.get(DeleteAction.class),
148-
//Actions.alwaysEnabled(new EffectTrackWizardAction(jmeControl.getLookup().lookup(AnimComposer.class).getSpatial(), this), "Add Effect Track", "", false),
149-
//Actions.alwaysEnabled(new AudioTrackWizardAction(jmeControl.getLookup().lookup(AnimComposer.class).getSpatial(), this), "Add Audio Track", "", false),
150-
// @TODO: not working yet, Actions.alwaysEnabled(new ExtractAnimationAction(), "Extract sub-animation", "", true)
151-
};
145+
final AnimComposer control = jmeControl.getLookup().lookup(AnimComposer.class);
146+
if(control == null) {
147+
return new Action[]{
148+
Actions.alwaysEnabled(new PlayAction(AnimComposer.DEFAULT_LAYER), jmeControl.getPlaying(AnimComposer.DEFAULT_LAYER) == this ? "Stop" : "Play", "", false),
149+
SystemAction.get(RenameAction.class),
150+
SystemAction.get(DeleteAction.class),
151+
};
152+
}
153+
final String[] layers = control.getLayerNames().stream().toArray(String[] ::new);
154+
155+
List<Action> playActions = new ArrayList<>();
156+
157+
for(String layer: layers) {
158+
playActions.add(Actions.alwaysEnabled(new PlayAction(layer), jmeControl.getPlaying(layer) == this ? "Stop " + layer : "Play " + layer, "", false));
159+
}
160+
playActions.add(SystemAction.get(RenameAction.class));
161+
playActions.add(SystemAction.get(DeleteAction.class));
162+
final Action[] actions = new Action[playActions.size()];
163+
return playActions.toArray(actions);
152164
}
153165

154166
@Override
@@ -157,19 +169,19 @@ public boolean canDestroy() {
157169
}
158170

159171
public void stop() {
160-
playing = false;
161-
toggleIcon(playing);
172+
toggleIcon(false);
162173
}
163174

164175
@Override
165176
public void destroy() throws IOException {
166177
super.destroy();
167178
final AnimComposer control = jmeControl.getLookup().lookup(AnimComposer.class);
168-
if (playing) {
179+
180+
if (jmeControl.getPlaying(AnimComposer.DEFAULT_LAYER) == this) {
169181
control.removeCurrentAction(AnimComposer.DEFAULT_LAYER);
170-
jmeControl.setAnimClip(null);
171-
182+
jmeControl.setAnimClip(AnimComposer.DEFAULT_LAYER, null);
172183
}
184+
173185
lookupContents.remove(JmeAnimClip.this.animClip);
174186
lookupContents.remove(this);
175187
SceneApplication.getApplication().enqueue( () -> {
@@ -202,6 +214,13 @@ public Node[] createNodes(Object key, DataObject key2, boolean cookie) {
202214
}
203215

204216
class PlayAction implements ActionListener {
217+
218+
private final String layer;
219+
220+
public PlayAction(String layer) {
221+
this.layer = layer;
222+
}
223+
205224
@Override
206225
public void actionPerformed(ActionEvent e) {
207226
final AnimComposer control = jmeControl.getLookup().lookup(AnimComposer.class);
@@ -211,14 +230,14 @@ public void actionPerformed(ActionEvent e) {
211230

212231
try {
213232
SceneApplication.getApplication().enqueue(() -> {
214-
if (playing) { // Stop Playing
215-
control.removeCurrentAction(AnimComposer.DEFAULT_LAYER);
216-
jmeControl.setAnimClip(null);
233+
if (jmeControl.getPlaying(layer) == JmeAnimClip.this) { // Stop Playing
234+
control.removeCurrentAction(layer);
235+
jmeControl.setAnimClip(layer, null);
217236
return null;
218237
} else {
219-
control.setCurrentAction(animClip.getName());
238+
control.setCurrentAction(animClip.getName(), layer);
220239
java.awt.EventQueue.invokeLater(() -> {
221-
play();
240+
play(layer);
222241
});
223242
return null;
224243
}

jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/animation/JmeAnimComposer.java

Lines changed: 38 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,19 +34,29 @@
3434
import com.jme3.anim.AnimComposer;
3535
import com.jme3.gde.core.icons.IconList;
3636
import com.jme3.gde.core.scene.SceneApplication;
37+
import com.jme3.gde.core.sceneexplorer.SceneExplorerTopComponent;
3738
import com.jme3.gde.core.sceneexplorer.nodes.JmeControl;
3839
import com.jme3.gde.core.sceneexplorer.nodes.SceneExplorerNode;
3940
import com.jme3.gde.core.sceneexplorer.nodes.actions.ControlsPopup;
4041
import com.jme3.gde.core.sceneexplorer.nodes.actions.animation.AnimClipProperty;
4142
import java.awt.Image;
43+
import java.awt.event.ActionEvent;
44+
import java.util.Collection;
45+
import java.util.HashMap;
46+
import java.util.List;
47+
import java.util.Map;
4248
import java.util.concurrent.ExecutionException;
49+
import javax.swing.AbstractAction;
4350
import javax.swing.Action;
4451
import org.openide.actions.DeleteAction;
52+
import org.openide.awt.Actions;
53+
import org.openide.explorer.ExplorerManager;
4554
import org.openide.loaders.DataObject;
4655
import org.openide.nodes.Node;
4756
import org.openide.nodes.Sheet;
4857
import org.openide.util.Exceptions;
4958
import org.openide.util.actions.SystemAction;
59+
import org.openide.windows.TopComponent;
5060

5161
/**
5262
* Visual representation of the AnimComposer Class in the Scene Explorer
@@ -56,13 +66,13 @@
5666
@SuppressWarnings({"unchecked", "rawtypes"})
5767
public class JmeAnimComposer extends JmeControl {
5868
private AnimComposer animComposer;
59-
private JmeAnimClip playingAnimation = null;
69+
private final Map<String, JmeAnimClip> playingAnimation = new HashMap<>();
6070
private static Image smallImage = IconList.animControl.getImage();
6171

6272
public JmeAnimComposer() {
6373
}
6474

65-
public JmeAnimComposer(AnimComposer animComposer, JmeAnimClipChildren children, DataObject obj) {
75+
public JmeAnimComposer(AnimComposer animComposer, JmeAnimComposerChildren children, DataObject obj) {
6676
super(children);
6777
dataObject = obj;
6878
children.setDataObject(dataObject);
@@ -100,15 +110,15 @@ protected Sheet createSheet() {
100110
return sheet;
101111
}
102112

103-
public boolean isPlaying() {
104-
return playingAnimation != null;
113+
public JmeAnimClip getPlaying(String layer) {
114+
return playingAnimation.get(layer);
105115
}
106-
107-
public void setAnimClip(JmeAnimClip anim) {
108-
if (playingAnimation != null) {
109-
playingAnimation.stop();
116+
117+
public void setAnimClip(String layer, JmeAnimClip anim) {
118+
if (playingAnimation.get(layer) != null) {
119+
playingAnimation.get(layer).stop();
110120
}
111-
playingAnimation = anim;
121+
playingAnimation.put(layer, anim);
112122
}
113123

114124
public float getGlobalSpeed() {
@@ -130,7 +140,8 @@ public void setGlobalSpeed(final float speed) {
130140
public Action[] getActions(boolean context) {
131141
return new Action[]{
132142
new ControlsPopup(this),
133-
SystemAction.get(DeleteAction.class)
143+
new StopAllAction(),
144+
SystemAction.get(DeleteAction.class),
134145
};
135146
}
136147

@@ -146,13 +157,28 @@ public Class getExplorerNodeClass() {
146157

147158
@Override
148159
public Node[] createNodes(Object key, DataObject key2, boolean cookie) {
149-
JmeAnimClipChildren children = new JmeAnimClipChildren(this);
160+
JmeAnimComposerChildren children = new JmeAnimComposerChildren(this);
150161
return new Node[]{ new JmeAnimComposer((AnimComposer)key, children, key2)};
151162
}
152163

153164
@Override
154165
public void refresh(boolean immediate) {
155-
((JmeAnimClipChildren) jmeChildren).refreshChildren(immediate);
166+
((JmeAnimComposerChildren) jmeChildren).refreshChildren(immediate);
156167
super.refresh(immediate);
157168
}
169+
170+
private class StopAllAction extends AbstractAction {
171+
172+
public StopAllAction() {
173+
super("Stop animations");
174+
}
175+
176+
@Override
177+
public void actionPerformed(ActionEvent e) {
178+
for(JmeAnimClip layer: JmeAnimComposer.this.playingAnimation.values()) {
179+
layer.stop();
180+
}
181+
}
182+
}
183+
158184
}

0 commit comments

Comments
 (0)