/* * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are * met: * * - Redistribution of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistribution in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * Neither the name of Sun Microsystems, Inc. or the names of * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * This software is provided "AS IS," without a warranty of any kind. ALL * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, * INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A * PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN * MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR * ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR * ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR * DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE * DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, * ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, EVEN IF * SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. * * You acknowledge that this software is not designed or intended for use * in the design, construction, operation or maintenance of any nuclear * facility. * * Sun gratefully acknowledges that this software was originally authored * and developed by Kenneth Bradley Russell and Christopher John Kline. */ package demos.xtrans; import java.awt.*; import java.awt.geom.*; import java.util.*; import gleem.linalg.*; /** A basic transition manager supporting animated scrolling, rotating * and fading of components. * * @author Kenneth Russell */ public class XTBasicTransitionManager implements XTTransitionManager { /** Indicates the style of the transition (either no motion, scrolling, or rotating). */ public static class Style { private Style() {} } /** Indicates the component has no motion (scrolling or rotation) in its animation. */ public static Style STYLE_NO_MOTION = new Style(); /** Indicates the component is to be scrolled in to or out of place. */ public static Style STYLE_SCROLL = new Style(); /** Indicates the component is to be rotated in to or out of place. */ public static Style STYLE_ROTATE = new Style(); /** Indicates the direction of the transition if it contains any motion (either up, down, left, or right). */ public static class Direction { private Direction() {} } /** Indicates the component's animation is from or toward the left, depending on whether the transition is an "in" or "out" transition. */ public static Direction DIR_LEFT = new Direction(); /** Indicates the component's animation is from or toward the right, depending on whether the transition is an "in" or "out" transition. */ public static Direction DIR_RIGHT = new Direction(); /** Indicates the component's animation is in the upward direction. */ public static Direction DIR_UP = new Direction(); /** Indicates the component's animation is in the downward direction. */ public static Direction DIR_DOWN = new Direction(); private Style nextTransitionStyle; private Direction nextTransitionDirection; private boolean nextTransitionFade; private Random random; /** Sets the next transition to be used by this transition manager for either an "in" or an "out" transition. By default the transition manager selects random transitions from those available. */ public void setNextTransition(Style style, Direction direction, boolean fade) { if (style == null) { throw new IllegalArgumentException("Must supply a style"); } nextTransitionStyle = style; nextTransitionDirection = direction; nextTransitionFade = fade; } /** Creates an XTBasicTransition for the given component. By default this transition manager chooses a random transition from those available if one is not specified via {@link #setNextTransition setNextTransition}. */ public XTTransition createTransitionForComponent(Component c, boolean isAddition, Rectangle oglViewportOfDesktop, Point viewportOffsetFromOrigin, Rectangle2D oglTexCoordsOnBackBuffer) { if (nextTransitionStyle == null) { chooseRandomTransition(); } // Figure out the final positions of everything // Keep in mind that the Java2D origin is at the upper left and // the OpenGL origin is at the lower left Rectangle bounds = c.getBounds(); int x = bounds.x; int y = bounds.y; int w = bounds.width; int h = bounds.height; float tx = (float) oglTexCoordsOnBackBuffer.getX(); float ty = (float) oglTexCoordsOnBackBuffer.getY(); float tw = (float) oglTexCoordsOnBackBuffer.getWidth(); float th = (float) oglTexCoordsOnBackBuffer.getHeight(); float vx = oglViewportOfDesktop.x; float vy = oglViewportOfDesktop.y; float vw = oglViewportOfDesktop.width; float vh = oglViewportOfDesktop.height; Quad3f verts = new Quad3f(new Vec3f(0, 0, 0), new Vec3f(0, -h, 0), new Vec3f(w, -h, 0), new Vec3f(w, 0, 0)); Quad2f texcoords = new Quad2f(new Vec2f(tx, ty + th), new Vec2f(tx, ty), new Vec2f(tx + tw, ty), new Vec2f(tx + tw, ty + th)); XTBasicTransition trans = new XTBasicTransition(); Vec3f translation = new Vec3f(x - viewportOffsetFromOrigin.x, vh - y - viewportOffsetFromOrigin.y, 0); InterpolatedVec3f transInterp = new InterpolatedVec3f(); transInterp.setStart(translation); transInterp.setEnd(translation); InterpolatedQuad3f quadInterp = new InterpolatedQuad3f(); quadInterp.setStart(verts); quadInterp.setEnd(verts); InterpolatedQuad2f texInterp = new InterpolatedQuad2f(); texInterp.setStart(texcoords); texInterp.setEnd(texcoords); trans.setTranslation(transInterp); trans.setVertices(quadInterp); trans.setTexCoords(texInterp); // Now decide how we are going to handle this transition Style transitionStyle = nextTransitionStyle; Direction transitionDirection = nextTransitionDirection; boolean fade = nextTransitionFade; nextTransitionStyle = null; nextTransitionDirection = null; nextTransitionFade = false; int[] vtIdxs = null; int[] ttIdxs = null; Vec3f rotAxis = null; Vec3f pivot = null; float startAngle = 0; float endAngle = 0; if (fade) { InterpolatedFloat alpha = new InterpolatedFloat(); float start = (isAddition ? 0.0f : 1.0f); float end = (isAddition ? 1.0f : 0.0f); alpha.setStart(start); alpha.setEnd(end); trans.setAlpha(alpha); } if (transitionDirection != null) { if (transitionStyle == STYLE_SCROLL) { if (transitionDirection == DIR_LEFT) { vtIdxs = new int[] { 3, 2, 2, 3 }; ttIdxs = new int[] { 0, 1, 1, 0 }; } else if (transitionDirection == DIR_RIGHT) { vtIdxs = new int[] { 0, 1, 1, 0 }; ttIdxs = new int[] { 3, 2, 2, 3 }; } else if (transitionDirection == DIR_UP) { vtIdxs = new int[] { 1, 1, 2, 2 }; ttIdxs = new int[] { 0, 0, 3, 3 }; } else { // DIR_DOWN vtIdxs = new int[] { 0, 0, 3, 3 }; ttIdxs = new int[] { 1, 1, 2, 2 }; } } else if (transitionStyle == STYLE_ROTATE) { if (transitionDirection == DIR_LEFT) { rotAxis = new Vec3f(0, 1, 0); pivot = new Vec3f(); startAngle = -90; endAngle = 0; } else if (transitionDirection == DIR_RIGHT) { rotAxis = new Vec3f(0, 1, 0); pivot = new Vec3f(w, 0, 0); startAngle = 90; endAngle = 0; } else if (transitionDirection == DIR_UP) { rotAxis = new Vec3f(1, 0, 0); pivot = new Vec3f(0, -h, 0); startAngle = 90; endAngle = 0; } else { // DIR_DOWN rotAxis = new Vec3f(1, 0, 0); pivot = new Vec3f(); startAngle = -90; endAngle = 0; } } } /* switch (transitionType) { case FADE: { InterpolatedFloat alpha = new InterpolatedFloat(); float start = (isAddition ? 0.0f : 1.0f); float end = (isAddition ? 1.0f : 0.0f); alpha.setStart(start); alpha.setEnd(end); trans.setAlpha(alpha); break; } case SCROLL_LEFT: { vtIdxs = new int[] { 3, 2, 2, 3 }; ttIdxs = new int[] { 0, 1, 1, 0 }; break; } case SCROLL_RIGHT: { vtIdxs = new int[] { 0, 1, 1, 0 }; ttIdxs = new int[] { 3, 2, 2, 3 }; break; } case SCROLL_UP: { vtIdxs = new int[] { 1, 1, 2, 2 }; ttIdxs = new int[] { 0, 0, 3, 3 }; break; } case SCROLL_DOWN: { vtIdxs = new int[] { 0, 0, 3, 3 }; ttIdxs = new int[] { 1, 1, 2, 2 }; break; } case ROTATE_LEFT: { rotAxis = new Vec3f(0, 1, 0); pivot = new Vec3f(); startAngle = -90; endAngle = 0; break; } case ROTATE_RIGHT: { rotAxis = new Vec3f(0, 1, 0); // pivot = translation.plus(new Vec3f(w, 0, 0)); pivot = new Vec3f(w, 0, 0); startAngle = 90; endAngle = 0; break; } case ROTATE_UP: { rotAxis = new Vec3f(1, 0, 0); // pivot = translation.plus(new Vec3f(0, -h, 0)); pivot = new Vec3f(0, -h, 0); startAngle = 90; endAngle = 0; break; } case ROTATE_DOWN: { rotAxis = new Vec3f(1, 0, 0); pivot = new Vec3f(); startAngle = -90; endAngle = 0; break; } } */ if (vtIdxs != null) { if (isAddition) { quadInterp.setStart(new Quad3f(verts.getVec(vtIdxs[0]), verts.getVec(vtIdxs[1]), verts.getVec(vtIdxs[2]), verts.getVec(vtIdxs[3]))); texInterp.setStart(new Quad2f(texcoords.getVec(ttIdxs[0]), texcoords.getVec(ttIdxs[1]), texcoords.getVec(ttIdxs[2]), texcoords.getVec(ttIdxs[3]))); } else { // Note: swapping the vertex and texture indices happens to // have the correct effect int[] tmp = vtIdxs; vtIdxs = ttIdxs; ttIdxs = tmp; quadInterp.setEnd(new Quad3f(verts.getVec(vtIdxs[0]), verts.getVec(vtIdxs[1]), verts.getVec(vtIdxs[2]), verts.getVec(vtIdxs[3]))); texInterp.setEnd(new Quad2f(texcoords.getVec(ttIdxs[0]), texcoords.getVec(ttIdxs[1]), texcoords.getVec(ttIdxs[2]), texcoords.getVec(ttIdxs[3]))); } } else if (rotAxis != null) { if (!isAddition) { float tmp = endAngle; endAngle = -startAngle; startAngle = tmp; } trans.setPivotPoint(pivot); trans.setRotationAxis(rotAxis); InterpolatedFloat rotInterp = new InterpolatedFloat(); rotInterp.setStart(startAngle); rotInterp.setEnd(endAngle); trans.setRotationAngle(rotInterp); } return trans; } /** Chooses a random transition from those available. */ protected void chooseRandomTransition() { if (random == null) { random = new Random(); } nextTransitionFade = random.nextBoolean(); nextTransitionStyle = null; do { int style = random.nextInt(3); switch (style) { // Make no-motion transitions always use fades for effect // without biasing transitions toward no-motion transitions case 0: if (nextTransitionFade) nextTransitionStyle = STYLE_NO_MOTION; break; case 1: nextTransitionStyle = STYLE_SCROLL; break; default: nextTransitionStyle = STYLE_ROTATE; break; } } while (nextTransitionStyle == null); int dir = random.nextInt(4); switch (dir) { case 0: nextTransitionDirection = DIR_LEFT; break; case 1: nextTransitionDirection = DIR_RIGHT; break; case 2: nextTransitionDirection = DIR_UP; break; default: nextTransitionDirection = DIR_DOWN; break; } } }