package graphics; //wraps keyframe data public class Animation { public boolean looping = true; private double[][] keyframes; private int lastFrame = -1; //index of last frame in animation public Animation(int numFrames) { keyframes = new double[numFrames][2]; } //returns number of frames actually added public int numFrames() { return lastFrame + 1; } //how many seconds is this animation? public double totalTime() { if (lastFrame < 0) return 0; return keyframes[lastFrame][0]; } public void addKeyFrame(double time, double value) { if (lastFrame >= 0 && keyframes[lastFrame][0] >= time) { System.err.println("Cannot add keyframe - new time is earlier than existing time"); return; } if (lastFrame == keyframes.length-1) { System.err.println("Cannot add keyframe - keyframe array is full"); return; } lastFrame++; keyframes[lastFrame][0] = time; keyframes[lastFrame][1] = value; } //interpolates keyframe value public double get(double time) { //if animation loops, wrap around total animation time if (looping) time %= totalTime(); //index of keyframe before or at specified time int frameIndex = -1; //find index where time falls in between //check edges - before first keyframe or after last? if (time <= keyframes[0][0]) return keyframes[0][1]; //value of first frame if (time >= keyframes[lastFrame][0]) return keyframes[lastFrame][1]; //value of last frame for (int i=0; i<=lastFrame; i++) { if (keyframes[i][0] <= time && keyframes[i+1][0] > time) { frameIndex = i; break; } } if (frameIndex < 0) //should never happen { System.err.println("Could not find a value in animation for time = "+time); return -1; } double t0 = keyframes[frameIndex][0]; double v0 = keyframes[frameIndex][1]; //time delta double dt = keyframes[frameIndex+1][0] - keyframes[frameIndex][0]; //value delta double dv = keyframes[frameIndex+1][1] - keyframes[frameIndex][1]; return v0 + dv*(time - t0)/dt; } }