/******************************************************************************* * Copyright (c) 2010 Ahmed Mahran and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Ahmed Mahran - initial API and implementation *******************************************************************************/ package org.eclipse.nebula.effects.stw.transitions; import org.eclipse.nebula.effects.stw.Transition; import org.eclipse.nebula.effects.stw.TransitionManager; import org.eclipse.swt.graphics.GC; import org.eclipse.swt.graphics.Image; import org.eclipse.swt.graphics.ImageData; /** * A cubic rotation effect. Showing two sides of a cube, the cube rotates from one * side to the other side. * * @author Ahmed Mahran (ahmahran@gmail.com) */ public class CubicRotationTransition extends Transition { private int _w, _halfW, _h, _halfH; private double _a1, _a2, _x, _y, _x0, _y0, _v0; private boolean _flag1; private ImageData _fromData; private ImageData _toData; private ImageData _imgDataBuffer; private ImageData _imgDataToDraw; private Image _bgImage; private long _halfT, _t1, _tSqrd; private double _dy1, _dx1, _dx2, _dy2 , _x1, _y1, _x2, _y2 , _destHeight, _destWidth , _destHeight0, _destWidth0 , _destHeightV0, _destWidthV0 , _ratio1, _ratio2 , _remainedSize; private double _quality = 100;//% /** * This constructor creates a CubicRotationTransition with number of frames per second of {@link Transition#DEFAULT_FPS} * and total transition time of {@link Transition#DEFAULT_T} milliseconds. It is similar to * new CubicRotationTransition(transitionManager, {@link Transition#DEFAULT_FPS}, {@link Transition#DEFAULT_T}) * * @param transitionManager the transition manager to be used to manage transitions */ public CubicRotationTransition(TransitionManager transitionManager) { this(transitionManager, DEFAULT_FPS, DEFAULT_T); } /** * This constructor creates a CubicRotationTransition with number of frames per second of <code>fps</code> * and total transition time of <code>T</code> milliseconds. * * @param transitionManager the transition manager to be used to manage transitions * @param fps number of frames per second * @param T the total time the transition effect will take in milliseconds */ public CubicRotationTransition(TransitionManager transitionManager, long fps, long T) { super(transitionManager, fps, T); } @Override protected void initTransition(Image from, Image to, GC gc, double direction) { _halfT = (long) (_T / 2.0); _fromData = from.getImageData(); _toData = to.getImageData(); _w = _fromData.width; _h = _fromData.height; _halfW = (int) (_w / 2.0); _halfH = (int) (_h / 2.0); switch((int)direction) { case (int)DIR_RIGHT: _a1 = _w / (double)(_halfT * _halfT); _a2 = _h / (double)(_halfT * _halfT); _x = 0; _destHeight = 0; _dx1 = _dx2 = _w - _quality * (_w - 1) / 100.0; _remainedSize = _w - ((int)(_w / _dx1) * _dx1); break; case (int)DIR_LEFT: _a1 = _w / (double)(_halfT * _halfT); _a2 = _h / (double)(_halfT * _halfT); _x = _w; _destHeight = _h; _dx1 = _dx2 = _w - _quality * (_w - 1) / 100.0; _remainedSize = _w - ((int)(_w / _dx1) * _dx1); break; case (int)DIR_UP: _a1 = _h / (double)(_halfT * _halfT); _a2 = _w / (double)(_halfT * _halfT); _y = _h; _destWidth = _w; _dy1 = _dy2 = _h - _quality * (_h - 1) / 100.0; _remainedSize = _h - ((int)(_h / _dy1) * _dy1); break; case (int)DIR_DOWN: _a1 = _h / (double)(_halfT * _halfT); _a2 = _w / (double)(_halfT * _halfT); _y = 0; _destWidth = 0; _dy1 = _dy2 = _h - _quality * (_h - 1) / 100.0; _remainedSize = _h - ((int)(_h / _dy1) * _dy1); break; } _flag1 = false; if (useDataBuffersToDraw()) { initImgDataBuffers(gc, direction); } } /** * Initialize the image data buffers, used to draw the transition * instead of drawing into the graphics context object directly. * @param gc Graphics context where to initialize the background image object. * @param direction Direction to be used as a reference to * initialize the image data buffers. */ private void initImgDataBuffers(GC gc, double direction) { switch((int)direction) { case (int)DIR_RIGHT: case (int)DIR_LEFT: _imgDataBuffer = new ImageData((int) _dx1, _h, _fromData.depth, _fromData.palette); break; case (int)DIR_UP: case (int)DIR_DOWN: _imgDataBuffer = new ImageData(_w, (int) _dy1, _fromData.depth, _fromData.palette); break; } _bgImage = new Image(gc.getDevice(), _w, _h); } /** * @return true if the application will use the data buffers * to draw the image, false if the buffers won't be used and the * image will be drawn directly to the graphics context * object instead. */ private boolean useDataBuffersToDraw() { return IS_MAC_OS; } /** * Draw an image to a graphics context object. The image * can be drawn using image data buffers before drawing to the * graphics context object, or drawn directly to the * graphics context object. * @param gc Graphics context object to draw the image to. * @param src the source image. * @param srcData image data of the source image. * @param srcX the x coordinate in the source image to copy from * @param srcY the y coordinate in the source image to copy from * @param srcWidth the width in pixels to copy from the source * @param srcHeight the height in pixels to copy from the source * @param destX the x coordinate in the destination to copy to * @param destY the y coordinate in the destination to copy to * @param destWidth the width in pixels of the destination rectangle * @param destHeight the height in pixels of the destination rectangle */ private void drawImage(GC gc, Image src, ImageData srcData, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight) { if (useDataBuffersToDraw()) { drawImageData(srcData, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight); } else { gc.drawImage(src, srcX, srcY, srcWidth, srcHeight, destX, destY, destWidth, destHeight); } } /** * Draw an image to the image data buffer object that contains all * the image data to be drawn to the graphics context object. * @param srcData image data of the source image. * @param srcX the x coordinate in the source image to copy from * @param srcY the y coordinate in the source image to copy from * @param srcWidth the width in pixels to copy from the source * @param srcHeight the height in pixels to copy from the source * @param destX the x coordinate in the destination to copy to * @param destY the y coordinate in the destination to copy to * @param destWidth the width in pixels of the destination rectangle * @param destHeight the height in pixels of the destination rectangle */ private void drawImageData(ImageData srcData, int srcX, int srcY, int srcWidth, int srcHeight, int destX, int destY, int destWidth, int destHeight) { if (srcWidth == 0 || srcHeight == 0 || destWidth == 0 || destHeight == 0) { return; } if (srcX == srcData.width) { srcX--; } if (srcY == srcData.height) { srcY--; } if (destX == _imgDataToDraw.width) { destX--; } if (destY == _imgDataToDraw.height) { destY--; } if ((srcX + srcWidth) > srcData.width || (srcY + srcHeight) > srcData.height || (destX + destWidth) > _imgDataToDraw.width || (destY + destHeight) > _imgDataToDraw.height) { return; } for (int y = 0; y < srcHeight; y++) { for (int x = 0; x < srcWidth; x++) { _imgDataBuffer.setPixel(x, y, srcData.getPixel(srcX + x, srcY + y)); } } ImageData scaledDataBuffer = _imgDataBuffer.scaledTo(destWidth, destHeight); for (int y = 0; y < destHeight; y++) { for (int x = 0; x < destWidth; x++) { _imgDataToDraw.setPixel(destX + x, destY + y, scaledDataBuffer.getPixel(x, y)); } } } @Override protected void stepTransition(long t, Image from, Image to, GC gc, double direction) { if (useDataBuffersToDraw()) { gc.copyArea(_bgImage, 0, 0); _imgDataToDraw = _bgImage.getImageData(); } switch((int)direction) { case (int)DIR_RIGHT: _ratio1 = (_w - _x) / _w; _ratio2 = (_x) / _w; _dy1 = _dx1 * (_destHeight) / (2.0 * _w); _dy2 = _dx2 * (_h - _destHeight) / (2.0 * _w); _x1 = 0; _y1 = 0; _x2 = 0; _y2 = (_h - _destHeight) / 2.0; for (; _x1 < _w; _x1 += _dx1) { try { _x2 = _x1; drawImage(gc, from, _fromData, (int) _x1, 0, (int) _dx1, _h, (int) (_x + _x1 * _ratio1), (int) _y1, (int) _dx1, (int) (_h - _y1 - _y1)); drawImage(gc, to, _toData, (int) _x2, 0, (int) _dx2, _h, (int) (_x2 * _ratio2), (int) _y2 , (int) _dx2, (int) (_h - _y2 - _y2)); _y1 += _dy1; _y2 -= _dy2; } catch (Exception e) { drawImage(gc, from, _fromData, (int) _x1, 0, (int) _remainedSize, _h, (int) (_x + _x1 * _ratio1), (int) _y1 , (int) _remainedSize, (int) (_h - _y1 - _y1)); drawImage(gc, to, _toData, (int) _x2, 0, (int) _remainedSize, _h, (int) (_x2 * _ratio2), (int) _y2 , (int) _remainedSize, (int) (_h - _y2 - _y2)); } } if( t <= _halfT ) { _tSqrd = t * t; _x = Math.min(0.5 * _a1 * _tSqrd, _halfW); _destHeight = Math.min(0.5 * _a2 * _tSqrd, _halfH); } else { if(!_flag1) { _x0 = _x; _destHeight0 = _destHeight; _v0 = _a1 * t; _destHeightV0 = _a2 * t; _a1 *= -1.0; _a2 *= -1.0; _flag1 = true; } _t1 = t - _halfT; _tSqrd = _t1 * _t1; _x = Math.min(_x0 + _v0 * _t1 + 0.5 * _a1 * _tSqrd, _w); _destHeight = Math.min(_destHeight0 + _destHeightV0 * _t1 + 0.5 * _a2 * _tSqrd, _h); } break; case (int)DIR_LEFT: _ratio1 = (_x) / _w; _ratio2 = (_w - _x) / _w; _dy1 = _dx1 * (_h - _destHeight) / (2.0 * _w); _dy2 = _dx2 * (_destHeight) / (2.0 * _w); _x1 = 0; _y1 = (_h - _destHeight) / 2.0; _x2 = 0; _y2 = 0; for (; _x1 < _w; _x1 += _dx1) { try { drawImage(gc, from, _fromData, (int) _x1, 0, (int) _dx1, _h, (int) (_x1 * _ratio1), (int) _y1 , (int) _dx1, (int) (_h - _y1 - _y1)); _y1 -= _dy1; } catch (Exception e) { drawImage(gc, from, _fromData, (int) _x1, 0, (int) _remainedSize, _h, (int) (_x1 * _ratio1), (int) _y1 , (int) _remainedSize, (int) (_h - _y1 - _y1)); } } for (; _x2 < _w; _x2 += _dx2) { try { drawImage(gc, to, _toData, (int) _x2, 0, (int) _dx2, _h, (int) (_x + _x2 * _ratio2), (int) _y2 , (int) _dx2, (int) (_h - _y2 - _y2)); _y2 += _dy2; } catch (Exception e) { drawImage(gc, to, _toData, (int) _x2, 0, (int) _remainedSize, _h, (int) (_x + _x2 * _ratio2), (int) _y2 , (int) _remainedSize, (int) (_h - _y2 - _y2)); } } if( t <= _halfT ) { _tSqrd = t * t; _x = _w - Math.min(0.5 * _a1 * _tSqrd, _halfW); _destHeight = _h - Math.min(0.5 * _a2 * _tSqrd, _halfH); } else { if(!_flag1) { _x0 = _w - _x; _destHeight0 = _h - _destHeight; _v0 = _a1 * t; _destHeightV0 = _a2 * t; _a1 *= -1.0; _a2 *= -1.0; _flag1 = true; } _t1 = t - _halfT; _tSqrd = _t1 * _t1; _x = _w - Math.min(_x0 + _v0 * _t1 + 0.5 * _a1 * _tSqrd, _w); _destHeight = _h - Math.min(_destHeight0 + _destHeightV0 * _t1 + 0.5 * _a2 * _tSqrd, _h); } break; case (int)DIR_UP: _ratio1 = (_y) / _h; _ratio2 = (_h - _y) / _h; _dx1 = _dy1 * (_w - _destWidth) / (2.0 * _h); _dx2 = _dy2 * (_destWidth) / (2.0 * _h); _y1 = 0; _x1 = (_w - _destWidth) / 2.0; _y2 = 0; _x2 = 0; for (; _y1 < _h; _y1 += _dy1) { try { drawImage(gc, from, _fromData, 0, (int) _y1, _w, (int) _dy1 , (int) _x1, (int) (_y1 * _ratio1) , (int) (_w - _x1 - _x1), (int) _dy1); _x1 -= _dx1; } catch (Exception e) { drawImage(gc, from, _fromData, 0, (int) _y1, _w, (int) _remainedSize , (int) _x1, (int) (_y1 * _ratio1) , (int) (_w - _x1 - _x1), (int) _remainedSize); } } for (; _y2 < _h; _y2 += _dy2) { try { drawImage(gc, to, _toData, 0, (int) _y2, _w, (int) _dy2 , (int) _x2, (int) (_y + _y2 * _ratio2) , (int) (_w - _x2 - _x2), (int) _dy2); _x2 += _dx2; } catch (Exception e) { drawImage(gc, to, _toData, 0, (int) _y2, _w, (int) _remainedSize , (int) _x2, (int) (_y + _y2 * _ratio2) , (int) (_w - _x2 - _x2), (int) _remainedSize); } } if( t <= _halfT ) { _tSqrd = t * t; _y = _h - Math.min(0.5 * _a1 * _tSqrd, _halfH); _destWidth = _w - Math.min(0.5 * _a2 * _tSqrd, _halfW); } else { if(!_flag1) { _y0 = _h - _y; _destWidth0 = _w - _destWidth; _v0 = _a1 * t; _destWidthV0 = _a2 * t; _a1 *= -1.0; _a2 *= -1.0; _flag1 = true; } _t1 = t - _halfT; _tSqrd = _t1 * _t1; _y = _h - Math.min(_y0 + _v0 * _t1 + 0.5 * _a1 * _tSqrd, _h); _destWidth = _w - Math.min(_destWidth0 + _destWidthV0 * _t1 + 0.5 * _a2 * _tSqrd, _w); } break; case (int)DIR_DOWN: _ratio1 = (_h - _y) / _h; _ratio2 = (_y) / _h; _dx1 = _dy1 * (_destWidth) / (2.0 * _h); _dx2 = _dy2 * (_w - _destWidth) / (2.0 * _h); _y1 = 0; _x1 = 0; _y2 = 0; _x2 = (_w - _destWidth) / 2.0; for (; _y1 < _h; _y1 += _dy1) { try { _y2 = _y1; drawImage(gc, from, _fromData, 0, (int) _y1, _w, (int) _dy1 , (int) _x1, (int) (_y + _y1 * _ratio1) , (int) (_w - _x1 - _x1), (int) _dy1); drawImage(gc, to, _toData, 0, (int) _y2, _w, (int) _dy2 , (int) _x2, (int) (_y2 * _ratio2) , (int) (_w - _x2 - _x2), (int) _dy2); _x1 += _dx1; _x2 -= _dx2; } catch (Exception e) { drawImage(gc, from, _fromData, 0, (int) _y1, _w, (int) _remainedSize , (int) _x1, (int) (_y + _y1 * _ratio1) , (int) (_w - _x1 - _x1), (int) _remainedSize); drawImage(gc, to, _toData, 0, (int) _y2, _w, (int) _remainedSize , (int) _x2, (int) (_y2 * _ratio2) , (int) (_w - _x2 - _x2), (int) _remainedSize); } } if( t <= _halfT ) { _tSqrd = t * t; _y = Math.min(0.5 * _a1 * _tSqrd, _halfH); _destWidth = Math.min(0.5 * _a2 * _tSqrd, _halfW); } else { if(!_flag1) { _y0 = _y; _destWidth0 = _destWidth; _v0 = _a1 * t; _destWidthV0 = _a2 * t; _a1 *= -1.0; _a2 *= -1.0; _flag1 = true; } _t1 = t - _halfT; _tSqrd = _t1 * _t1; _y = Math.min(_y0 + _v0 * _t1 + 0.5 * _a1 * _tSqrd, _h); _destWidth = Math.min(_destWidth0 + _destWidthV0 * _t1 + 0.5 * _a2 * _tSqrd, _w); } break; } if (useDataBuffersToDraw()) { Image buffer = new Image(gc.getDevice(), _imgDataToDraw); gc.drawImage(buffer, 0, 0); buffer.dispose(); } } @Override protected void endTransition(Image from, Image to, GC gc, double direction) { if (_bgImage != null && !_bgImage.isDisposed()) { _bgImage.dispose(); } } /** * Sets the quality of image slicing as a percentage in * the interval from 0 to 100 inclusive * * @param quality is a percentage from 0 to 100 inclusive */ public void setQuality(double quality) { if(quality >= 0.0 && quality <= 100.0) _quality = quality; } /** * Returns a percentage representing the quality of image slicing * @return a percentage representing the quality of image slicing */ public double getQuality() { return _quality; } }