1 /*
   2  *
   3  * Copyright (c) 2007, 2018, 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 
  33 
  34 import javax.swing.*;
  35 import javax.swing.event.*;
  36 import javax.swing.text.*;
  37 import javax.swing.border.*;
  38 import javax.swing.colorchooser.*;
  39 import javax.swing.filechooser.*;
  40 import javax.accessibility.*;
  41 
  42 import java.awt.*;
  43 import java.awt.font.*;
  44 import java.awt.geom.*;
  45 import java.awt.image.*;
  46 import java.awt.event.*;
  47 
  48 /**
  49  * BezierAnimationPanel
  50  *
  51  * @author Jim Graham
  52  * @author Jeff Dinkins (removed dynamic setting changes, made swing friendly)
  53  */
  54 class BezierAnimationPanel extends JPanel implements Runnable {
  55 
  56     Color backgroundColor =  new Color(0,     0, 153);
  57     Color outerColor      =  new Color(255, 255, 255);
  58     Color gradientColorA  =  new Color(255,   0, 101);
  59     Color gradientColorB  =  new Color(255, 255,   0);
  60 
  61     boolean bgChanged = false;
  62 
  63     GradientPaint gradient = null;
  64 
  65     public final int NUMPTS = 6;
  66 
  67     float[] animpts = new float[NUMPTS * 2];
  68 
  69     float[] deltas = new float[NUMPTS * 2];
  70 
  71     float[] staticpts = {
  72          50.0f,   0.0f,
  73         150.0f,   0.0f,
  74         200.0f,  75.0f,
  75         150.0f, 150.0f,
  76          50.0f, 150.0f,
  77           0.0f,  75.0f,
  78     };
  79 
  80     float[] movepts = new float[staticpts.length];
  81 
  82     BufferedImage img;
  83 
  84     Rectangle bounds = null;
  85 
  86     Thread anim;
  87 
  88     private final Object lock = new Object();
  89 
  90     /**
  91      * BezierAnimationPanel Constructor
  92      */
  93     public BezierAnimationPanel() {
  94         addHierarchyListener(
  95             new HierarchyListener() {
  96                public void hierarchyChanged(HierarchyEvent e) {
  97                    if(isShowing()) {
  98                        start();
  99                    } else {
 100                        stop();
 101                    }
 102                }
 103            }
 104         );
 105         setBackground(getBackgroundColor());
 106     }
 107 
 108     public boolean isOpaque() {
 109         return true;
 110     }
 111 
 112     public Color getGradientColorA() {
 113         return gradientColorA;
 114     }
 115 
 116     public void setGradientColorA(Color c) {
 117         if(c != null) {
 118             gradientColorA = c;
 119         }
 120     }
 121 
 122     public Color getGradientColorB() {
 123         return gradientColorB;
 124     }
 125 
 126     public void setGradientColorB(Color c) {
 127         if(c != null) {
 128             gradientColorB = c;
 129         }
 130     }
 131 
 132     public Color getOuterColor() {
 133         return outerColor;
 134     }
 135 
 136     public void setOuterColor(Color c) {
 137         if(c != null) {
 138             outerColor = c;
 139         }
 140     }
 141 
 142     public Color getBackgroundColor() {
 143         return backgroundColor;
 144     }
 145 
 146     public void setBackgroundColor(Color c) {
 147         if(c != null) {
 148             backgroundColor = c;
 149             setBackground(c);
 150             bgChanged = true;
 151         }
 152     }
 153 
 154     public void start() {
 155         Dimension size = getSize();
 156         for (int i = 0; i < animpts.length; i += 2) {
 157             animpts[i + 0] = (float) (Math.random() * size.width);
 158             animpts[i + 1] = (float) (Math.random() * size.height);
 159             deltas[i + 0] = (float) (Math.random() * 4.0 + 2.0);
 160             deltas[i + 1] = (float) (Math.random() * 4.0 + 2.0);
 161             if (animpts[i + 0] > size.width / 6.0f) {
 162                 deltas[i + 0] = -deltas[i + 0];
 163             }
 164             if (animpts[i + 1] > size.height / 6.0f) {
 165                 deltas[i + 1] = -deltas[i + 1];
 166             }
 167         }
 168         anim = new Thread(this);
 169         anim.setPriority(Thread.MIN_PRIORITY);
 170         anim.start();
 171     }
 172 
 173     public synchronized void stop() {
 174         anim = null;
 175         notify();
 176     }
 177 
 178     public void animate(float[] pts, float[] deltas, int index, int limit) {
 179         float newpt = pts[index] + deltas[index];
 180         if (newpt <= 0) {
 181             newpt = -newpt;
 182             deltas[index] = (float) (Math.random() * 3.0 + 2.0);
 183         } else if (newpt >= (float) limit) {
 184             newpt = 2.0f * limit - newpt;
 185             deltas[index] = - (float) (Math.random() * 3.0 + 2.0);
 186         }
 187         pts[index] = newpt;
 188     }
 189 
 190     public void run() {
 191         Thread me = Thread.currentThread();
 192         while (getSize().width <= 0) {
 193             try {
 194                 anim.sleep(500);
 195             } catch (InterruptedException e) {
 196                 return;
 197             }
 198         }
 199 
 200         Graphics2D g2d = null;
 201         Graphics2D BufferG2D = null;
 202         Graphics2D ScreenG2D = null;
 203         BasicStroke solid = new BasicStroke(9.0f, BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 9.0f);
 204         GeneralPath gp = new GeneralPath(GeneralPath.WIND_NON_ZERO);
 205         int rule = AlphaComposite.SRC_OVER;
 206         AlphaComposite opaque = AlphaComposite.SrcOver;
 207         AlphaComposite blend = AlphaComposite.getInstance(rule, 0.9f);
 208         AlphaComposite set = AlphaComposite.Src;
 209         int frame = 0;
 210         int frametmp = 0;
 211         Dimension oldSize = getSize();
 212         Shape clippath = null;
 213         while (anim == me) {
 214             Dimension size = getSize();
 215             if (size.width != oldSize.width || size.height != oldSize.height) {
 216                 img = null;
 217                 clippath = null;
 218                 if (BufferG2D != null) {
 219                     BufferG2D.dispose();
 220                     BufferG2D = null;
 221                 }
 222                 if (ScreenG2D != null) {
 223                     ScreenG2D.dispose();
 224                     ScreenG2D = null;
 225                 }
 226             }
 227             oldSize = size;
 228 
 229             if (img == null) {
 230                 img = (BufferedImage) createImage(size.width, size.height);
 231             }
 232 
 233         if (BufferG2D == null) {
 234                 BufferG2D = img.createGraphics();
 235                 BufferG2D.setRenderingHint(RenderingHints.KEY_RENDERING,
 236                                            RenderingHints.VALUE_RENDER_DEFAULT);
 237                 BufferG2D.setClip(clippath);
 238             }
 239             g2d = BufferG2D;
 240 
 241             float[] ctrlpts;
 242             for (int i = 0; i < animpts.length; i += 2) {
 243                 animate(animpts, deltas, i + 0, size.width);
 244                 animate(animpts, deltas, i + 1, size.height);
 245             }
 246             ctrlpts = animpts;
 247             int len = ctrlpts.length;
 248             gp.reset();
 249             int dir = 0;
 250             float prevx = ctrlpts[len - 2];
 251             float prevy = ctrlpts[len - 1];
 252             float curx = ctrlpts[0];
 253             float cury = ctrlpts[1];
 254             float midx = (curx + prevx) / 2.0f;
 255             float midy = (cury + prevy) / 2.0f;
 256             gp.moveTo(midx, midy);
 257             for (int i = 2; i <= ctrlpts.length; i += 2) {
 258                 float x1 = (midx + curx) / 2.0f;
 259                 float y1 = (midy + cury) / 2.0f;
 260                 prevx = curx;
 261                 prevy = cury;
 262                 if (i < ctrlpts.length) {
 263                     curx = ctrlpts[i + 0];
 264                     cury = ctrlpts[i + 1];
 265                 } else {
 266                     curx = ctrlpts[0];
 267                     cury = ctrlpts[1];
 268                 }
 269                 midx = (curx + prevx) / 2.0f;
 270                 midy = (cury + prevy) / 2.0f;
 271                 float x2 = (prevx + midx) / 2.0f;
 272                 float y2 = (prevy + midy) / 2.0f;
 273                 gp.curveTo(x1, y1, x2, y2, midx, midy);
 274             }
 275             gp.closePath();
 276 
 277             synchronized(lock) {
 278         g2d.setComposite(set);
 279             g2d.setBackground(backgroundColor);
 280             g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
 281                                  RenderingHints.VALUE_ANTIALIAS_OFF);
 282 
 283             if(bgChanged || bounds == null) {
 284                 bounds = new Rectangle(0, 0, getWidth(), getHeight());
 285                 bgChanged = false;
 286             }
 287 
 288         // g2d.clearRect(bounds.x-5, bounds.y-5, bounds.x + bounds.width + 5, bounds.y + bounds.height + 5);
 289             g2d.clearRect(0, 0, getWidth(), getHeight());
 290 
 291             g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
 292                                  RenderingHints.VALUE_ANTIALIAS_ON);
 293             g2d.setColor(outerColor);
 294             g2d.setComposite(opaque);
 295             g2d.setStroke(solid);
 296             g2d.draw(gp);
 297             g2d.setPaint(gradient);
 298 
 299             if(!bgChanged) {
 300                 bounds = gp.getBounds();
 301             } else {
 302                 bounds = new Rectangle(0, 0, getWidth(), getHeight());
 303                 bgChanged = false;
 304             }
 305             gradient = new GradientPaint(bounds.x, bounds.y, gradientColorA,
 306                                          bounds.x + bounds.width, bounds.y + bounds.height,
 307                                          gradientColorB, true);
 308             g2d.setComposite(blend);
 309             g2d.fill(gp);
 310         }
 311             if (g2d == BufferG2D) {
 312                 repaint();
 313             }
 314             ++frame;
 315             Thread.yield();
 316         }
 317         if (g2d != null) {
 318             g2d.dispose();
 319         }
 320     }
 321 
 322     public void paint(Graphics g) {
 323         synchronized (lock) {
 324            Graphics2D g2d = (Graphics2D) g;
 325            if (img != null) {
 326                g2d.setComposite(AlphaComposite.Src);
 327                g2d.drawImage(img, null, 0, 0);
 328            }
 329         }
 330     }
 331 }