| /* |
| * |
| * Copyright (c) 2007, 2011, Oracle and/or its affiliates. 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 Oracle 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. |
| */ |
| package java2d.demos.Mix; |
| |
| |
| import static java.awt.Color.BLUE; |
| import static java.awt.Color.GREEN; |
| import static java.awt.Color.ORANGE; |
| import static java.awt.Color.RED; |
| import static java.awt.Color.WHITE; |
| import static java.awt.Color.YELLOW; |
| import static java.lang.Math.random; |
| import static java.lang.Math.sqrt; |
| import java.awt.Color; |
| import java.awt.Component; |
| import java.awt.Dimension; |
| import java.awt.Graphics2D; |
| import java.awt.event.ActionEvent; |
| import java.awt.event.ActionListener; |
| import java.awt.image.BufferedImage; |
| import java.awt.image.DataBufferByte; |
| import java.awt.image.IndexColorModel; |
| import java.awt.image.Raster; |
| import java.awt.image.WritableRaster; |
| import java2d.AnimatingControlsSurface; |
| import java2d.CustomControls; |
| import javax.swing.AbstractButton; |
| import javax.swing.JComboBox; |
| import javax.swing.JToggleButton; |
| import javax.swing.JToolBar; |
| |
| |
| /** |
| * Animated color bouncing balls with custom controls. |
| */ |
| @SuppressWarnings("serial") |
| public class Balls extends AnimatingControlsSurface { |
| |
| private static Color colors[] = { RED, ORANGE, YELLOW, GREEN.darker(), BLUE, |
| new Color(75, 00, 82), new Color(238, 130, 238) }; |
| private long now, deltaT, lasttime; |
| private boolean active; |
| protected Ball balls[] = new Ball[colors.length]; |
| protected boolean clearToggle; |
| protected JComboBox combo; |
| |
| public Balls() { |
| setBackground(WHITE); |
| for (int i = 0; i < colors.length; i++) { |
| balls[i] = new Ball(colors[i], 30); |
| } |
| balls[0].isSelected = true; |
| balls[3].isSelected = true; |
| balls[4].isSelected = true; |
| balls[6].isSelected = true; |
| setControls(new Component[] { new DemoControls(this) }); |
| } |
| |
| @Override |
| public void reset(int w, int h) { |
| if (w > 400 && h > 100) { |
| combo.setSelectedIndex(5); |
| } |
| } |
| |
| @Override |
| public void step(int w, int h) { |
| if (lasttime == 0) { |
| lasttime = System.currentTimeMillis(); |
| } |
| now = System.currentTimeMillis(); |
| deltaT = now - lasttime; |
| active = false; |
| for (Ball ball : balls) { |
| if (ball == null) { |
| return; |
| } |
| ball.step(deltaT, w, h); |
| if (ball.Vy > .02 || -ball.Vy > .02 || ball.y + ball.bsize < h) { |
| active = true; |
| } |
| } |
| if (!active) { |
| for (Ball ball : balls) { |
| ball.Vx = (float) random() / 4.0f - 0.125f; |
| ball.Vy = -(float) random() / 4.0f - 0.2f; |
| } |
| clearToggle = true; |
| } |
| } |
| |
| @Override |
| public void render(int w, int h, Graphics2D g2) { |
| for (Ball b : balls) { |
| if (b == null || b.imgs[b.index] == null || !b.isSelected) { |
| continue; |
| } |
| g2.drawImage(b.imgs[b.index], (int) b.x, (int) b.y, this); |
| } |
| lasttime = now; |
| } |
| |
| public static void main(String argv[]) { |
| createDemoFrame(new Balls()); |
| } |
| |
| |
| protected static final class Ball { |
| |
| public static final int nImgs = 5; |
| public int bsize; |
| public float x, y; |
| public float Vx = 0.1f; |
| public float Vy = 0.05f; |
| public BufferedImage imgs[]; |
| // Pick a random starting image index, but not the last: we're going UP |
| // and that would throw us off the end. |
| public int index = (int) (random() * (nImgs - 1)); |
| private static final float inelasticity = .96f; |
| private static final float Ax = 0.0f; |
| private static final float Ay = 0.0002f; |
| private static final int UP = 0; |
| private static final int DOWN = 1; |
| private int indexDirection = UP; |
| private float jitter; |
| private Color color; |
| private boolean isSelected; |
| |
| public Ball(Color color, int bsize) { |
| this.color = color; |
| makeImages(bsize); |
| } |
| |
| public void makeImages(int bsize) { |
| this.bsize = bsize * 2; |
| int R = bsize; |
| byte[] data = new byte[R * 2 * R * 2]; |
| int maxr = 0; |
| for (int Y = 2 * R; --Y >= 0;) { |
| int x0 = (int) (sqrt(R * R - (Y - R) * (Y - R)) + 0.5); |
| int p = Y * (R * 2) + R - x0; |
| for (int X = -x0; X < x0; X++) { |
| int xx = X + 15; |
| int yy = Y - R + 15; |
| int r = (int) (Math.hypot(xx, yy) + 0.5); |
| if (r > maxr) { |
| maxr = r; |
| } |
| data[p++] = r <= 0 ? 1 : (byte) r; |
| } |
| } |
| |
| imgs = new BufferedImage[nImgs]; |
| |
| int bg = 255; |
| byte red[] = new byte[256]; |
| red[0] = (byte) bg; |
| byte green[] = new byte[256]; |
| green[0] = (byte) bg; |
| byte blue[] = new byte[256]; |
| blue[0] = (byte) bg; |
| |
| for (int r = 0; r < imgs.length; r++) { |
| float b = 0.5f + ((r + 1f) / imgs.length / 2f); |
| for (int i = maxr; i >= 1; --i) { |
| float d = (float) i / maxr; |
| red[i] = (byte) blend(blend(color.getRed(), 255, d), bg, b); |
| green[i] = (byte) blend(blend(color.getGreen(), 255, d), bg, |
| b); |
| blue[i] = |
| (byte) blend(blend(color.getBlue(), 255, d), bg, b); |
| } |
| IndexColorModel icm = new IndexColorModel(8, maxr + 1, |
| red, green, blue, 0); |
| DataBufferByte dbb = new DataBufferByte(data, data.length); |
| int bandOffsets[] = { 0 }; |
| WritableRaster wr = Raster.createInterleavedRaster(dbb, |
| R * 2, R * 2, R * 2, 1, bandOffsets, null); |
| imgs[r] = new BufferedImage(icm, wr, icm.isAlphaPremultiplied(), |
| null); |
| } |
| } |
| |
| private int blend(int fg, int bg, float fgfactor) { |
| return (int) (bg + (fg - bg) * fgfactor); |
| } |
| |
| public void step(long deltaT, int w, int h) { |
| |
| jitter = (float) random() * .01f - .005f; |
| |
| x += Vx * deltaT + (Ax / 2.0) * deltaT * deltaT; |
| y += Vy * deltaT + (Ay / 2.0) * deltaT * deltaT; |
| if (x <= 0.0f) { |
| x = 0.0f; |
| Vx = -Vx * inelasticity + jitter; |
| //collision_x = true; |
| } |
| if (x + bsize >= w) { |
| x = w - bsize; |
| Vx = -Vx * inelasticity + jitter; |
| //collision_x = true; |
| } |
| if (y <= 0) { |
| y = 0; |
| Vy = -Vy * inelasticity + jitter; |
| //collision_y = true; |
| } |
| if (y + bsize >= h) { |
| y = h - bsize; |
| Vx *= inelasticity; |
| Vy = -Vy * inelasticity + jitter; |
| //collision_y = true; |
| } |
| Vy = Vy + Ay * deltaT; |
| Vx = Vx + Ax * deltaT; |
| |
| if (indexDirection == UP) { |
| index++; |
| } |
| if (indexDirection == DOWN) { |
| --index; |
| } |
| if (index + 1 == nImgs) { |
| indexDirection = DOWN; |
| } |
| if (index == 0) { |
| indexDirection = UP; |
| } |
| } |
| } // End class Ball |
| |
| |
| final class DemoControls extends CustomControls implements ActionListener { |
| |
| Balls demo; |
| JToolBar toolbar; |
| |
| @SuppressWarnings("LeakingThisInConstructor") |
| public DemoControls(Balls demo) { |
| super(demo.name); |
| this.demo = demo; |
| add(toolbar = new JToolBar()); |
| toolbar.setFloatable(false); |
| addTool("Clear", true); |
| addTool("R", demo.balls[0].isSelected); |
| addTool("O", demo.balls[1].isSelected); |
| addTool("Y", demo.balls[2].isSelected); |
| addTool("G", demo.balls[3].isSelected); |
| addTool("B", demo.balls[4].isSelected); |
| addTool("I", demo.balls[5].isSelected); |
| addTool("V", demo.balls[6].isSelected); |
| add(combo = new JComboBox()); |
| combo.addItem("10"); |
| combo.addItem("20"); |
| combo.addItem("30"); |
| combo.addItem("40"); |
| combo.addItem("50"); |
| combo.addItem("60"); |
| combo.addItem("70"); |
| combo.addItem("80"); |
| combo.setSelectedIndex(2); |
| combo.addActionListener(this); |
| } |
| |
| public void addTool(String str, boolean state) { |
| JToggleButton b = |
| (JToggleButton) toolbar.add(new JToggleButton(str)); |
| b.setFocusPainted(false); |
| b.setSelected(state); |
| b.addActionListener(this); |
| int width = b.getPreferredSize().width; |
| Dimension prefSize = new Dimension(width, 21); |
| b.setPreferredSize(prefSize); |
| b.setMaximumSize(prefSize); |
| b.setMinimumSize(prefSize); |
| } |
| |
| @Override |
| public void actionPerformed(ActionEvent e) { |
| if (e.getSource() instanceof JComboBox) { |
| int size = Integer.parseInt((String) combo.getSelectedItem()); |
| for (Ball ball : demo.balls) { |
| ball.makeImages(size); |
| } |
| return; |
| } |
| JToggleButton b = (JToggleButton) e.getSource(); |
| if (b.getText().equals("Clear")) { |
| demo.clearSurface = b.isSelected(); |
| } else { |
| int index = toolbar.getComponentIndex(b) - 1; |
| demo.balls[index].isSelected = b.isSelected(); |
| } |
| } |
| |
| @Override |
| public Dimension getPreferredSize() { |
| return new Dimension(200, 40); |
| } |
| |
| @Override |
| @SuppressWarnings("SleepWhileHoldingLock") |
| public void run() { |
| try { |
| Thread.sleep(999); |
| } catch (Exception e) { |
| return; |
| } |
| Thread me = Thread.currentThread(); |
| ((AbstractButton) toolbar.getComponentAtIndex(2)).doClick(); |
| while (thread == me) { |
| try { |
| Thread.sleep(222); |
| } catch (InterruptedException e) { |
| return; |
| } |
| if (demo.clearToggle) { |
| if (demo.clearSurface) { |
| combo.setSelectedIndex((int) (random() * 5)); |
| } |
| ((AbstractButton) toolbar.getComponentAtIndex(0)).doClick(); |
| demo.clearToggle = false; |
| } |
| } |
| thread = null; |
| } |
| } // End DemoControls |
| } // End Balls |
| |