Package com.ardor3d.extension.animation.skeletal.layer

Source Code of com.ardor3d.extension.animation.skeletal.layer.AnimationLayer

/**
* 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.layer;

import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;

import com.ardor3d.extension.animation.skeletal.AnimationManager;
import com.ardor3d.extension.animation.skeletal.state.AbstractFiniteState;
import com.ardor3d.extension.animation.skeletal.state.AbstractTransitionState;
import com.ardor3d.extension.animation.skeletal.state.StateOwner;
import com.ardor3d.extension.animation.skeletal.state.SteadyState;
import com.google.common.collect.Maps;

/**
* Animation layers are essentially independent state machines, managed by a single AnimationManager. Each maintains a
* set of possible "steady states" - main states that the layer can be in. The layer can only be in one state at any
* given time. It may transition between states, provided that a path is defined for transition from the current state
* to the desired one.
*/
public class AnimationLayer implements StateOwner {

    /** The layer name of the default base layer. */
    public static final String BASE_LAYER_NAME = "-BASE_LAYER-";

    /** our class logger */
    private static final Logger logger = Logger.getLogger(AnimationLayer.class.getName());

    /** Our animation states */
    private final Map<String, SteadyState> _steadyStates = Maps.newHashMap();

    /** Our current animation state */
    private AbstractFiniteState _currentState;

    /** our parent manager */
    private AnimationManager _manager;

    /** our layer blending module */
    private LayerBlender _layerBlender;

    /** the name of this layer, used for identification, so best if unique. */
    private final String _name;

    /** A map of general transitions for moving from the current state to another. */
    private final Map<String, AbstractTransitionState> _transitions = Maps.newHashMap();

    /**
     * Construct a new AnimationLayer.
     *
     * @param name
     *            the name of this layer, used for id purposes.
     */
    public AnimationLayer(final String name) {
        _name = name;
    }

    /**
     * Force the current state of the machine to the steady state with the given name. Used to set the FSM's initial
     * state.
     *
     * @param stateName
     *            the name of our state. If null, or is not present in this state machine, the current state is not
     *            changed.
     * @param rewind
     *            if true, the clip(s) in the given state will be rewound by setting its start time to the current time
     *            and setting it active.
     * @return true if succeeds
     */
    public boolean setCurrentState(final String stateName, final boolean rewind) {
        if (stateName != null) {
            final AbstractFiniteState state = _steadyStates.get(stateName);
            if (state != null) {
                setCurrentState(state, rewind);
                return true;
            } else {
                AnimationLayer.logger.warning("unable to find SteadyState named: " + stateName);
            }
        }
        return false;
    }

    /**
     * Sets the current finite state to the given state. Generally for transitional state use.
     *
     * @param state
     *            our new state. If null, then no state is currently set on this layer.
     * @param rewind
     *            if true, the clip(s) in the given state will be rewound by setting its start time to the current time
     *            and setting it active.
     */
    public void setCurrentState(final AbstractFiniteState state, final boolean rewind) {
        _currentState = state;
        if (state != null) {
            state.setLastStateOwner(this);
            if (rewind) {
                state.resetClips(_manager);
            }
        }
    }

    /**
     * Set the currently playing state on this layer to null.
     */
    public void clearCurrentState() {
        setCurrentState((AbstractFiniteState) null, false);
    }

    /**
     * Attempt to perform a transition. First, check the current state to see if it has a transition for the given key.
     * If not, check this layer for a general purpose transition. If no transition is found, this does nothing.
     *
     * @param key
     *            the transition key, a string key used to look up a transition in the current animation state.
     * @return true if there is a current state and we were able to do the given transition.
     */
    public boolean doTransition(final String key) {
        final AbstractFiniteState state = getCurrentState();
        // see if current state has a transition
        if (state instanceof SteadyState) {
            final SteadyState steadyState = (SteadyState) state;
            AbstractFiniteState nextState = steadyState.doTransition(key, this);
            if (nextState == null) {
                // no transition found, check if there is a global transition
                AbstractTransitionState transition = _transitions.get(key);
                if (transition == null) {
                    transition = _transitions.get("*");
                }
                if (transition != null) {
                    nextState = transition.doTransition(state, this);
                }
            }

            if (nextState != null) {
                if (nextState != state) {
                    setCurrentState(nextState, false);
                    return true;
                }
            }
        } else if (state == null) {
            // check if there is a global transition
            AbstractTransitionState transition = _transitions.get(key);
            if (transition == null) {
                transition = _transitions.get("*");
            }
            if (transition != null) {
                setCurrentState(transition.doTransition(state, this), true);
                return true;
            }
        }

        // no transition found
        return false;
    }

    /**
     * @return a set containing the names of our steady states.
     */
    public Set<String> getSteadyStateNames() {
        return _steadyStates.keySet();
    }

    /**
     * @return the current active finite state in this machine.
     */
    public AbstractFiniteState getCurrentState() {
        return _currentState;
    }

