/* * Copyright 2015 Daniel Dittmar * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ package dan.dit.whatsthat.util.flatworld.look; import android.graphics.Bitmap; import android.graphics.Canvas; import android.graphics.Paint; import android.graphics.PorterDuff; import android.graphics.PorterDuffXfermode; import android.util.Log; import dan.dit.whatsthat.util.general.MathFunction; /** * Created by daniel on 26.06.15. */ public class Frames extends Look { private Bitmap[] mFrames; int mFrameIndex; private long mFrameCounter; private long mFrameDuration; private long[] mFrameDurations; private boolean mBlendFrames; private Paint mBlendPaint; private MathFunction mBlendFunction; public Frames(Bitmap[] frames, long frameDuration) { mFrames = frames; mFrameCounter = 0; mFrameIndex = 0; mFrameDuration = frameDuration; if (mFrames == null || mFrames.length == 0) { throw new IllegalArgumentException("No frames given."); } if (frames.length > 1 && mFrameDuration <= 0L) { Log.e("Riddle", "Illegal frame duration set to 1000ms " + mFrameDuration); mFrameDuration = 1000L; } } public Frames(Frames toCopy) { mFrames = new Bitmap[toCopy.mFrames.length]; System.arraycopy(toCopy.mFrames, 0, mFrames, 0, mFrames.length); mFrameDurations = toCopy.mFrameDurations != null ? new long[toCopy.mFrameDurations .length] : null; if (toCopy.mFrameDurations != null) { System.arraycopy(toCopy.mFrameDurations, 0, mFrameDurations, 0, mFrameDurations.length); } mFrameCounter = 0; mFrameIndex = 0; mFrameDuration = toCopy.mFrameDuration; if (toCopy.mBlendFrames && toCopy.mBlendPaint != null) { mBlendPaint = new Paint(toCopy.mBlendPaint); mBlendFrames = true; mBlendFunction = toCopy.mBlendFunction; } } public static final int BLEND_MODE_LINEAR = 0; public static final int BLEND_MODE_QUADRATIC = 1; public Frames setBlendFrames(boolean blendFrames, int blendInterpolation) { mBlendFrames = blendFrames; if (mBlendFrames) { if (blendInterpolation == BLEND_MODE_LINEAR) { mBlendFunction = new MathFunction.LinearInterpolation(0., 255, 1.0, 0.); } else { mBlendFunction = new MathFunction.QuadraticInterpolation(0., 255., 1.0, 0.); } if (mBlendPaint == null) { mBlendPaint = new Paint(); mBlendPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.ADD)); } } else { mBlendPaint = null; mBlendFunction = null; } return this; } @Override public int getWidth() { return mFrames[0].getWidth(); } public Frames setFrameDuration(int index, long duration) { if (mFrameDurations == null) { mFrameDurations = new long[mFrames.length]; } mFrameDurations[index] = duration <= 0L ? 0L : duration; return this; } @Override public int getHeight() { return mFrames[0].getHeight(); } public int getCount() { return mFrames.length; } @Override public boolean update(long updatePeriod) { if (mFrames.length > 1) { mFrameCounter += updatePeriod; long frameDuration = getCurrentFrameDuration(); if (mFrameCounter > frameDuration) { mFrameCounter -= frameDuration; mFrameIndex++; mFrameIndex %= mFrames.length; return true; } } return false; } protected boolean performBlending(int frameIndex) { return mBlendFrames && mFrames.length > 1; } private long getCurrentFrameDuration() { if (mFrameDurations == null) { return mFrameDuration; } long duration = mFrameDurations[mFrameIndex]; if (duration <= 0L) { return mFrameDuration; } return duration; } @Override public void draw(Canvas canvas, float x, float y, Paint paint) { if (mVisible) { int oldAlpha = 255; boolean performBlending = performBlending(mFrameIndex); int blendingAlpha = 255; Bitmap currFrame = mFrames[mFrameIndex]; if (performBlending) { // there is another bitmap and we want to blend to it, depending on time left // till its visible paint = mBlendPaint; oldAlpha = paint.getAlpha(); blendingAlpha = (int) (mBlendFunction.evaluate(Math.min(mFrameCounter / (double) getCurrentFrameDuration(), 1.))); paint.setAlpha(blendingAlpha); } boolean currentDrawn = false; if (currFrame != null && (!performBlending || blendingAlpha < 128)) { currentDrawn = true; canvas.drawBitmap(currFrame, x - currFrame.getWidth() + getWidth() + mOffsetX, y - currFrame.getHeight() + getHeight() + mOffsetY, paint); } if (performBlending) { Bitmap nextFrame = mFrames[(mFrameIndex + 1) % mFrames.length]; if (nextFrame != null) { paint.setAlpha(255 - blendingAlpha); canvas.drawBitmap(nextFrame, x - nextFrame.getWidth() + getWidth() + mOffsetX, y - nextFrame.getHeight() + getHeight() + mOffsetY, paint); if (!currentDrawn && currFrame != null) { paint.setAlpha(blendingAlpha); canvas.drawBitmap(currFrame, x - currFrame.getWidth() + getWidth() + mOffsetX, y - currFrame.getHeight() + getHeight() + mOffsetY, paint); } } paint.setAlpha(oldAlpha); } } } @Override public void reset() { mFrameIndex = 0; mFrameCounter = 0L; } public Bitmap[] getFrames() { return mFrames; } }