aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJoshua Slack <[email protected]>2012-11-28 08:07:40 -0800
committerJoshua Slack <[email protected]>2012-11-28 08:07:40 -0800
commit0713beb1d75ccda959f5de3dfa36c189d3cdba18 (patch)
tree27cf043974fa82043f6658a8bf4e0af4db421d40
parent49f31991999b0986d454caff48127206d17bf5eb (diff)
parent103369aca26c829045125138f1eea7de7bef9472 (diff)
Merge pull request #6 from ricardolpd/pull_request_Branch
Add animation states in the AnimationManager
-rw-r--r--trunk/ardor3d-animation/src/main/java/com/ardor3d/extension/animation/skeletal/AnimationManager.java61
-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.java450
-rw-r--r--trunk/ardor3d-examples/src/main/resources/com/ardor3d/example/media/thumbnails/pipeline_AnimationStateExample.jpgbin0 -> 51443 bytes
5 files changed, 523 insertions, 0 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 0c10ffe..2bd7ad9 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,6 +10,7 @@
package com.ardor3d.extension.animation.skeletal;
+import java.util.Collection;
import java.util.List;
import java.util.Map;
@@ -38,6 +39,10 @@ import com.google.common.collect.MapMaker;
*/
public class AnimationManager {
+ public enum AnimationUpdateState {
+ 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.
@@ -76,6 +81,13 @@ public class AnimationManager {
private 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 _previousAnimationState;
+
+ /**
* Construct a new AnimationManager.
*
* @param globalTimer
@@ -139,6 +151,25 @@ public class AnimationManager {
}
/**
+ * @param newAnimationState
+ * the new animation state in the animation Manager.
+ */
+ public void setAnimationState(final AnimationUpdateState newAnimationState) {
+ if (newAnimationState == AnimationUpdateState.pause && _currentAnimationState == AnimationUpdateState.stop) {
+ return;
+ }
+ _previousAnimationState = _currentAnimationState;
+ _currentAnimationState = newAnimationState;
+ }
+
+ /**
+ * @return the currentAnimationState.
+ */
+ public AnimationUpdateState getAnimationState() {
+ return _currentAnimationState;
+ }
+
+ /**
* @param pose
* a pose to add to be updated by this manager.
*/
@@ -213,6 +244,10 @@ 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);
@@ -244,6 +279,32 @@ 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/blendtree/ClipSource.java b/trunk/ardor3d-animation/src/main/java/com/ardor3d/extension/animation/skeletal/blendtree/ClipSource.java
index 9674c8f..6dfb208 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,6 +94,8 @@ 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 4d7d542..d56a391 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,6 +39,8 @@ 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();
@@ -118,6 +120,14 @@ 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
new file mode 100644
index 0000000..ef95fc2
--- /dev/null
+++ b/trunk/ardor3d-examples/src/main/java/com/ardor3d/example/pipeline/AnimationStateExample.java
@@ -0,0 +1,450 @@
+/**
+ * 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.example.pipeline;
+
+import java.io.IOException;
+import java.util.EnumSet;
+import java.util.List;
+
+import com.ardor3d.example.ExampleBase;
+import com.ardor3d.example.Purpose;
+import com.ardor3d.extension.animation.skeletal.AnimationListener;
+import com.ardor3d.extension.animation.skeletal.AnimationManager;
+import com.ardor3d.extension.animation.skeletal.AnimationManager.AnimationUpdateState;
+import com.ardor3d.extension.animation.skeletal.SkeletonPose;
+import com.ardor3d.extension.animation.skeletal.SkinnedMesh;
+import com.ardor3d.extension.animation.skeletal.SkinnedMeshCombineLogic;
+import com.ardor3d.extension.animation.skeletal.blendtree.SimpleAnimationApplier;
+import com.ardor3d.extension.animation.skeletal.clip.AnimationClip;
+import com.ardor3d.extension.animation.skeletal.state.loader.InputStore;
+import com.ardor3d.extension.animation.skeletal.state.loader.JSLayerImporter;
+import com.ardor3d.extension.animation.skeletal.util.MissingCallback;
+import com.ardor3d.extension.animation.skeletal.util.SkeletalDebugger;
+import com.ardor3d.extension.model.collada.jdom.ColladaImporter;
+import com.ardor3d.extension.model.collada.jdom.data.ColladaStorage;
+import com.ardor3d.extension.model.collada.jdom.data.SkinData;
+import com.ardor3d.extension.model.util.nvtristrip.NvTriangleStripper;
+import com.ardor3d.extension.ui.UIButton;
+import com.ardor3d.extension.ui.UICheckBox;
+import com.ardor3d.extension.ui.UIComponent;
+import com.ardor3d.extension.ui.UIFrame;
+import com.ardor3d.extension.ui.UIFrame.FrameButtons;
+import com.ardor3d.extension.ui.UIHud;
+import com.ardor3d.extension.ui.UILabel;
+import com.ardor3d.extension.ui.UIPanel;
+import com.ardor3d.extension.ui.event.ActionEvent;
+import com.ardor3d.extension.ui.event.ActionListener;
+import com.ardor3d.extension.ui.layout.AnchorLayout;
+import com.ardor3d.extension.ui.layout.AnchorLayoutData;
+import com.ardor3d.extension.ui.util.Alignment;
+import com.ardor3d.framework.NativeCanvas;
+import com.ardor3d.light.DirectionalLight;
+import com.ardor3d.math.ColorRGBA;
+import com.ardor3d.math.Vector3;
+import com.ardor3d.renderer.Camera;
+import com.ardor3d.renderer.Renderer;
+import com.ardor3d.renderer.state.CullState;
+import com.ardor3d.renderer.state.CullState.Face;
+import com.ardor3d.renderer.state.GLSLShaderObjectsState;
+import com.ardor3d.renderer.state.RenderState.StateType;
+import com.ardor3d.scenegraph.Node;
+import com.ardor3d.scenegraph.Spatial;
+import com.ardor3d.scenegraph.hint.DataMode;
+import com.ardor3d.scenegraph.visitor.Visitor;
+import com.ardor3d.util.ReadOnlyTimer;
+import com.ardor3d.util.geom.MeshCombiner;
+import com.ardor3d.util.resource.ResourceLocatorTool;
+import com.ardor3d.util.resource.ResourceSource;
+import com.ardor3d.util.resource.URLResourceSource;
+
+/**
+ * Illustrates loading several animations from Collada and arranging them in an animation state machine.
+ */
+@Purpose(htmlDescriptionKey = "com.ardor3d.example.pipeline.AnimationStateExample", //
+thumbnailPath = "com/ardor3d/example/media/thumbnails/pipeline_AnimationStateExample.jpg", //
+maxHeapMemory = 64)
+public class AnimationStateExample extends ExampleBase {
+
+ private Spatial primeModel;
+ private boolean showSkeleton = false, showJointLabels = false;
+
+ private UILabel frameRateLabel;
+ private UIHud hud;
+
+ private int frames = 0;
+ private long startTime = System.currentTimeMillis();
+
+ private AnimationManager manager;
+ private SkeletonPose pose;
+
+ private UIButton runWalkButton, punchButton, playPauseButton, stopButton;
+
+ private GLSLShaderObjectsState gpuShader;
+
+ private final Node skNode = new Node("model");
+
+ public static void main(final String[] args) {
+ ExampleBase.start(AnimationStateExample.class);
+ }
+
+ @Override
+ protected void initExample() {
+ _canvas.setTitle("Ardor3D - Animation State Example");
+ _canvas.getCanvasRenderer().getRenderer().setBackgroundColor(ColorRGBA.GRAY);
+
+ // set camera
+ final Camera cam = _canvas.getCanvasRenderer().getCamera();
+ cam.setLocation(280, 372, -280);
+ cam.lookAt(new Vector3(250, 350, -280), Vector3.UNIT_Y);
+ cam.setFrustumPerspective(50.0, cam.getWidth() / (double) cam.getHeight(), .25, 900);
+ cam.update();
+
+ // speed up wasd control a little
+ _controlHandle.setMoveSpeed(200);
+
+ _lightState.detachAll();
+ final DirectionalLight light = new DirectionalLight();
+ light.setDiffuse(new ColorRGBA(0.75f, 0.75f, 0.75f, 0.75f));
+ light.setAmbient(new ColorRGBA(0.25f, 0.25f, 0.25f, 1.0f));
+ light.setDirection(new Vector3(-1, -1, -1).normalizeLocal());
+ light.setEnabled(true);
+ _lightState.attach(light);
+
+ // Load collada model
+ createCharacter();
+
+ // Create our options frame and fps label
+ createHUD();
+ }
+
+ private void createHUD() {
+ hud = new UIHud();
+ hud.setupInput(_canvas, _physicalLayer, _logicalLayer);
+ hud.setMouseManager(_mouseManager);
+
+ // Add fps display
+ frameRateLabel = new UILabel("X");
+ frameRateLabel.setHudXY(5,
+ _canvas.getCanvasRenderer().getCamera().getHeight() - 5 - frameRateLabel.getContentHeight());
+ frameRateLabel.setForegroundColor(ColorRGBA.WHITE);
+ hud.add(frameRateLabel);
+
+ final UIFrame optionsFrame = new UIFrame("Controls", EnumSet.noneOf(FrameButtons.class));
+
+ final UIPanel basePanel = optionsFrame.getContentPanel();
+ basePanel.setLayout(new AnchorLayout());
+
+ runWalkButton = new UIButton("Start running...");
+ runWalkButton.setLayoutData(new AnchorLayoutData(Alignment.TOP_LEFT, basePanel, Alignment.TOP_LEFT, 5, -5));
+ runWalkButton.addActionListener(new ActionListener() {
+ boolean walk = true;
+
+ public void actionPerformed(final ActionEvent event) {
+ if (!walk) {
+ if (manager.getBaseAnimationLayer().doTransition("walk")) {
+ runWalkButton.setButtonText("Start running...");
+ walk = true;
+ }
+ } else {
+ if (manager.getBaseAnimationLayer().doTransition("run")) {
+ runWalkButton.setButtonText("Start walking...");
+ walk = false;
+ }
+ }
+ }
+ });
+ basePanel.add(runWalkButton);
+
+ punchButton = new UIButton("PUNCH!");
+ punchButton
+ .setLayoutData(new AnchorLayoutData(Alignment.TOP_LEFT, runWalkButton, Alignment.BOTTOM_LEFT, 0, -5));
+ punchButton.addActionListener(new ActionListener() {
+ public void actionPerformed(final ActionEvent event) {
+ manager.findAnimationLayer("punch").setCurrentState("punch_right", true);
+ punchButton.setEnabled(false);
+ }
+ });
+ basePanel.add(punchButton);
+
+ playPauseButton = new UIButton("Pause");
+ playPauseButton.setLayoutData(new AnchorLayoutData(Alignment.TOP_LEFT, punchButton, Alignment.BOTTOM_LEFT, 0,
+ -5));
+ playPauseButton.addActionListener(new ActionListener() {
+ public void actionPerformed(final ActionEvent event) {
+ if (playPauseButton.getText().equals("Pause")) {
+ manager.setAnimationState(AnimationUpdateState.pause);
+ playPauseButton.setButtonText("Play");
+ } else {
+ manager.setAnimationState(AnimationUpdateState.play);
+ playPauseButton.setButtonText("Pause");
+ }
+ }
+ });
+ basePanel.add(playPauseButton);
+
+ stopButton = new UIButton("Stop");
+ stopButton
+ .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);
+ playPauseButton.setButtonText("Play");
+ }
+ });
+ basePanel.add(stopButton);
+
+ final UICheckBox gpuSkinningCheck = new UICheckBox("Use GPU skinning");
+ gpuSkinningCheck.setLayoutData(new AnchorLayoutData(Alignment.TOP_LEFT, stopButton, Alignment.BOTTOM_LEFT, 0,
+ -5));
+ gpuSkinningCheck.setSelected(false);
+ gpuSkinningCheck.addActionListener(new ActionListener() {
+ public void actionPerformed(final ActionEvent event) {
+ _root.acceptVisitor(new Visitor() {
+ @Override
+ public void visit(final Spatial spatial) {
+ if (spatial instanceof SkinnedMesh) {
+ final SkinnedMesh skinnedSpatial = (SkinnedMesh) spatial;
+ if (gpuSkinningCheck.isSelected()) {
+ skinnedSpatial.setGPUShader(gpuShader);
+ skinnedSpatial.setUseGPU(true);
+ } else {
+ skinnedSpatial.setGPUShader(null);
+ skinnedSpatial.clearRenderState(StateType.GLSLShader);
+ skinnedSpatial.setUseGPU(false);
+ }
+ }
+ }
+ }, true);
+ }
+ });
+ basePanel.add(gpuSkinningCheck);
+
+ final UICheckBox vboCheck = new UICheckBox("Use VBO");
+ vboCheck.setLayoutData(new AnchorLayoutData(Alignment.TOP_LEFT, gpuSkinningCheck, Alignment.BOTTOM_LEFT, 0, -5));
+ vboCheck.setSelected(false);
+ vboCheck.addActionListener(new ActionListener() {
+ public void actionPerformed(final ActionEvent event) {
+ skNode.getSceneHints().setDataMode(vboCheck.isSelected() ? DataMode.VBO : DataMode.Arrays);
+ gpuShader.setUseAttributeVBO(vboCheck.isSelected());
+ }
+ });
+ basePanel.add(vboCheck);
+
+ final UICheckBox skeletonCheck = new UICheckBox("Show skeleton");
+ final UICheckBox boneLabelCheck = new UICheckBox("Show joint labels");
+ skeletonCheck.setLayoutData(new AnchorLayoutData(Alignment.TOP_LEFT, vboCheck, Alignment.BOTTOM_LEFT, 0, -5));
+ skeletonCheck.setSelected(showSkeleton);
+ skeletonCheck.addActionListener(new ActionListener() {
+
+ public void actionPerformed(final ActionEvent event) {
+ showSkeleton = skeletonCheck.isSelected();
+ boneLabelCheck.setEnabled(showSkeleton);
+ }
+ });
+ basePanel.add(skeletonCheck);
+
+ boneLabelCheck.setLayoutData(new AnchorLayoutData(Alignment.TOP_LEFT, skeletonCheck, Alignment.BOTTOM_LEFT, 0,
+ -5));
+ boneLabelCheck.setSelected(false);
+ boneLabelCheck.setEnabled(showSkeleton);
+ boneLabelCheck.addActionListener(new ActionListener() {
+
+ public void actionPerformed(final ActionEvent event) {
+ showJointLabels = boneLabelCheck.isSelected();
+ }
+ });
+ basePanel.add(boneLabelCheck);
+
+ optionsFrame.updateMinimumSizeFromContents();
+ optionsFrame.layout();
+ optionsFrame.pack();
+
+ optionsFrame.setUseStandin(true);
+ optionsFrame.setOpacity(0.8f);
+
+ final Camera cam = _canvas.getCanvasRenderer().getCamera();
+ optionsFrame.setLocalXY(cam.getWidth() - optionsFrame.getLocalComponentWidth() - 10, cam.getHeight()
+ - optionsFrame.getLocalComponentHeight() - 10);
+ hud.add(optionsFrame);
+
+ UIComponent.setUseTransparency(true);
+ }
+
+ private void createCharacter() {
+ try {
+ skNode.detachAllChildren();
+ _root.attachChild(skNode);
+
+ final long time = System.currentTimeMillis();
+ final ColladaImporter colladaImporter = new ColladaImporter();
+
+ // OPTIMIZATION: run GeometryTool on collada meshes to reduce redundant vertices...
+ colladaImporter.setOptimizeMeshes(true);
+
+ // Load the collada scene
+ final String mainFile = "collada/skeleton/skeleton.walk.dae";
+ final ColladaStorage storage = colladaImporter.load(mainFile);
+ final Node colladaNode = storage.getScene();
+ final List<SkinData> skinDatas = storage.getSkins();
+ pose = skinDatas.get(0).getPose();
+
+ createAnimation();
+
+ System.out.println("Importing: " + mainFile);
+ System.out.println("Took " + (System.currentTimeMillis() - time) + " ms");
+
+ gpuShader = new GLSLShaderObjectsState();
+ gpuShader.setEnabled(true);
+ try {
+ gpuShader.setVertexShader(ResourceLocatorTool.getClassPathResourceAsStream(AnimationStateExample.class,
+ "com/ardor3d/extension/animation/skeletal/skinning_gpu_texture.vert"));
+ gpuShader.setFragmentShader(ResourceLocatorTool.getClassPathResourceAsStream(
+ AnimationStateExample.class,
+ "com/ardor3d/extension/animation/skeletal/skinning_gpu_texture.frag"));
+
+ gpuShader.setUniform("texture", 0);
+ gpuShader.setUniform("lightDirection", new Vector3(1, 1, 1).normalizeLocal());
+ } catch (final IOException ioe) {
+ ioe.printStackTrace();
+ }
+
+ // OPTIMIZATION: SkinnedMesh combining... Useful in our case because the skeleton model is composed of 2
+ // separate meshes.
+ primeModel = MeshCombiner.combine(colladaNode, new SkinnedMeshCombineLogic());
+ // Non-combined:
+ // primeModel = colladaNode;
+
+ // OPTIMIZATION: turn on the buffers in our skeleton so they can be shared. (reuse ids)
+ primeModel.acceptVisitor(new Visitor() {
+ @Override
+ public void visit(final Spatial spatial) {
+ if (spatial instanceof SkinnedMesh) {
+ final SkinnedMesh skinnedSpatial = (SkinnedMesh) spatial;
+ skinnedSpatial.recreateWeightAttributeBuffer();
+ skinnedSpatial.recreateJointAttributeBuffer();
+ }
+ }
+ }, true);
+
+ // OPTIMIZATION: run nv strippifyier on model...
+ final NvTriangleStripper stripper = new NvTriangleStripper();
+ stripper.setReorderVertices(true);
+ primeModel.acceptVisitor(stripper, true);
+
+ // OPTIMIZATION: don't draw surfaces that face away from the camera...
+ final CullState cullState = new CullState();
+ cullState.setCullFace(Face.Back);
+ primeModel.setRenderState(cullState);
+
+ for (int i = 0; i < 10; i++) {
+ for (int j = 0; j < 10; j++) {
+ // Add copy of model
+ final Spatial copy = primeModel.makeCopy(true);
+ copy.setTranslation(-i * 50, 0, -50 - (j * 50));
+ skNode.attachChild(copy);
+ }
+ }
+ } catch (final Exception ex) {
+ ex.printStackTrace();
+ }
+ }
+
+ private void createAnimation() {
+ final ColladaImporter colladaImporter = new ColladaImporter();
+
+ // Make our manager
+ manager = new AnimationManager(_timer, pose);
+
+ // Add our "applier logic".
+ final SimpleAnimationApplier applier = new SimpleAnimationApplier();
+ manager.setApplier(applier);
+
+ // Add a call back to load clips.
+ final InputStore input = new InputStore();
+ input.getClips().setMissCallback(new MissingCallback<String, AnimationClip>() {
+ public AnimationClip getValue(final String key) {
+ try {
+ final ColladaStorage storage1 = colladaImporter.load("collada/skeleton/" + key + ".dae");
+ return storage1.extractChannelsAsClip(key);
+ } catch (final IOException e) {
+ e.printStackTrace();
+ }
+ return null;
+ }
+ });
+
+ // Load our layer and states from script
+ try {
+ final ResourceSource layersFile = new URLResourceSource(ResourceLocatorTool.getClassPathResource(
+ AnimationStateExample.class, "com/ardor3d/example/pipeline/AnimationCopyExample.js"));
+ JSLayerImporter.addLayers(layersFile, manager, input);
+ } catch (final Exception e) {
+ e.printStackTrace();
+ }
+
+ // kick things off by setting our starting states
+ manager.getBaseAnimationLayer().setCurrentState("walk_anim", true);
+
+ // add callback for our UI
+ manager.findClipInstance("skeleton.punch").addAnimationListener(new AnimationListener() {
+ public void animationFinished() {
+ punchButton.setEnabled(true);
+ }
+ });
+ }
+
+ @Override
+ protected void updateExample(final ReadOnlyTimer timer) {
+ hud.updateGeometricState(timer.getTimePerFrame());
+
+ final long now = System.currentTimeMillis();
+ final long dt = now - startTime;
+ if (dt > 200) {
+ final long fps = Math.round(1e3 * frames / dt);
+ frameRateLabel.setText(fps + " fps");
+
+ startTime = now;
+ frames = 0;
+ }
+ frames++;
+
+ manager.update();
+ }
+
+ @Override
+ protected void updateLogicalLayer(final ReadOnlyTimer timer) {
+ hud.getLogicalLayer().checkTriggers(timer.getTimePerFrame());
+ }
+
+ @Override
+ protected void renderExample(final Renderer renderer) {
+ super.renderExample(renderer);
+ renderer.renderBuckets();
+ renderer.draw(hud);
+ }
+
+ @Override
+ protected void renderDebug(final Renderer renderer) {
+ super.renderDebug(renderer);
+
+ if (showSkeleton) {
+ SkeletalDebugger.drawSkeletons(_root, renderer, false, showJointLabels);
+ }
+ }
+
+ public NativeCanvas getCanvas() {
+ return _canvas;
+ }
+
+ public Node getRoot() {
+ return _root;
+ }
+} \ No newline at end of file
diff --git a/trunk/ardor3d-examples/src/main/resources/com/ardor3d/example/media/thumbnails/pipeline_AnimationStateExample.jpg b/trunk/ardor3d-examples/src/main/resources/com/ardor3d/example/media/thumbnails/pipeline_AnimationStateExample.jpg
new file mode 100644
index 0000000..cf641d9
--- /dev/null
+++ b/trunk/ardor3d-examples/src/main/resources/com/ardor3d/example/media/thumbnails/pipeline_AnimationStateExample.jpg
Binary files differ