package org.andengine.entity.sprite;
import java.util.Arrays;
import org.andengine.util.math.MathUtils;
import org.andengine.util.modifier.IModifier.DeepCopyNotSupportedException;
import org.andengine.util.time.TimeConstants;
/**
* (c) Zynga 2012
*
* @author Nicolas Gramlich <ngramlich@zynga.com>
* @since 11:43:01 - 04.05.2012
*/
public class AnimationData implements IAnimationData {
// ===========================================================
// Constants
// ===========================================================
// ===========================================================
// Fields
// ===========================================================
private int mFrameCount;
private int[] mFrames;
private long[] mFrameDurations;
private int mFirstFrameIndex;
private int mLoopCount;
private long[] mFrameEndsInNanoseconds;
private long mAnimationDuration;
// ===========================================================
// Constructors
// ===========================================================
@Deprecated
public AnimationData() {
}
public AnimationData(final long pFrameDurationEach, final int pFrameCount) {
this.set(pFrameDurationEach, pFrameCount);
}
public AnimationData(final long pFrameDurationEach, final int pFrameCount, final boolean pLoop) {
this.set(pFrameDurationEach, pFrameCount, pLoop);
}
public AnimationData(final long pFrameDurationEach, final int pFrameCount, final int pLoopCount) {
this.set(pFrameDurationEach, pFrameCount, pLoopCount);
}
public AnimationData(final long[] pFrameDurations) {
this.set(pFrameDurations);
}
public AnimationData(final long[] pFrameDurations, final boolean pLoop) {
this.set(pFrameDurations, pLoop);
}
public AnimationData(final long[] pFrameDurations, final int pLoopCount) {
this.set(pFrameDurations, pLoopCount);
}
public AnimationData(final long[] pFrameDurations, final int pFirstFrameIndex, final int pLastFrameIndex, final boolean pLoop) {
this.set(pFrameDurations, pFirstFrameIndex, pLastFrameIndex, pLoop);
}
/**
* Animate specifics frames.
*
* @param pFrameDurations must have the same length as pFrames.
* @param pFrames indices of the frames to animate.
* @param pLoopCount
*/
public AnimationData(final long[] pFrameDurations, final int[] pFrames, final int pLoopCount) {
this.set(pFrameDurations, pFrames, pLoopCount);
}
/**
* @param pFrameDurations must have the same length as pFirstFrameIndex to pLastFrameIndex.
* @param pFirstFrameIndex
* @param pLastFrameIndex
* @param pLoopCount
*/
public AnimationData(final long[] pFrameDurations, final int pFirstFrameIndex, final int pLastFrameIndex, final int pLoopCount) {
this.set(pFrameDurations, pFirstFrameIndex, pLastFrameIndex, pLoopCount);
}
public AnimationData(final IAnimationData pAnimationData) {
this.set(pAnimationData);
}
@Override
public IAnimationData deepCopy() throws DeepCopyNotSupportedException {
return new AnimationData(this);
}
// ===========================================================
// Getter & Setter
// ===========================================================
// ===========================================================
// Methods for/from SuperClass/Interfaces
// ===========================================================
@Override
public int[] getFrames() {
return this.mFrames;
}
@Override
public long[] getFrameDurations() {
return this.mFrameDurations;
}
@Override
public int getLoopCount() {
return this.mLoopCount;
}
@Override
public int getFrameCount() {
return this.mFrameCount;
}
@Override
public int getFirstFrameIndex() {
return this.mFirstFrameIndex;
}
@Override
public long getAnimationDuration() {
return this.mAnimationDuration;
}
/**
* @param pAnimationProgress in milliseconds.
* @return
*/
@Override
public int calculateCurrentFrameIndex(final long pAnimationProgress) {
final long[] frameEnds = this.mFrameEndsInNanoseconds;
final int frameCount = this.mFrameCount;
for(int i = 0; i < frameCount; i++) {
if(frameEnds[i] > pAnimationProgress) {
return i;
}
}
return frameCount - 1;
}
@Override
public void set(final long pFrameDurationEach, final int pFrameCount) {
this.set(pFrameDurationEach, pFrameCount, true);
}
@Override
public void set(final long pFrameDurationEach, final int pFrameCount, final boolean pLoop) {
this.set(pFrameDurationEach, pFrameCount, (pLoop) ? IAnimationData.LOOP_CONTINUOUS : 0);
}
@Override
public void set(final long pFrameDurationEach, final int pFrameCount, final int pLoopCount) {
this.set(AnimationData.fillFrameDurations(pFrameDurationEach, pFrameCount), pLoopCount);
}
@Override
public void set(final long[] pFrameDurations) {
this.set(pFrameDurations, true);
}
@Override
public void set(final long[] pFrameDurations, final boolean pLoop) {
this.set(pFrameDurations, (pLoop) ? IAnimationData.LOOP_CONTINUOUS : 0);
}
@Override
public void set(final long[] pFrameDurations, final int pLoopCount) {
this.set(pFrameDurations, 0, pFrameDurations.length - 1, pLoopCount);
}
@Override
public void set(final long[] pFrameDurations, final int pFirstFrameIndex, final int pLastFrameIndex) {
this.set(pFrameDurations, pFirstFrameIndex, pLastFrameIndex, true);
}
@Override
public void set(final long[] pFrameDurations, final int pFirstFrameIndex, final int pLastFrameIndex, final boolean pLoop) {
this.set(pFrameDurations, pFirstFrameIndex, pLastFrameIndex, (pLoop) ? IAnimationData.LOOP_CONTINUOUS : 0);
}
/**
* @param pFrameDurations must have the same length as pFirstFrameIndex to pLastFrameIndex.
* @param pFirstFrameIndex
* @param pLastFrameIndex
* @param pLoopCount
*/
@Override
public void set(final long[] pFrameDurations, final int pFirstFrameIndex, final int pLastFrameIndex, final int pLoopCount) {
this.set(pFrameDurations, (pLastFrameIndex - pFirstFrameIndex) + 1, null, pFirstFrameIndex, pLoopCount);
if((pFirstFrameIndex + 1) > pLastFrameIndex) {
throw new IllegalArgumentException("An animation needs at least two tiles to animate between.");
}
}
/**
* Animate specifics frames.
*
* @param pFrameDurations must have the same length as pFrames.
* @param pFrames indices of the frames to animate.
*/
@Override
public void set(final long[] pFrameDurations, final int[] pFrames) {
this.set(pFrameDurations, pFrames, true);
}
/**
* Animate specifics frames.
*
* @param pFrameDurations must have the same length as pFrames.
* @param pFrames indices of the frames to animate.
* @param pLoop
*/
@Override
public void set(final long[] pFrameDurations, final int[] pFrames, final boolean pLoop) {
this.set(pFrameDurations, pFrames, (pLoop) ? IAnimationData.LOOP_CONTINUOUS : 0);
}
/**
* Animate specifics frames.
*
* @param pFrameDurations must have the same length as pFrames.
* @param pFrames indices of the frames to animate.
* @param pLoopCount
*/
@Override
public void set(final long[] pFrameDurations, final int[] pFrames, final int pLoopCount) {
this.set(pFrameDurations, pFrames.length, pFrames, 0, pLoopCount);
}
@Override
public void set(final IAnimationData pAnimationData) {
this.set(pAnimationData.getFrameDurations(), pAnimationData.getFrameCount(), pAnimationData.getFrames(), pAnimationData.getFirstFrameIndex(), pAnimationData.getLoopCount());
}
private void set(final long[] pFrameDurations, final int pFrameCount, final int[] pFrames, final int pFirstFrameIndex, final int pLoopCount) {
if(pFrameDurations.length != pFrameCount) {
throw new IllegalArgumentException("pFrameDurations does not equal pFrameCount!");
}
this.mFrameDurations = pFrameDurations;
this.mFrameCount = pFrameCount;
this.mFrames = pFrames;
this.mFirstFrameIndex = pFirstFrameIndex;
this.mLoopCount = pLoopCount;
if((this.mFrameEndsInNanoseconds == null) || (this.mFrameCount > this.mFrameEndsInNanoseconds.length)) {
this.mFrameEndsInNanoseconds = new long[this.mFrameCount];
}
final long[] frameEndsInNanoseconds = this.mFrameEndsInNanoseconds;
MathUtils.arraySumInto(this.mFrameDurations, frameEndsInNanoseconds, TimeConstants.NANOSECONDS_PER_MILLISECOND);
final long lastFrameEnd = frameEndsInNanoseconds[this.mFrameCount - 1];
this.mAnimationDuration = lastFrameEnd;
}
// ===========================================================
// Methods
// ===========================================================
private static long[] fillFrameDurations(final long pFrameDurationEach, final int pFrameCount) {
final long[] frameDurations = new long[pFrameCount];
Arrays.fill(frameDurations, pFrameDurationEach);
return frameDurations;
}
// ===========================================================
// Inner and Anonymous Classes
// ===========================================================
}