    /**
     * @param stateName
     *            the name of the steady state we are looking for.
     * @return our animation state, or null if none is found.
     */
    public SteadyState getSteadyState(final String stateName) {
        return _steadyStates.get(stateName);
    }

    /**
     * Add a new steady state to this layer.
     *
     * @param state
     *            the state to add.
     */
    public void addSteadyState(final SteadyState state) {
        if (state == null) {
            throw new IllegalArgumentException("state must not be null.");
        }
        _steadyStates.put(state.getName(), state);
    }

    /**
     * Remove the given steady state from our layer
     *
     * @param state
     *            the state to remove
     * @return true if the state was found for removal.
     */
    public boolean removeSteadyState(final SteadyState state) {
        return _steadyStates.remove(state.getName()) != null;
    }

    /**
     * Sets a reference back to the manager associated with this layer. Generally this is handled by the
     * AnimationManager itself as layers are added to it.
     *
     * @param manager
     *            the animation manager.
     */
    public void setManager(final AnimationManager manager) {
        _manager = manager;
    }

    /**
     * @return the manager associated with this layer.
     */
    public AnimationManager getManager() {
        return _manager;
    }

    /**
     * @return the name of this layer, used for identification, so best if unique.
     */
    public String getName() {
        return _name;
    }

    /**
     * @return a source data mapping for the channels involved in the current state/transition of this layer.
     */
    public Map<String, ? extends Object> getCurrentSourceData() {
        if (getLayerBlender() != null) {
            return getLayerBlender().getBlendedSourceData(getManager());
        }

        final AbstractFiniteState state = getCurrentState();
        if (state != null) {
            return state.getCurrentSourceData(getManager());
        } else {
            return null;
        }
    }

    /**
     * Update the layer blender in this animation layer to properly point to the previous layer.
     *
     * @param previousLayer
     *            the layer before this layer in the animation manager.
     */
    public void updateLayerBlending(final AnimationLayer previousLayer) {
        final LayerBlender blender = getLayerBlender();
        if (blender != null) {
            blender.setLayerA(previousLayer);
            blender.setLayerB(this);
        }
    }

    /**
     * @param layerBlender
     *            the layer blender to use for combining this layer's contents with others in the animation manager.
     */
    public void setLayerBlender(final LayerBlender layerBlender) {
        _layerBlender = layerBlender;
    }

    /**
     * @return the layer blender used for combining this layer's contents with others in the animation manager.
     */
    public LayerBlender getLayerBlender() {
        return _layerBlender;
    }

    @Override
    public void replaceState(final AbstractFiniteState currentState, final AbstractFiniteState newState) {
        if (getCurrentState() == currentState) {
            setCurrentState(newState, false);
        }
    }

    /**
     * Add a new general transition to this layer.
     *
     * @param keyword
     *            the reference key for the added transition.
     * @param state
     *            the transition state to add.
     * @throws IllegalArgumentException
     *             if keyword or state are null.
     */
    public void addTransition(final String keyword, final AbstractTransitionState state) {
        if (state == null) {
            throw new IllegalArgumentException("state must not be null.");
        }
        if (keyword == null) {
            throw new IllegalArgumentException("keyword must not be null.");
        }
        _transitions.put(keyword, state);
    }

    /**
     *
     * @param keyword
     *            the reference key for the transition state we wish to pull from this layer.
     * @return the transition related to the given keyword, or null if none are found.
     * @throws IllegalArgumentException
     *             if keyword is null.
     */
    public AbstractTransitionState getTransition(final String keyword) {
        if (keyword == null) {
            throw new IllegalArgumentException("keyword must not be null.");
        }
        return _transitions.get(keyword);
    }

    /**
     * @return a Set of the transition state keywords used by this layer.
     */
    public Set<String> getTransitionKeywords() {
        return _transitions.keySet();
    }

    /**
     * Remove a transition state by keyword.
     *
     * @param keyword
     *            the reference key for the transition state we wish to remove from this layer.
     * @return the removed transition, or null if none was found by the given keyword.
     * @throws IllegalArgumentException
     *             if keyword is null.
     */
    public AbstractTransitionState removeTransition(final String keyword) {
        if (keyword == null) {
            throw new IllegalArgumentException("keyword must not be null.");
        }
        return _transitions.remove(keyword);
    }

    /**
     * Remove the first instance of a specific transition state from this layer.
     *
     * @param transition
     *            the transition state we wish to remove from this steady state.
     * @return true if we found and removed the given transition.
     * @throws IllegalArgumentException
     *             if transition is null.
     */
    public boolean removeTransition(final AbstractTransitionState transition) {
        if (transition == null) {
            throw new IllegalArgumentException("transition must not be null.");
        }
        for (final String keyword : _transitions.keySet()) {
            if (_transitions.get(keyword).equals(transition)) {
                _transitions.remove(keyword);
                return true;
            }
        }
        return false;
    }
}
TOP

Related Classes of com.ardor3d.extension.animation.skeletal.layer.AnimationLayer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.