1 /* 2 * 3 * Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * - Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 12 * - Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * - Neither the name of Oracle nor the names of its 17 * contributors may be used to endorse or promote products derived 18 * from this software without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 21 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, 22 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR 24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 31 */ 32 package java2d.demos.Mix; 33 34 35 import static java.awt.Color.BLUE; 36 import static java.awt.Color.GREEN; 37 import static java.awt.Color.ORANGE; 38 import static java.awt.Color.RED; 39 import static java.awt.Color.WHITE; 40 import static java.awt.Color.YELLOW; 41 import static java.lang.Math.random; 42 import static java.lang.Math.sqrt; 43 import java.awt.Color; 44 import java.awt.Component; 45 import java.awt.Dimension; 46 import java.awt.Graphics2D; 47 import java.awt.event.ActionEvent; 48 import java.awt.event.ActionListener; 49 import java.awt.image.BufferedImage; 50 import java.awt.image.DataBufferByte; 51 import java.awt.image.IndexColorModel; 52 import java.awt.image.Raster; 53 import java.awt.image.WritableRaster; 54 import java2d.AnimatingControlsSurface; 55 import java2d.CustomControls; 56 import javax.swing.AbstractButton; 57 import javax.swing.JComboBox; 58 import javax.swing.JToggleButton; 59 import javax.swing.JToolBar; 60 61 62 /** 63 * Animated color bouncing balls with custom controls. 64 */ 65 @SuppressWarnings("serial") 66 public class Balls extends AnimatingControlsSurface { 67 68 private static Color colors[] = { RED, ORANGE, YELLOW, GREEN.darker(), BLUE, 69 new Color(75, 00, 82), new Color(238, 130, 238) }; 70 private long now, deltaT, lasttime; 71 private boolean active; 72 protected Ball balls[] = new Ball[colors.length]; 73 protected boolean clearToggle; 74 protected JComboBox combo; 75 76 public Balls() { 77 setBackground(WHITE); 78 for (int i = 0; i < colors.length; i++) { 79 balls[i] = new Ball(colors[i], 30); 80 } 81 balls[0].isSelected = true; 82 balls[3].isSelected = true; 83 balls[4].isSelected = true; 84 balls[6].isSelected = true; 85 setControls(new Component[] { new DemoControls(this) }); 86 } 87 88 @Override 89 public void reset(int w, int h) { 90 if (w > 400 && h > 100) { 91 combo.setSelectedIndex(5); 92 } 93 } 94 95 @Override 96 public void step(int w, int h) { 97 if (lasttime == 0) { 98 lasttime = System.currentTimeMillis(); 99 } 100 now = System.currentTimeMillis(); 101 deltaT = now - lasttime; 102 active = false; 103 for (Ball ball : balls) { 104 if (ball == null) { 105 return; 106 } 107 ball.step(deltaT, w, h); 108 if (ball.Vy > .02 || -ball.Vy > .02 || ball.y + ball.bsize < h) { 109 active = true; 110 } 111 } 112 if (!active) { 113 for (Ball ball : balls) { 114 ball.Vx = (float) random() / 4.0f - 0.125f; 115 ball.Vy = -(float) random() / 4.0f - 0.2f; 116 } 117 clearToggle = true; 118 } 119 } 120 121 @Override 122 public void render(int w, int h, Graphics2D g2) { 123 for (Ball b : balls) { 124 if (b == null || b.imgs[b.index] == null || !b.isSelected) { 125 continue; 126 } 127 g2.drawImage(b.imgs[b.index], (int) b.x, (int) b.y, this); 128 } 129 lasttime = now; 130 } 131 132 public static void main(String argv[]) { 133 createDemoFrame(new Balls()); 134 } 135 136 137 protected static final class Ball { 138 139 public static final int nImgs = 5; 140 public int bsize; 141 public float x, y; 142 public float Vx = 0.1f; 143 public float Vy = 0.05f; 144 public BufferedImage imgs[]; 145 // Pick a random starting image index, but not the last: we're going UP 146 // and that would throw us off the end. 147 public int index = (int) (random() * (nImgs - 1)); 148 private static final float inelasticity = .96f; 149 private static final float Ax = 0.0f; 150 private static final float Ay = 0.0002f; 151 private static final int UP = 0; 152 private static final int DOWN = 1; 153 private int indexDirection = UP; 154 private float jitter; 155 private Color color; 156 private boolean isSelected; 157 158 public Ball(Color color, int bsize) { 159 this.color = color; 160 makeImages(bsize); 161 } 162 163 public void makeImages(int bsize) { 164 this.bsize = bsize * 2; 165 int R = bsize; 166 byte[] data = new byte[R * 2 * R * 2]; 167 int maxr = 0; 168 for (int Y = 2 * R; --Y >= 0;) { 169 int x0 = (int) (sqrt(R * R - (Y - R) * (Y - R)) + 0.5); 170 int p = Y * (R * 2) + R - x0; 171 for (int X = -x0; X < x0; X++) { 172 int xx = X + 15; 173 int yy = Y - R + 15; 174 int r = (int) (Math.hypot(xx, yy) + 0.5); 175 if (r > maxr) { 176 maxr = r; 177 } 178 data[p++] = r <= 0 ? 1 : (byte) r; 179 } 180 } 181 182 imgs = new BufferedImage[nImgs]; 183 184 int bg = 255; 185 byte red[] = new byte[256]; 186 red[0] = (byte) bg; 187 byte green[] = new byte[256]; 188 green[0] = (byte) bg; 189 byte blue[] = new byte[256]; 190 blue[0] = (byte) bg; 191 192 for (int r = 0; r < imgs.length; r++) { 193 float b = 0.5f + ((r + 1f) / imgs.length / 2f); 194 for (int i = maxr; i >= 1; --i) { 195 float d = (float) i / maxr; 196 red[i] = (byte) blend(blend(color.getRed(), 255, d), bg, b); 197 green[i] = (byte) blend(blend(color.getGreen(), 255, d), bg, 198 b); 199 blue[i] = 200 (byte) blend(blend(color.getBlue(), 255, d), bg, b); 201 } 202 IndexColorModel icm = new IndexColorModel(8, maxr + 1, 203 red, green, blue, 0); 204 DataBufferByte dbb = new DataBufferByte(data, data.length); 205 int bandOffsets[] = { 0 }; 206 WritableRaster wr = Raster.createInterleavedRaster(dbb, 207 R * 2, R * 2, R * 2, 1, bandOffsets, null); 208 imgs[r] = new BufferedImage(icm, wr, icm.isAlphaPremultiplied(), 209 null); 210 } 211 } 212 213 private int blend(int fg, int bg, float fgfactor) { 214 return (int) (bg + (fg - bg) * fgfactor); 215 } 216 217 public void step(long deltaT, int w, int h) { 218 219 jitter = (float) random() * .01f - .005f; 220 221 x += Vx * deltaT + (Ax / 2.0) * deltaT * deltaT; 222 y += Vy * deltaT + (Ay / 2.0) * deltaT * deltaT; 223 if (x <= 0.0f) { 224 x = 0.0f; 225 Vx = -Vx * inelasticity + jitter; 226 //collision_x = true; 227 } 228 if (x + bsize >= w) { 229 x = w - bsize; 230 Vx = -Vx * inelasticity + jitter; 231 //collision_x = true; 232 } 233 if (y <= 0) { 234 y = 0; 235 Vy = -Vy * inelasticity + jitter; 236 //collision_y = true; 237 } 238 if (y + bsize >= h) { 239 y = h - bsize; 240 Vx *= inelasticity; 241 Vy = -Vy * inelasticity + jitter; 242 //collision_y = true; 243 } 244 Vy = Vy + Ay * deltaT; 245 Vx = Vx + Ax * deltaT; 246 247 if (indexDirection == UP) { 248 index++; 249 } 250 if (indexDirection == DOWN) { 251 --index; 252 } 253 if (index + 1 == nImgs) { 254 indexDirection = DOWN; 255 } 256 if (index == 0) { 257 indexDirection = UP; 258 } 259 } 260 } // End class Ball 261 262 263 final class DemoControls extends CustomControls implements ActionListener { 264 265 Balls demo; 266 JToolBar toolbar; 267 268 @SuppressWarnings("LeakingThisInConstructor") 269 public DemoControls(Balls demo) { 270 super(demo.name); 271 this.demo = demo; 272 add(toolbar = new JToolBar()); 273 toolbar.setFloatable(false); 274 addTool("Clear", true); 275 addTool("R", demo.balls[0].isSelected); 276 addTool("O", demo.balls[1].isSelected); 277 addTool("Y", demo.balls[2].isSelected); 278 addTool("G", demo.balls[3].isSelected); 279 addTool("B", demo.balls[4].isSelected); 280 addTool("I", demo.balls[5].isSelected); 281 addTool("V", demo.balls[6].isSelected); 282 add(combo = new JComboBox()); 283 combo.addItem("10"); 284 combo.addItem("20"); 285 combo.addItem("30"); 286 combo.addItem("40"); 287 combo.addItem("50"); 288 combo.addItem("60"); 289 combo.addItem("70"); 290 combo.addItem("80"); 291 combo.setSelectedIndex(2); 292 combo.addActionListener(this); 293 } 294 295 public void addTool(String str, boolean state) { 296 JToggleButton b = 297 (JToggleButton) toolbar.add(new JToggleButton(str)); 298 b.setFocusPainted(false); 299 b.setSelected(state); 300 b.addActionListener(this); 301 int width = b.getPreferredSize().width; 302 Dimension prefSize = new Dimension(width, 21); 303 b.setPreferredSize(prefSize); 304 b.setMaximumSize(prefSize); 305 b.setMinimumSize(prefSize); 306 } 307 308 @Override 309 public void actionPerformed(ActionEvent e) { 310 if (e.getSource() instanceof JComboBox) { 311 int size = Integer.parseInt((String) combo.getSelectedItem()); 312 for (Ball ball : demo.balls) { 313 ball.makeImages(size); 314 } 315 return; 316 } 317 JToggleButton b = (JToggleButton) e.getSource(); 318 if (b.getText().equals("Clear")) { 319 demo.clearSurface = b.isSelected(); 320 } else { 321 int index = toolbar.getComponentIndex(b) - 1; 322 demo.balls[index].isSelected = b.isSelected(); 323 } 324 } 325 326 @Override 327 public Dimension getPreferredSize() { 328 return new Dimension(200, 40); 329 } 330 331 @Override 332 @SuppressWarnings("SleepWhileHoldingLock") 333 public void run() { 334 try { 335 Thread.sleep(999); 336 } catch (Exception e) { 337 return; 338 } 339 Thread me = Thread.currentThread(); 340 ((AbstractButton) toolbar.getComponentAtIndex(2)).doClick(); 341 while (thread == me) { 342 try { 343 Thread.sleep(222); 344 } catch (InterruptedException e) { 345 return; 346 } 347 if (demo.clearToggle) { 348 if (demo.clearSurface) { 349 combo.setSelectedIndex((int) (random() * 5)); 350 } 351 ((AbstractButton) toolbar.getComponentAtIndex(0)).doClick(); 352 demo.clearToggle = false; 353 } 354 } 355 thread = null; 356 } 357 } // End DemoControls 358 } // End Balls 359