BezierAnimationPanel.java  
1   /*
2    * @(#)BezierAnimationPanel.java    1.14 04/07/26
3    * 
4    * Copyright (c) 2004 Sun Microsystems, Inc. All Rights Reserved.
5    * 
6    * Redistribution and use in source and binary forms, with or without
7    * modification, are permitted provided that the following conditions are met:
8    * 
9    * -Redistribution of source code must retain the above copyright notice, this
10   *  list of conditions and the following disclaimer.
11   * 
12   * -Redistribution in binary form must reproduce the above copyright notice, 
13   *  this list of conditions and the following disclaimer in the documentation
14   *  and/or other materials provided with the distribution.
15   * 
16   * Neither the name of Sun Microsystems, Inc. or the names of contributors may 
17   * be used to endorse or promote products derived from this software without 
18   * specific prior written permission.
19   * 
20   * This software is provided "AS IS," without a warranty of any kind. ALL 
21   * EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING
22   * ANY IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE
23   * OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN")
24   * AND ITS LICENSORS SHALL NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE
25   * AS A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
26   * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR ANY LOST 
27   * REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, 
28   * INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND REGARDLESS OF THE THEORY 
29   * OF LIABILITY, ARISING OUT OF THE USE OF OR INABILITY TO USE THIS SOFTWARE, 
30   * EVEN IF SUN HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
31   * 
32   * You acknowledge that this software is not designed, licensed or intended
33   * for use in the design, construction, operation or maintenance of any
34   * nuclear facility.
35   */
36  
37  /*
38   * @(#)BezierAnimationPanel.java    1.14 04/07/26
39   */
40  
41  
42  import javax.swing.*;
43  import javax.swing.event.*;
44  import javax.swing.text.*;
45  import javax.swing.border.*;
46  import javax.swing.colorchooser.*;
47  import javax.swing.filechooser.*;
48  import javax.accessibility.*;
49   
50  import java.awt.*;
51  import java.awt.font.*;
52  import java.awt.geom.*;
53  import java.awt.image.*;
54  import java.awt.event.*;
55  
56  /**
57   * BezierAnimationPanel
58   *
59   * @version 1.14 07/26/04
60   * @author Jim Graham
61   * @author Jeff Dinkins (removed dynamic setting changes, made swing friendly)
62   */
63  class BezierAnimationPanel extends JPanel implements Runnable {
64  
65      Color backgroundColor =  new Color(0,     0, 153);
66      Color outerColor      =  new Color(255, 255, 255);
67      Color gradientColorA  =  new Color(255,   0, 101);
68      Color gradientColorB  =  new Color(255, 255,   0);
69  
70      boolean bgChanged = false;
71  
72      GradientPaint gradient = null;
73      
74      public final int NUMPTS = 6;
75  
76      float animpts[] = new float[NUMPTS * 2];
77  
78      float deltas[] = new float[NUMPTS * 2];
79  
80      float staticpts[] = {
81       50.0f,   0.0f,
82      150.0f,   0.0f,
83      200.0f,  75.0f,
84      150.0f, 150.0f,
85       50.0f, 150.0f,
86        0.0f,  75.0f,
87      };
88  
89      float movepts[] = new float[staticpts.length];
90  
91      BufferedImage img;
92  
93      Rectangle bounds = null;
94  
95      Thread anim;
96  
97      /**
98       * BezierAnimationPanel Constructor
99       */
100     public BezierAnimationPanel() {
101     addHierarchyListener(
102         new HierarchyListener() {
103            public void hierarchyChanged(HierarchyEvent e) {
104            if(isShowing()) {
105                start();
106            } else {
107                stop();
108            }
109            }
110        }
111     );
112     setBackground(getBackgroundColor());
113     }
114 
115     public boolean isOpaque() {
116         return true;
117     }
118 
119     public Color getGradientColorA() {
120     return gradientColorA;
121     }
122 
123     public void setGradientColorA(Color c) {
124     if(c != null) {
125         gradientColorA = c;
126     }
127     }
128 
129     public Color getGradientColorB() {
130     return gradientColorB;
131     }
132 
133     public void setGradientColorB(Color c) {
134     if(c != null) {
135         gradientColorB = c;
136     }
137     }
138 
139     public Color getOuterColor() {
140     return outerColor;
141     }
142 
143     public void setOuterColor(Color c) {
144     if(c != null) {
145         outerColor = c;
146     }
147     }
148 
149     public Color getBackgroundColor() {
150     return backgroundColor;
151     }
152 
153     public void setBackgroundColor(Color c) {
154     if(c != null) {
155         backgroundColor = c;
156         setBackground(c);
157         bgChanged = true;
158     }
159     }
160 
161     public void start() {
162     Dimension size = getSize();
163     for (int i = 0; i < animpts.length; i += 2) {
164         animpts[i + 0] = (float) (Math.random() * size.width);
165         animpts[i + 1] = (float) (Math.random() * size.height);
166         deltas[i + 0] = (float) (Math.random() * 4.0 + 2.0);
167         deltas[i + 1] = (float) (Math.random() * 4.0 + 2.0);
168         if (animpts[i + 0] > size.width / 6.0f) {
169         deltas[i + 0] = -deltas[i + 0];
170         }
171         if (animpts[i + 1] > size.height / 6.0f) {
172         deltas[i + 1] = -deltas[i + 1];
173         }
174     }
175     anim = new Thread(this);
176     anim.setPriority(Thread.MIN_PRIORITY);
177     anim.start();
178     }
179 
180     public synchronized void stop() {
181     anim = null;
182     notify();
183     }
184 
185     public void animate(float[] pts, float[] deltas, int index, int limit) {
186     float newpt = pts[index] + deltas[index];
187     if (newpt <= 0) {
188         newpt = -newpt;
189         deltas[index] = (float) (Math.random() * 3.0 + 2.0);
190     } else if (newpt >= (float) limit) {
191         newpt = 2.0f * limit - newpt;
192         deltas[index] = - (float) (Math.random() * 3.0 + 2.0);
193     }
194     pts[index] = newpt;
195     }
196 
197     public void run() {
198     Thread me = Thread.currentThread();
199     while (getSize().width <= 0) {
200         try {
201         anim.sleep(500);
202         } catch (InterruptedException e) {
203         return;
204         }
205         }
206          
207     Graphics2D g2d = null;
208     Graphics2D BufferG2D = null;
209     Graphics2D ScreenG2D = null;
210     BasicStroke solid = new BasicStroke(9.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 9.0f);
211     GeneralPath gp = new GeneralPath(GeneralPath.WIND_NON_ZERO);
212     int rule = AlphaComposite.SRC_OVER;
213     AlphaComposite opaque = AlphaComposite.SrcOver;
214     AlphaComposite blend = AlphaComposite.getInstance(rule, 0.9f);
215     AlphaComposite set = AlphaComposite.Src;
216     int frame = 0;
217     int frametmp = 0;
218     Dimension oldSize = getSize();
219     Shape clippath = null;
220     while (anim == me) {
221         Dimension size = getSize();
222         if (size.width != oldSize.width || size.height != oldSize.height) {
223         img = null;
224         clippath = null;
225         if (BufferG2D != null) {
226             BufferG2D.dispose();
227             BufferG2D = null;
228         }
229         if (ScreenG2D != null) {
230             ScreenG2D.dispose();
231             ScreenG2D = null;
232         }
233         }
234         oldSize = size;
235 
236         if (img == null) {
237         img = (BufferedImage) createImage(size.width, size.height);
238         }
239 
240         if (BufferG2D == null) {
241         BufferG2D = img.createGraphics();
242         BufferG2D.setRenderingHint(RenderingHints.KEY_RENDERING,
243                        RenderingHints.VALUE_RENDER_DEFAULT);
244         BufferG2D.setClip(clippath);
245         }
246         g2d = BufferG2D;
247 
248         float[] ctrlpts;
249         for (int i = 0; i < animpts.length; i += 2) {
250         animate(animpts, deltas, i + 0, size.width);
251         animate(animpts, deltas, i + 1, size.height);
252         }
253         ctrlpts = animpts;
254         int len = ctrlpts.length;
255         gp.reset();
256         int dir = 0;
257         float prevx = ctrlpts[len - 2];
258         float prevy = ctrlpts[len - 1];
259         float curx = ctrlpts[0];
260         float cury = ctrlpts[1];
261         float midx = (curx + prevx) / 2.0f;
262         float midy = (cury + prevy) / 2.0f;
263         gp.moveTo(midx, midy);
264         for (int i = 2; i <= ctrlpts.length; i += 2) {
265         float x1 = (midx + curx) / 2.0f;
266         float y1 = (midy + cury) / 2.0f;
267         prevx = curx;
268         prevy = cury;
269         if (i < ctrlpts.length) {
270             curx = ctrlpts[i + 0];
271             cury = ctrlpts[i + 1];
272         } else {
273             curx = ctrlpts[0];
274             cury = ctrlpts[1];
275         }
276         midx = (curx + prevx) / 2.0f;
277         midy = (cury + prevy) / 2.0f;
278         float x2 = (prevx + midx) / 2.0f;
279         float y2 = (prevy + midy) / 2.0f;
280         gp.curveTo(x1, y1, x2, y2, midx, midy);
281         }
282         gp.closePath();
283 
284         g2d.setComposite(set);
285         g2d.setBackground(backgroundColor);
286         g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
287                  RenderingHints.VALUE_ANTIALIAS_OFF);
288 
289         if(bgChanged || bounds == null) {
290         bounds = new Rectangle(0, 0, getWidth(), getHeight());
291         bgChanged = false;
292         }
293         // g2d.clearRect(bounds.x-5, bounds.y-5, bounds.x + bounds.width + 5, bounds.y + bounds.height + 5);
294         g2d.clearRect(0, 0, getWidth(), getHeight());
295 
296         g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
297                  RenderingHints.VALUE_ANTIALIAS_ON);
298         g2d.setColor(outerColor);
299         g2d.setComposite(opaque);
300         g2d.setStroke(solid);
301         g2d.draw(gp);
302         g2d.setPaint(gradient);
303 
304         if(!bgChanged) {
305         bounds = gp.getBounds();
306         } else {
307         bounds = new Rectangle(0, 0, getWidth(), getHeight());
308         bgChanged = false;
309         }
310         gradient = new GradientPaint(bounds.x, bounds.y, gradientColorA,
311                      bounds.x + bounds.width, bounds.y + bounds.height,
312                      gradientColorB, true);
313         g2d.setComposite(blend);
314         g2d.fill(gp);
315 
316         if (g2d == BufferG2D) {
317         repaint();
318         }
319         ++frame;
320         Thread.yield();
321     }
322     if (g2d != null) {  
323         g2d.dispose();
324     }
325     }
326 
327     public void paint(Graphics g) {
328     synchronized (this) {
329        Graphics2D g2d = (Graphics2D) g;
330        if (img != null) {
331            int imgw = img.getWidth();
332            int imgh = img.getHeight();
333            g2d.setComposite(AlphaComposite.Src);
334            g2d.drawImage(img, null, 0, 0);
335        }
336         }
337     }
338 }
339