aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--trunk/ardor3d-animation/src/main/java/com/ardor3d/extension/animation/skeletal/AnimationManager.java164
-rw-r--r--trunk/ardor3d-animation/src/main/java/com/ardor3d/extension/animation/skeletal/AnimationUpdateStateListener.java19
-rw-r--r--trunk/ardor3d-animation/src/main/java/com/ardor3d/extension/animation/skeletal/blendtree/ClipSource.java2
-rw-r--r--trunk/ardor3d-animation/src/main/java/com/ardor3d/extension/animation/skeletal/clip/AnimationClipInstance.java10
-rw-r--r--trunk/ardor3d-examples/src/main/java/com/ardor3d/example/pipeline/AnimationStateExample.java6
-rw-r--r--trunk/ardor3d-examples/src/main/resources/com/ardor3d/example/i18n/example_descriptions.properties1
6 files changed, 140 insertions, 62 deletions
diff --git a/trunk/ardor3d-animation/src/main/java/com/ardor3d/extension/animation/skeletal/AnimationManager.java b/trunk/ardor3d-animation/src/main/java/com/ardor3d/extension/animation/skeletal/AnimationManager.java
index 2bd7ad9..5ec9bf5 100644
--- a/trunk/ardor3d-animation/src/main/java/com/ardor3d/extension/animation/skeletal/AnimationManager.java
+++ b/trunk/ardor3d-animation/src/main/java/com/ardor3d/extension/animation/skeletal/AnimationManager.java
@@ -10,7 +10,6 @@
package com.ardor3d.extension.animation.skeletal;
-import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -40,52 +39,55 @@ import com.google.common.collect.MapMaker;
public class AnimationManager {
public enum AnimationUpdateState {
- play, pause, stop
+ Play, Pause, Stop
}
/**
* A timer to use as our "global" time keeper. All animation sources under this manager will use this timer as their
* time reference.
*/
- private ReadOnlyTimer _globalTimer;
+ protected ReadOnlyTimer _globalTimer;
/** The pose(s) this manager manipulates on update. */
- private List<SkeletonPose> _applyToPoses;
+ protected List<SkeletonPose> _applyToPoses;
/** The root of a scenegraph we can look for transform animation targets under. */
- private final Spatial _sceneRoot;
+ protected final Spatial _sceneRoot;
/** Local instance information for any clips referenced by the layers/blend trees in this manager. */
- private final Map<AnimationClip, AnimationClipInstance> _clipInstances = new MapMaker().weakKeys().makeMap();
+ protected final Map<AnimationClip, AnimationClipInstance> _clipInstances = new MapMaker().weakKeys().makeMap();
/** A logic object responsible for taking animation data and applying it to skeleton poses. */
- private AnimationApplier _applier;
+ protected AnimationApplier _applier;
/** Our animation layers. */
- private final List<AnimationLayer> _layers = Lists.newArrayList();
+ protected final List<AnimationLayer> _layers = Lists.newArrayList();
/**
* A map of key->Double values, allowing control over elements under this manager without needing precise knowledge
* of the layout of those layers, blend trees, etc. Missing keys will return 0.0 and log a warning.
*/
- private final LoggingMap<String, Double> _valuesStore = new LoggingMap<String, Double>();
+ protected final LoggingMap<String, Double> _valuesStore = new LoggingMap<String, Double>();
/**
* The throttle rate of animation. Default is 60fps (1/60.0). Set to 0 to disable throttling.
*/
- private double _updateRate = 1.0 / 60.0;
+ protected double _updateRate = 1.0 / 60.0;
/**
* The global time we last processed an animation. (To use when checking our throttle.)
*/
- private double _lastUpdate = 0.0;
+ protected double _lastUpdate = 0.0;
/**
* Sets the current animationState used to control if animation is playing, pausing or stopped.
*/
- protected AnimationUpdateState _currentAnimationState = AnimationUpdateState.play;
+ protected AnimationUpdateState _currentAnimationState = AnimationUpdateState.Play;
- protected AnimationUpdateState _previousAnimationState;
+ /**
+ * Listeners for changes to this manager's AnimationUpdateState.
+ */
+ protected final List<AnimationUpdateStateListener> _updateStateListeners = Lists.newArrayList();
/**
* Construct a new AnimationManager.
@@ -150,22 +152,114 @@ public class AnimationManager {
_globalTimer = timer;
}
+ public void play() {
+ setAnimationUpdateState(AnimationUpdateState.Play);
+ }
+
+ public void pause() {
+ setAnimationUpdateState(AnimationUpdateState.Pause);
+ }
+
+ public void stop() {
+ setAnimationUpdateState(AnimationUpdateState.Stop);
+ }
+
+ public boolean isPlaying() {
+ return _currentAnimationState == AnimationUpdateState.Play;
+ }
+
+ public boolean isPaused() {
+ return _currentAnimationState == AnimationUpdateState.Pause;
+ }
+
/**
* @param newAnimationState
* the new animation state in the animation Manager.
*/
- public void setAnimationState(final AnimationUpdateState newAnimationState) {
- if (newAnimationState == AnimationUpdateState.pause && _currentAnimationState == AnimationUpdateState.stop) {
+ public void setAnimationUpdateState(final AnimationUpdateState newAnimationState) {
+ if (newAnimationState == _currentAnimationState) {
+ // ignore if unchanged.
return;
}
- _previousAnimationState = _currentAnimationState;
+ final double currentTime = _globalTimer.getTimeInSeconds();
+ if (newAnimationState == AnimationUpdateState.Pause) {
+ if (_currentAnimationState == AnimationUpdateState.Stop) {
+ // ignore a non-allowed situation
+ return;
+ }
+
+ // Keep track of current time so we can resume active clips
+ _lastUpdate = currentTime;
+ } else if (newAnimationState == AnimationUpdateState.Play) {
+ // reset instances
+ if (_currentAnimationState == AnimationUpdateState.Pause) {
+ final double offset = currentTime - _lastUpdate;
+ for (final AnimationClipInstance instance : _clipInstances.values()) {
+ if (instance.isActive()) {
+ instance.setStartTime(instance.getStartTime() + offset);
+ }
+ }
+ } else {
+ // must be resuming from stop, so restart clips
+ for (final AnimationClipInstance instance : _clipInstances.values()) {
+ if (instance.isActive()) {
+ instance.setStartTime(currentTime);
+ }
+ }
+ }
+ }
+
+ final AnimationUpdateState oldState = _currentAnimationState;
_currentAnimationState = newAnimationState;
+
+ // Let listeners know we have changed state.
+ fireAnimationUpdateStateChange(oldState);
+ }
+
+ /**
+ * Notify any listeners of the state change
+ *
+ * @param oldState
+ * previous state
+ */
+ protected void fireAnimationUpdateStateChange(final AnimationUpdateState oldState) {
+ for (final AnimationUpdateStateListener listener : _updateStateListeners) {
+ listener.stateChanged(oldState, _currentAnimationState);
+ }
+ }
+
+ /**
+ * Add an AnimationUpdateStateListener to this manager.
+ *
+ * @param listener
+ * the listener to add.
+ */
+ public void addAnimationUpdateStateListener(final AnimationUpdateStateListener listener) {
+ _updateStateListeners.add(listener);
+ }
+
+ /**
+ * Remove an AnimationUpdateStateListener from this manager.
+ *
+ * @param listener
+ * the listener to remove.
+ * @return true if the listener was found
+ */
+ public boolean removeAnimationUpdateStateListener(final AnimationUpdateStateListener listener) {
+ return _updateStateListeners.remove(listener);
+ }
+
+ /**
+ * Remove any AnimationUpdateStateListeners registered with this manager.
+ */
+ public void clearAnimationUpdateStateListeners() {
+ _updateStateListeners.clear();
}
/**
* @return the currentAnimationState.
*/
- public AnimationUpdateState getAnimationState() {
+ public AnimationUpdateState getAnimationUpdateState() {
return _currentAnimationState;
}
@@ -231,6 +325,12 @@ public class AnimationManager {
* SkeletonPoses set on the manager.
*/
public void update() {
+
+ if (_currentAnimationState != AnimationUpdateState.Play) {
+ // no animation allowed. Exit.
+ return;
+ }
+
// grab current global time
final double globalTime = _globalTimer.getTimeInSeconds();
@@ -244,10 +344,6 @@ public class AnimationManager {
_lastUpdate = globalTime - (globalTime - _lastUpdate) % _updateRate;
}
- // update animationState
- updateLayersForAnimationState(globalTime);
-
-
// move the time forward on the layers
for (int i = 0; i < _layers.size(); ++i) {
final AnimationLayer layer = _layers.get(i);
@@ -279,32 +375,6 @@ public class AnimationManager {
}
/**
- * @param globalTime
- * current global time in seconds
- * @return
- */
- protected void updateLayersForAnimationState(final double globalTime) {
-
- final Collection<AnimationClipInstance> clipInstances = _clipInstances.values();
- for (final AnimationClipInstance instance : clipInstances) {
- switch (_currentAnimationState) {
- case stop:
- instance.setActive(false);
- break;
- case pause:
- if (instance.isActive()) {
- final double startTime = globalTime - instance.getCurrentTime() / instance.getTimeScale();
- instance.setStartTime(startTime);
- }
- break;
- case play:
- instance.setActive(true);
- break;
- }
- }
- }
-
- /**
* Retrieve and track an instance of an animation clip to be used with this manager.
*
* @param clip
diff --git a/trunk/ardor3d-animation/src/main/java/com/ardor3d/extension/animation/skeletal/AnimationUpdateStateListener.java b/trunk/ardor3d-animation/src/main/java/com/ardor3d/extension/animation/skeletal/AnimationUpdateStateListener.java
new file mode 100644
index 0000000..0e6a6fc
--- /dev/null
+++ b/trunk/ardor3d-animation/src/main/java/com/ardor3d/extension/animation/skeletal/AnimationUpdateStateListener.java
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2008-2012 Ardor Labs, Inc.
+ *
+ * This file is part of Ardor3D.
+ *
+ * Ardor3D is free software: you can redistribute it and/or modify it
+ * under the terms of its license which may be found in the accompanying
+ * LICENSE file or at <http://www.ardor3d.com/LICENSE>.
+ */
+
+package com.ardor3d.extension.animation.skeletal;
+
+import com.ardor3d.extension.animation.skeletal.AnimationManager.AnimationUpdateState;
+
+public interface AnimationUpdateStateListener {
+
+ public void stateChanged(AnimationUpdateState oldState, AnimationUpdateState newState);
+
+}
diff --git a/trunk/ardor3d-animation/src/main/java/com/ardor3d/extension/animation/skeletal/blendtree/ClipSource.java b/trunk/ardor3d-animation/src/main/java/com/ardor3d/extension/animation/skeletal/blendtree/ClipSource.java
index 6dfb208..9674c8f 100644
--- a/trunk/ardor3d-animation/src/main/java/com/ardor3d/extension/animation/skeletal/blendtree/ClipSource.java
+++ b/trunk/ardor3d-animation/src/main/java/com/ardor3d/extension/animation/skeletal/blendtree/ClipSource.java
@@ -94,8 +94,6 @@ public class ClipSource implements BlendTreeSource {
// update the clip with the correct clip local time.
_clip.update(clockTime, instance);
-
- instance.setCurrentTime(clockTime);
}
return instance.isActive();
}
diff --git a/trunk/ardor3d-animation/src/main/java/com/ardor3d/extension/animation/skeletal/clip/AnimationClipInstance.java b/trunk/ardor3d-animation/src/main/java/com/ardor3d/extension/animation/skeletal/clip/AnimationClipInstance.java
index d56a391..4d7d542 100644
--- a/trunk/ardor3d-animation/src/main/java/com/ardor3d/extension/animation/skeletal/clip/AnimationClipInstance.java
+++ b/trunk/ardor3d-animation/src/main/java/com/ardor3d/extension/animation/skeletal/clip/AnimationClipInstance.java
@@ -39,8 +39,6 @@ public class AnimationClipInstance {
/** The global start time of our clip instance. */
private double _startTime = 0.0;
- private double _currentTime = 0.0;
-
/** Map of channel name -> state tracking objects. */
private final Map<String, Object> _clipStateObjects = Maps.newHashMap();
@@ -120,14 +118,6 @@ public class AnimationClipInstance {
_startTime = startTime;
}
- public double getCurrentTime() {
- return _currentTime;
- }
-
- public void setCurrentTime(final double duration) {
- _currentTime = duration;
- }
-
public Object getApplyTo(final AbstractAnimationChannel channel) {
final String channelName = channel.getChannelName();
Object rVal = _clipStateObjects.get(channelName);
diff --git a/trunk/ardor3d-examples/src/main/java/com/ardor3d/example/pipeline/AnimationStateExample.java b/trunk/ardor3d-examples/src/main/java/com/ardor3d/example/pipeline/AnimationStateExample.java
index ef95fc2..10a6002 100644
--- a/trunk/ardor3d-examples/src/main/java/com/ardor3d/example/pipeline/AnimationStateExample.java
+++ b/trunk/ardor3d-examples/src/main/java/com/ardor3d/example/pipeline/AnimationStateExample.java
@@ -180,10 +180,10 @@ public class AnimationStateExample extends ExampleBase {
playPauseButton.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent event) {
if (playPauseButton.getText().equals("Pause")) {
- manager.setAnimationState(AnimationUpdateState.pause);
+ manager.setAnimationUpdateState(AnimationUpdateState.Pause);
playPauseButton.setButtonText("Play");
} else {
- manager.setAnimationState(AnimationUpdateState.play);
+ manager.setAnimationUpdateState(AnimationUpdateState.Play);
playPauseButton.setButtonText("Pause");
}
}
@@ -195,7 +195,7 @@ public class AnimationStateExample extends ExampleBase {
.setLayoutData(new AnchorLayoutData(Alignment.TOP_LEFT, playPauseButton, Alignment.BOTTOM_LEFT, 0, -5));
stopButton.addActionListener(new ActionListener() {
public void actionPerformed(final ActionEvent event) {
- manager.setAnimationState(AnimationUpdateState.stop);
+ manager.setAnimationUpdateState(AnimationUpdateState.Stop);
playPauseButton.setButtonText("Play");
}
});
diff --git a/trunk/ardor3d-examples/src/main/resources/com/ardor3d/example/i18n/example_descriptions.properties b/trunk/ardor3d-examples/src/main/resources/com/ardor3d/example/i18n/example_descriptions.properties
index 8b1b7b6..03145e0 100644
--- a/trunk/ardor3d-examples/src/main/resources/com/ardor3d/example/i18n/example_descriptions.properties
+++ b/trunk/ardor3d-examples/src/main/resources/com/ardor3d/example/i18n/example_descriptions.properties
@@ -38,6 +38,7 @@ com.ardor3d.example.interpolation.LinearVector3InterpolationControllerExample=A
com.ardor3d.example.interpolation.QuaternionInterpolationControllerExample=A demonstration of the QuaternionInterpolationController class; which will rotate a Node each epoch by interpolating between the given quaternions.
com.ardor3d.example.pipeline.AnimationBlinnPhongExample=Illustrates gpu skinning with normal map, specular map and diffuse coloring.
com.ardor3d.example.pipeline.AnimationDemoExample=Illustrates loading several animations from Collada and arranging them in a controllable blend tree.
+com.ardor3d.example.pipeline.AnimationStateExample=Adds play/pause/stop controls to AnimationDemoExample.
com.ardor3d.example.pipeline.ColladaExample=Illustrates loading a model from Collada. If the model also contains an animation, the animation is played as well.
com.ardor3d.example.pipeline.ColladaManualAnimationExample=Illustrates loading a model from Collada and procedurally animating its joints.
com.ardor3d.example.pipeline.ExportImportExample=A demonstration of the BinaryImporter and BinaryExporter classes; which can export/import a Node to/from a data stream.