1 /* 2 * Copyright (c) 2007, 2019, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 */ 23 24 package com.sun.swingset3.demos.colorchooser; 25 26 import java.awt.*; 27 import java.awt.event.HierarchyEvent; 28 import java.awt.event.HierarchyListener; 29 import java.awt.geom.GeneralPath; 30 import java.awt.image.BufferedImage; 31 import java.lang.reflect.InvocationTargetException; 32 import java.util.Hashtable; 33 import java.util.Map; 34 import javax.swing.*; 35 36 import static com.sun.swingset3.demos.colorchooser.BezierAnimationPanel.BezierColor.*; 37 38 /** 39 * BezierAnimationPanel 40 * 41 * @author Jim Graham 42 * @author Jeff Dinkins (removed dynamic setting changes, made swing friendly) 43 * @version 1.16 11/17/05 44 */ 45 public class BezierAnimationPanel extends JPanel implements Runnable { 46 public static enum BezierColor { 47 BACKGROUND, OUTER, GRADIENT_A, GRADIENT_B 48 } 49 50 private final Map<BezierColor, Color> colors = new Hashtable<BezierColor, Color>(); 51 52 private GradientPaint gradient = null; 53 54 private static final int NUMPTS = 6; 55 56 private final float[] animpts = new float[NUMPTS * 2]; 57 58 private final float[] deltas = new float[NUMPTS * 2]; 59 60 private BufferedImage img; 61 62 private Thread anim; 63 64 private final Object lock = new Object(); 65 66 /** 67 * BezierAnimationPanel Constructor 68 */ BezierAnimationPanel()69 public BezierAnimationPanel() { 70 setOpaque(true); 71 72 colors.put(BACKGROUND, new Color(0, 0, 153)); 73 colors.put(OUTER, new Color(255, 255, 255)); 74 colors.put(GRADIENT_A, new Color(255, 0, 101)); 75 colors.put(GRADIENT_B, new Color(255, 255, 0)); 76 77 addHierarchyListener(new HierarchyListener() { 78 public void hierarchyChanged(HierarchyEvent e) { 79 if (isShowing()) { 80 start(); 81 } else { 82 stop(); 83 } 84 } 85 }); 86 } 87 getBezierColor(BezierColor bezierColor)88 public Color getBezierColor(BezierColor bezierColor) { 89 return colors.get(bezierColor); 90 } 91 setBezierColor(BezierColor bezierColor, Color value)92 public void setBezierColor(BezierColor bezierColor, Color value) { 93 if (value != null) { 94 colors.put(bezierColor, value); 95 } 96 } 97 start()98 public void start() { 99 Dimension size = getSize(); 100 for (int i = 0; i < animpts.length; i += 2) { 101 animpts[i] = (float) (Math.random() * size.width); 102 animpts[i + 1] = (float) (Math.random() * size.height); 103 deltas[i] = (float) (Math.random() * 4.0 + 2.0); 104 deltas[i + 1] = (float) (Math.random() * 4.0 + 2.0); 105 if (animpts[i] > size.width / 6.0f) { 106 deltas[i] = -deltas[i]; 107 } 108 if (animpts[i + 1] > size.height / 6.0f) { 109 deltas[i + 1] = -deltas[i + 1]; 110 } 111 } 112 anim = new Thread(this); 113 anim.setPriority(Thread.MIN_PRIORITY); 114 anim.start(); 115 } 116 stop()117 public synchronized void stop() { 118 anim = null; 119 notify(); 120 } 121 animate(float[] pts, float[] deltas, int index, int limit)122 private static void animate(float[] pts, float[] deltas, int index, int limit) { 123 float newpt = pts[index] + deltas[index]; 124 if (newpt <= 0) { 125 newpt = -newpt; 126 deltas[index] = (float) (Math.random() * 3.0 + 2.0); 127 } else if (newpt >= (float) limit) { 128 newpt = 2.0f * limit - newpt; 129 deltas[index] = -(float) (Math.random() * 3.0 + 2.0); 130 } 131 pts[index] = newpt; 132 } 133 run()134 public void run() { 135 Thread me = Thread.currentThread(); 136 while (getSize().width <= 0) { 137 try { 138 Thread.sleep(500); 139 } catch (InterruptedException e) { 140 return; 141 } 142 } 143 144 Graphics2D g2d = null; 145 Graphics2D bufferG2D = null; 146 BasicStroke solid = new BasicStroke(9.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 9.0f); 147 GeneralPath gp = new GeneralPath(GeneralPath.WIND_NON_ZERO); 148 int rule = AlphaComposite.SRC_OVER; 149 AlphaComposite opaque = AlphaComposite.SrcOver; 150 AlphaComposite blend = AlphaComposite.getInstance(rule, 0.9f); 151 AlphaComposite set = AlphaComposite.Src; 152 Dimension oldSize = getSize(); 153 Shape clippath = null; 154 while (anim == me) { 155 Dimension size = getSize(); 156 if (size.width != oldSize.width || size.height != oldSize.height) { 157 img = null; 158 clippath = null; 159 if (bufferG2D != null) { 160 bufferG2D.dispose(); 161 bufferG2D = null; 162 } 163 } 164 oldSize = size; 165 166 if (img == null) { 167 img = (BufferedImage) createImage(size.width, size.height); 168 } 169 170 if (bufferG2D == null) { 171 bufferG2D = img.createGraphics(); 172 bufferG2D.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_DEFAULT); 173 bufferG2D.setClip(clippath); 174 } 175 g2d = bufferG2D; 176 177 float[] ctrlpts; 178 for (int i = 0; i < animpts.length; i += 2) { 179 animate(animpts, deltas, i, size.width); 180 animate(animpts, deltas, i + 1, size.height); 181 } 182 ctrlpts = animpts; 183 int len = ctrlpts.length; 184 gp.reset(); 185 float prevx = ctrlpts[len - 2]; 186 float prevy = ctrlpts[len - 1]; 187 float curx = ctrlpts[0]; 188 float cury = ctrlpts[1]; 189 float midx = (curx + prevx) / 2.0f; 190 float midy = (cury + prevy) / 2.0f; 191 gp.moveTo(midx, midy); 192 for (int i = 2; i <= ctrlpts.length; i += 2) { 193 float x1 = (midx + curx) / 2.0f; 194 float y1 = (midy + cury) / 2.0f; 195 prevx = curx; 196 prevy = cury; 197 if (i < ctrlpts.length) { 198 curx = ctrlpts[i]; 199 cury = ctrlpts[i + 1]; 200 } else { 201 curx = ctrlpts[0]; 202 cury = ctrlpts[1]; 203 } 204 midx = (curx + prevx) / 2.0f; 205 midy = (cury + prevy) / 2.0f; 206 float x2 = (prevx + midx) / 2.0f; 207 float y2 = (prevy + midy) / 2.0f; 208 gp.curveTo(x1, y1, x2, y2, midx, midy); 209 } 210 gp.closePath(); 211 212 synchronized (lock) { 213 g2d.setComposite(set); 214 g2d.setBackground(getBezierColor(BACKGROUND)); 215 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_OFF); 216 217 // g2d.clearRect(bounds.x-5, bounds.y-5, bounds.x + bounds.width 218 // + 5, bounds.y + bounds.height + 5); 219 g2d.clearRect(0, 0, getWidth(), getHeight()); 220 221 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 222 g2d.setColor(getBezierColor(OUTER)); 223 g2d.setComposite(opaque); 224 g2d.setStroke(solid); 225 g2d.draw(gp); 226 g2d.setPaint(gradient); 227 228 Rectangle bounds = gp.getBounds(); 229 230 gradient = new GradientPaint(bounds.x, bounds.y, getBezierColor(GRADIENT_A), bounds.x + bounds.width, 231 bounds.y + bounds.height, getBezierColor(GRADIENT_B), true); 232 233 g2d.setComposite(blend); 234 g2d.fill(gp); 235 } 236 237 try { 238 SwingUtilities.invokeAndWait(new Runnable() { 239 @Override 240 public void run() { 241 repaint(); 242 } 243 }); 244 } catch (InvocationTargetException | InterruptedException e) { 245 e.printStackTrace(); 246 } 247 } 248 if (g2d != null) { 249 g2d.dispose(); 250 } 251 } 252 paint(Graphics g)253 public void paint(Graphics g) { 254 synchronized (lock) { 255 Graphics2D g2d = (Graphics2D) g; 256 if (img != null) { 257 g2d.setComposite(AlphaComposite.Src); 258 g2d.drawImage(img, null, 0, 0); 259 } 260 } 261 } 262 } 263