StaticAnimation.java
上传用户:haobig99
上传日期:2022-06-15
资源大小:369k
文件大小:19k
- /*
- * Copyright 2008 Sun Microsystems, Inc. All Rights Reserved.
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
- *
- * This code is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License version 2 only, as
- * published by the Free Software Foundation. Sun designates this
- * particular file as subject to the "Classpath" exception as provided
- * by Sun in the LICENSE file that accompanied this code.
- *
- * This code is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * version 2 for more details (a copy is included in the LICENSE file that
- * accompanied this code).
- *
- * You should have received a copy of the GNU General Public License version
- * 2 along with this work; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
- *
- * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
- * CA 95054 USA or visit www.sun.com if you need additional information or
- * have any questions.
- */
- package com.sun.lwuit;
- import com.sun.lwuit.animations.Animation;
- import com.sun.lwuit.geom.Dimension;
- import com.sun.lwuit.geom.Rectangle;
- import java.io.DataInputStream;
- import java.io.IOException;
- import java.util.Vector;
- /**
- * An animation with pre-existing
- *
- * @deprecated this class shouldn't be referenced directly, use the Image base class
- * for all functionality
- * @author Shai Almog
- */
- public class StaticAnimation extends IndexedImage implements Animation {
- private Frame[] frames;
-
- /**
- * The current frame doesn't point directly at the frames array since the first frame
- * is the image itself
- */
- private int currentFrame;
-
- private long animationStartTime;
- private int totalAnimationTime;
-
- private boolean loop;
-
- /**
- * Invoked with the first frame value
- */
- StaticAnimation(int width, int height, int[] palette, byte[] data) {
- super(width, height, palette, data);
- }
- /**
- * Returns the number of frames in the animation including the initial frame
- *
- * @return number of frames in the animation
- */
- public int getFrameCount() {
- // +1 for this image
- return frames.length + 1;
- }
-
- /**
- * The time in which the given frame should appear
- *
- * @param frame must be a number bigger than -1 and smaller than getFrameCount()
- * @return the time in milliseconds for the frame to appear
- */
- public int getFrameTime(int frame) {
- if(frame == 0) {
- return 0;
- }
- return frames[frame - 1].time;
- }
- /**
- * Returns the duration for the entire animation used to determine when to loop
- * @return total animation time in milliseconds
- */
- public int getTotalAnimationTime() {
- return totalAnimationTime;
- }
-
- /**
- * Returns the RGB for the given frame, this method is relatively slow and
- * it is recommended that you do not use it for realtime animations.
- *
- * @param frame must be a number bigger than -1 and smaller than getFrameCount()
- * @return ARGB pixels within the given frame
- */
- public int[] getFrameRGB(int frame) {
- if(frame == 0) {
- return getRGBCached();
- }
- Frame f = frames[frame - 1];
- int height = getHeight();
- int width = getWidth();
- int[] array = new int[width * height];
- byte[] imageDataByte = f.getKeyFrame();
- int[] palette = getPalette();
-
- for(int line = 0 ; line < height ; line++) {
- byte[] lineArray = f.getModifiedRow(line);
- if(lineArray != null) {
- for(int position = 0 ; position < width ; position++) {
- int i = lineArray[position] & 0xff;
- array[position + (width * line)] = palette[i];
- }
- } else {
- int currentPos = line * width;
- for(int position = 0 ; position < width ; position++) {
- int i = imageDataByte[position + currentPos] & 0xff;
- array[position + (width * line)] = palette[i];
- }
- }
- }
- return array;
- }
-
- /**
- * Creates an animation from the given stream, this method is used internally
- * by Resources normally you should not create static animations manually.
- *
- * @param data input stream from which the animation is loaded
- * @return An instance of a static animation
- * @throws IOException when the stream throws it
- */
- public static StaticAnimation createAnimation(DataInputStream data) throws IOException {
- // read the length of the palette;
- byte pSize = data.readByte();
- int[] palette = new int[pSize & 0xff];
- for(int iter = 0 ; iter < palette.length ; iter++) {
- palette[iter] = data.readInt();
- }
- int width = data.readShort();
- int height = data.readShort();
- int numberOfFrames = data.readByte() & 0xff;
- int totalAnimationTime = Math.max(1, data.readInt());
- boolean loop = data.readBoolean();
- byte[] array = new byte[width * height];
- data.readFully(array);
-
- // create the first frame of the animation
- StaticAnimation animation = new StaticAnimation(width, height, palette, array);
- animation.frames = new Frame[numberOfFrames -1];
- animation.totalAnimationTime = totalAnimationTime;
- animation.loop = loop;
- int currentTime = 0;
- byte[] lastKeyframe = array;
- Vector rowNumbers = new Vector();
- Vector rowValues = new Vector();
-
- // read the rest of the frames in the animation
- for(int iter = 1 ; iter < numberOfFrames ; iter++) {
- currentTime += data.readInt();
-
- // if this is a keyframe then just read the data else read the specific
- // modified row offsets
- if(data.readBoolean()) {
- array = new byte[width * height];
- data.readFully(array);
- animation.frames[iter - 1] = new Frame(currentTime, array);
- lastKeyframe = array;
- rowValues.removeAllElements();
- rowNumbers.removeAllElements();
- } else {
- boolean drawPrevious = data.readBoolean();
- int nextRow = data.readShort();
- while(nextRow != -1) {
- byte[] rowData = new byte[width];
- data.readFully(rowData);
- // if this row was already modified in a previous frame we can remove
- // the old row
- Integer rowInteger = new Integer(nextRow);
- int index = rowNumbers.indexOf(rowInteger);
- if(index > -1) {
- rowNumbers.removeElementAt(index);
- rowValues.removeElementAt(index);
- }
-
- rowNumbers.addElement(rowInteger);
- rowValues.addElement(rowData);
- nextRow = data.readShort();
- }
- animation.frames[iter - 1] = new Frame(currentTime, lastKeyframe, rowNumbers, rowValues, drawPrevious);
- }
- }
-
- return animation;
- }
-
- /**
- * @inheritDoc
- */
- public boolean animate() {
- if(animationStartTime == 0) {
- animationStartTime = System.currentTimeMillis();
- return false;
- }
- long currentTime = System.currentTimeMillis();
- int position = (int)(currentTime - animationStartTime);
- if(loop) {
- position %= totalAnimationTime;
- } else {
- if(position > totalAnimationTime) {
- return false;
- }
- }
-
- // special case for last frame
- if(currentFrame == frames.length) {
- if(position >= totalAnimationTime || position < frames[frames.length - 1].getTime()) {
- currentFrame = 0;
- return true;
- }
- } else {
- if(position >= frames[currentFrame].getTime()) {
- currentFrame++;
- if(currentFrame > frames.length + 1) {
- currentFrame = 0;
- }
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Restarts the animation
- */
- public void restart() {
- animationStartTime = System.currentTimeMillis();
- }
- /**
- * @inheritDoc
- */
- public void paint(Graphics g) {
- drawImage(g, g.getGraphics(), 0, 0);
- }
- /**
- * Indicates whether the animation will run in a loop or run only once
- *
- * @return true for a loop animation
- */
- public boolean isLoop() {
- return loop;
- }
- /**
- * Indicates whether the animation will run in a loop or run only once
- *
- * @param loop true for looping the animation
- */
- public void setLoop(boolean loop) {
- this.loop = loop;
- }
-
- /**
- * @inheritDoc
- */
- protected void drawImage(Graphics g, Object nativeGraphics, int x, int y) {
- if(currentFrame == 0) {
- super.drawImage(g, nativeGraphics, x, y);
- return;
- }
- int width = getWidth();
-
- if(lineCache == null || lineCache.length < width) {
- lineCache = new int[width];
- }
-
- // for performance we can calculate the visible drawing area so we don't have to
- // calculate the whole array
- int clipY = g.getClipY();
- int clipBottomY = g.getClipHeight() + clipY;
- int firstLine = 0;
- int lastLine = getHeight();
- if(clipY > y) {
- firstLine = clipY - y;
- }
- if(clipBottomY < y + getHeight()) {
- lastLine = clipBottomY - y;
- }
-
- Frame f = frames[currentFrame - 1];
- byte[] imageDataByte = f.getKeyFrame();
- int[] palette = getPalette();
-
- // we draw based on the last keyframe and if a row was modified then we
- // will draw that row rather than the keyframe
- for(int line = firstLine ; line < lastLine ; line += 1) {
- byte[] lineArray = f.getModifiedRow(line);
- if(lineArray != null) {
- for(int position = 0 ; position < width ; position++) {
- int i = lineArray[position] & 0xff;
- lineCache[position] = palette[i];
- }
- } else {
- //if(!f.isDrawPrevious()) {
- int currentPos = line * width;
- for(int position = 0 ; position < width ; position++) {
- int i = imageDataByte[position + currentPos] & 0xff;
- lineCache[position] = palette[i];
- }
- //}
- }
- g.drawRGB(lineCache, 0, x, y + line, width, 1, true);
- }
- }
-
- /**
- * @inheritDoc
- */
- public void scale(int width, int height) {
- StaticAnimation s = (StaticAnimation)scaled(width, height);
- super.scale(width, height);
- frames = s.frames;
- }
-
- /**
- * @inheritDoc
- */
- public Image scaled(int width, int height) {
- int srcWidth = getWidth();
- int srcHeight = getHeight();
- // no need to scale
- if(srcWidth == width && srcHeight == height){
- return this;
- }
- // save the previous keyframe all the time this allows us to swap a keyframe
- // based on its pointer rather than scale it twice
- byte[] lastKeyFrame = getImageDataByte();
- // scale the first frame
- StaticAnimation result = new StaticAnimation(width, height, getPalette(), scaleArray(lastKeyFrame, width, height));
- result.loop = loop;
- result.totalAnimationTime = totalAnimationTime;
- result.animationStartTime = animationStartTime;
- result.currentFrame = currentFrame;
- result.frames = new Frame[frames.length];
-
- byte[] lastKeyFrameAfterScale = result.getImageDataByte();
-
- int yRatio = (srcHeight << 16) / height;
- int xRatio = (srcWidth << 16) / width;
- // now we need to traverse all the frames and scale them one by one
- for(int iter = 0 ; iter < frames.length ; iter++) {
- byte[] currentKeyFrame = frames[iter].getKeyFrame();
- if(currentKeyFrame != lastKeyFrame) {
- lastKeyFrame = currentKeyFrame;
- currentKeyFrame = scaleArray(currentKeyFrame, width, height);
- lastKeyFrameAfterScale = currentKeyFrame;
- }
- result.frames[iter] = new Frame(frames[iter].getTime(), lastKeyFrameAfterScale, frames[iter], xRatio, yRatio, width, height);
- }
- return result;
- }
-
- /**
- * @inheritDoc
- */
- public boolean isAnimation() {
- return true;
- }
-
- /**
- * Used by the resource editor
- */
- boolean isKeyframe(int offset) {
- if(offset == 0) {
- return true;
- }
- if(offset == 1) {
- return frames[offset - 1].getKeyFrame() != imageDataByte;
- }
- return frames[offset - 1].getKeyFrame() != frames[offset - 2].getKeyFrame();
- }
-
- /**
- * Used by the resource editor
- */
- byte[] getKeyframe(int offset) {
- return frames[offset - 1].getKeyFrame();
- }
- /**
- * Used by the resource editor
- */
- boolean isDrawPrevious(int offset) {
- return frames[offset - 1].isDrawPrevious();
- }
-
- /**
- * Used by the resource editor
- */
- byte[][] getModifiedRows(int offset) {
- return frames[offset - 1].modifiedRows;
- }
-
- /**
- * Used by the resource editor
- */
- int[] getModifiedRowOffsets(int offset) {
- return frames[offset - 1].modifiedRowOffsets;
- }
-
- Rectangle getDirtyRegion(){
- int frame = currentFrame;
- if(frame == 0){
- return null;
- }
- if(frame == frames.length){
- frame = 0;
- }
- Rectangle rect = new Rectangle(0, frames[frame].smallestChangedRow, new Dimension(getWidth(), frames[frame].highestChangedRow -frames[frame].smallestChangedRow));
- return rect;
- }
-
- /**
- * Represents a frame within the animation that is not the first frame
- */
- static class Frame {
- /**
- * Offset since the beginning of the animation
- */
- private int time;
-
- private byte[] keyFrame;
-
- /**
- * Relevant only for standard frames, this represents the rows that
- * were modified for this specific frame
- */
- byte[][] modifiedRows;
- int[] modifiedRowOffsets;
- private boolean drawPrevious;
- int smallestChangedRow;
- int highestChangedRow;
-
-
- public Frame(int time, byte[] keyFrame, Vector rowNumbers, Vector rowValues, boolean drawPrevious) {
- this.time = time;
- this.keyFrame = keyFrame;
- this.drawPrevious = drawPrevious;
- initArrays(rowNumbers, rowValues);
- }
- private void initArrays(Vector rowNumbers, Vector rowValues) {
- modifiedRowOffsets = new int[rowNumbers.size()];
- modifiedRows = new byte[modifiedRowOffsets.length][];
- for(int iter = 0 ; iter < modifiedRowOffsets.length ; iter++) {
- modifiedRowOffsets[iter] = ((Integer)rowNumbers.elementAt(iter)).intValue();
- modifiedRows[iter] = (byte[])rowValues.elementAt(iter);
- }
- smallestChangedRow = modifiedRowOffsets[0];
- highestChangedRow = modifiedRowOffsets[0];
- for(int i=1;i<modifiedRowOffsets.length;i++){
- smallestChangedRow = Math.min(smallestChangedRow, modifiedRowOffsets[i]) ;
- highestChangedRow = Math.max(highestChangedRow, modifiedRowOffsets[i]) ;
- }
- }
-
- public Frame(int time, byte[] keyFrame) {
- this.time = time;
- this.keyFrame = keyFrame;
- modifiedRowOffsets = new int[0];
- }
-
- /**
- * This constructor is used for scaling the original frame according to the given ratios
- */
- public Frame(int time, byte[] keyFrame, Frame original, int xRatio, int yRatio, int width, int height) {
- this.time = time;
- this.keyFrame = keyFrame;
-
- // if the original was a keyframe then no work...
- if(original.modifiedRowOffsets.length == 0) {
- modifiedRowOffsets = original.modifiedRowOffsets;
- return;
- }
- Vector newRows = new Vector();
- Vector newValues = new Vector();
-
- int xPos = xRatio / 2;
- int yPos = yRatio / 2;
- for(int y = 0 ; y < height ; y++) {
- int srcY = yPos >> 16;
-
- // do we have the row at srcY???
- int rowAtY = -1;
- for(int iter = 0 ; iter < original.modifiedRowOffsets.length ; iter++) {
- if(original.modifiedRowOffsets[iter] == srcY) {
- rowAtY = iter;
- break;
- }
- }
- if(rowAtY != -1) {
- byte[] newRow = new byte[width];
- for (int x = 0; x < width; x++) {
- int srcX = xPos >> 16;
- newRow[x] = original.modifiedRows[rowAtY][srcX];
- xPos += xRatio;
- }
- newRows.addElement(new Integer(y));
- newValues.addElement(newRow);
- }
- yPos += yRatio;
- xPos = xRatio / 2;
- }
-
- initArrays(newRows, newValues);
- }
-
- public boolean isDrawPrevious() {
- return drawPrevious;
- }
-
- public int getTime() {
- return time;
- }
-
- private byte[] getModifiedRow(int row) {
- for(int iter = 0 ; iter < modifiedRowOffsets.length ; iter++) {
- if(modifiedRowOffsets[iter] == row) {
- return modifiedRows[iter];
- }
- }
- return null;
- }
-
- private byte[] getKeyFrame() {
- return keyFrame;
- }
-
- private void setKeyFrame(byte[] keyFrame) {
- this.keyFrame = keyFrame;
- }
- }
- }