/* * Copyright 2007 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: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions 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 nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /** * A demonstration of some Scenario features. * Juggler.gif was provided by duke project ( https://duke.dev.java.net/ ) * audio clips were provided by jdk's Animator demo. * * @author Igor Kushnriskiy */ package demo.movie; import java.applet.Applet; import java.applet.AudioClip; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Font; import java.awt.Graphics2D; import java.awt.GraphicsEnvironment; import java.awt.Image; import java.awt.Paint; import java.awt.RadialGradientPaint; import java.awt.RenderingHints; import java.awt.Shape; import java.awt.Transparency; import java.awt.geom.Arc2D; import java.awt.geom.Ellipse2D; import java.awt.geom.Line2D; import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.BufferedImage; import java.io.IOException; import java.net.URL; import java.util.Random; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import javax.imageio.ImageIO; import javax.swing.JFrame; import javax.swing.SwingUtilities; import com.sun.scenario.animation.Clip; import com.sun.scenario.animation.Timeline; import com.sun.scenario.animation.TimingTargetAdapter; import com.sun.scenario.animation.Clip.RepeatBehavior; import com.sun.scenario.scenegraph.JSGPanel; import com.sun.scenario.scenegraph.SGClip; import com.sun.scenario.scenegraph.SGGroup; import com.sun.scenario.scenegraph.SGImage; import com.sun.scenario.scenegraph.SGNode; import com.sun.scenario.scenegraph.SGShape; import com.sun.scenario.scenegraph.SGText; import com.sun.scenario.scenegraph.SGTransform; public class Movie { public static void main(String[] args) { SwingUtilities.invokeLater( new Runnable() { public void run() { createAndShowGUI(); } }); } private static JFrame frame; private static Movie movie = null; static void createAndShowGUI() { frame = new JFrame("Film Countdown"); frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); restart(); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } static void restart() { if (movie != null) { movie.getTimeline().stop(); frame.remove(movie.getPanel()); movie = null; } movie = new Movie(); frame.add(movie.getPanel()); movie.getTimeline().start(); } private final JSGPanel panel; private final Timeline timeline = new Timeline(); private final int R = 300; private final int COUNT_DOWN_START = 9; Movie() { panel = new JSGPanel(); panel.setBackground(Color.LIGHT_GRAY); SGGroup scene = new SGGroup(); SGNode countDownNode = createCountDown(); scene.add(createOldFilmEffect(countDownNode)); panel.setScene(scene); } JSGPanel getPanel() { return panel; } Timeline getTimeline() { return timeline; } SGNode createOldFilmEffect(SGNode node) { final Random random = new Random(); SGGroup scene = new SGGroup(); scene.add(node); final Rectangle2D bounds = scene.getBounds(); final SGTransform.Translate sgTranslate = SGTransform.createTranslation(0, 0, scene); final SGShape particles[] = new SGShape[20]; for (int i = 0; i < particles.length; i++) { particles[i] = createStroke( new Line2D.Float(0, 0, 0, 0), 2, Color.BLACK); particles[i].setVisible(false); scene.add(particles[i]); } Clip clip = Clip.create(Clip.INDEFINITE, new TimingTargetAdapter() { // clip.setResolution does not seem to work // will handle resolution here private final long PERIOD = TimeUnit.MILLISECONDS.toNanos(1000 / 25); private long lastShakeTime = Long.MIN_VALUE; @Override public void timingEvent(float fraction) { long now = System.nanoTime(); if (lastShakeTime == Long.MIN_VALUE) { lastShakeTime = now; } if (now - lastShakeTime > PERIOD) { //do shaking sgTranslate.setTranslation( 3 * (random.nextFloat() - .5f), 3 * (random.nextFloat() - .5f)); //update particles for (SGShape particle : particles) { if (random.nextInt(10) == 0) { particle.setVisible(false); } else { if (! particle.isVisible()) { Line2D line = (Line2D) particle.getShape(); double x1 = random.nextInt(( int) bounds.getWidth()); double y1 = random.nextInt( (int) bounds.getHeight()); double xDelta = random.nextInt(10) - 5; double yDelta = random.nextInt(10) - 5; line.setLine(x1, y1, x1 + xDelta, y1 + yDelta); particle.setShape(line); particle.setVisible(true); } } } lastShakeTime = now; } } }); timeline.schedule(clip); return sgTranslate; } private SGNode createCountDown() { SGGroup scene = new SGGroup(); //first layer: animated fill final SGGroup layer1 = new SGGroup(); SGShape sgFill = new SGShape(); sgFill.setShape(new Rectangle2D.Float(0f, 0f, 2f * R, 2f * R)); sgFill.setMode(SGShape.Mode.FILL); sgFill.setFillPaint(new RadialGradientPaint(R, R, 3 * R, new float[]{0, 1}, new Color[]{Color.GRAY, Color.BLACK})); final SGClip sgClip = new SGClip(); sgClip.setAntialiased(true); sgClip.setChild(sgFill); final Arc2D.Float arc2D = new Arc2D.Float(R - 2 * R, R - 2 * R, 4 * R, 4 * R, 90, 0, Arc2D.PIE); layer1.add(sgClip); scene.add(layer1); //second layer: vertical and horizontal lines final SGGroup layer2 = new SGGroup(); layer2.add( createStroke(new Line2D.Float(0, R, 2 * R, R), 2f, Color.BLACK)); layer2.add( createStroke(new Line2D.Float(R, 0, R, 2 * R), 2f, Color.BLACK)); scene.add(layer2); //third layer: two circles and animated number final SGGroup layer3 = new SGGroup(); layer3.add(createStroke( createCircle(R, R, R - 5), 2f, Color.WHITE)); layer3.add(createStroke( createCircle(R, R, R - 15), 2f, Color.WHITE)); final SGText sgText = new SGText(); sgText.setVerticalAlignment(SGText.VAlign.TOP); sgText.setFont(new Font("SansSerif", Font.PLAIN, 2 * R)); sgText.setAntialiasingHint(RenderingHints.VALUE_TEXT_ANTIALIAS_ON); sgText.setFillPaint(Color.BLACK); final AtomicInteger countDownValue = new AtomicInteger(COUNT_DOWN_START); sgText.setText(Integer.toString(countDownValue.get())); Rectangle2D textBounds = sgText.getBounds(); sgText.setLocation(new Point2D.Double( R - textBounds.getX() - textBounds.getWidth() / 2, R - textBounds.getY() - textBounds.getHeight() / 2)); layer3.add(sgText); scene.add(layer3); //forth layer: animated image SGGroup layer4 = new SGGroup(); Image image = readImage("resources/Juggler.gif"); SGImage sgImage = new SGImage(); sgImage.setImage(image); final SGTransform.Scale sgScale = SGTransform.createScale(.0001f, .0001f, sgImage); sgScale.setVisible(false); final SGTransform.Translate sgTranslate = SGTransform.createTranslation(0, 0, sgScale); layer4.add(sgTranslate); scene.add(layer4); Clip countDownClip = Clip.create(1000, new TimingTargetAdapter() { private float oldFraction = 0; private final AudioClip[] audioClips = loadAudio(); @Override public void begin() { audioClips[0].play(); } @Override public void timingEvent(float fraction) { arc2D.setAngleExtent(-360 * fraction); sgClip.setShape(arc2D); if (oldFraction > fraction) { //new loop sgText.setText( Integer.toString(countDownValue.decrementAndGet())); audioClips[countDownValue.get()].play(); } oldFraction = fraction; } private AudioClip[] loadAudio() { AudioClip[] audioClips = new AudioClip[10]; for (int i = 0; i < audioClips.length; i++) { URL url = this.getClass() .getResource("resources/" + Integer.toString(i) + ".au"); audioClips[i] = Applet.newAudioClip(url); } return audioClips; } }); countDownClip.setRepeatBehavior(RepeatBehavior.LOOP); countDownClip.setRepeatCount(countDownValue.get()); timeline.schedule(countDownClip); Clip dukeClip = Clip.create(2000, new TimingTargetAdapter() { @Override public void timingEvent(float fraction) { fraction = Math.max(fraction, .0001f); sgScale.setScale(fraction, fraction); sgScale.setVisible(true); Rectangle2D rect = sgScale.getBounds(); sgTranslate.setTranslation( R - rect.getWidth() / 2, R - rect.getHeight() / 2); } @Override public void end() { //hide every layer except the last one layer1.setVisible(false); layer2.setVisible(false); layer3.setVisible(false); } }); countDownClip.addEndAnimation(dukeClip); Clip restartClip = Clip.create(5000, new TimingTargetAdapter() { @Override public void end() { Movie.restart(); } }); dukeClip.addEndAnimation(restartClip); return scene; } private static SGShape createStroke(Shape shape, float width, Paint drawPaint) { SGShape sgShape = new SGShape(); sgShape.setShape(shape); sgShape.setAntialiasingHint(RenderingHints.VALUE_ANTIALIAS_ON); sgShape.setDrawPaint(drawPaint); sgShape.setMode(SGShape.Mode.STROKE); sgShape.setDrawStroke( new BasicStroke(width, BasicStroke.CAP_ROUND, BasicStroke.JOIN_MITER)); return sgShape; } private static Shape createCircle(float x, float y, float r) { return new Ellipse2D.Float(x - r, y - r, 2 * r, 2 * r); } private Image readImage(String name) { BufferedImage image = null; Image rv = null; try { image = ImageIO.read(getClass().getResource(name)); } catch (IOException e) { } if (image != null) { BufferedImage cimg = GraphicsEnvironment.getLocalGraphicsEnvironment() .getDefaultScreenDevice().getDefaultConfiguration() .createCompatibleImage(image.getWidth(), image.getHeight(), Transparency.TRANSLUCENT); Graphics2D g2d = cimg.createGraphics(); g2d.drawImage(image, null, 0, 0); g2d.dispose(); rv = cimg; } return rv; } }