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 package java2d.demos.Arcs_Curves;
  33 
  34 
  35 import static java.awt.Color.BLUE;
  36 import static java.awt.Color.GRAY;
  37 import static java.awt.Color.GREEN;
  38 import static java.awt.Color.RED;
  39 import static java.awt.Color.WHITE;
  40 import static java.awt.Color.YELLOW;
  41 import java.awt.BasicStroke;
  42 import java.awt.Color;
  43 import java.awt.Component;
  44 import java.awt.Dimension;
  45 import java.awt.Font;
  46 import java.awt.GradientPaint;
  47 import java.awt.Graphics;
  48 import java.awt.Graphics2D;
  49 import java.awt.Paint;
  50 import java.awt.Rectangle;
  51 import java.awt.TexturePaint;
  52 import java.awt.event.ActionEvent;
  53 import java.awt.event.ActionListener;
  54 import java.awt.geom.GeneralPath;
  55 import java.awt.geom.Path2D;
  56 import java.awt.image.BufferedImage;
  57 import java2d.AnimatingControlsSurface;
  58 import java2d.CustomControls;
  59 import javax.swing.Icon;
  60 import javax.swing.JMenu;
  61 import javax.swing.JMenuBar;
  62 import javax.swing.JMenuItem;
  63 
  64 
  65 /**
  66  * Animated Bezier Curve with controls for different draw & fill paints.
  67  */
  68 @SuppressWarnings("serial")
  69 public class BezierAnim extends AnimatingControlsSurface {
  70 
  71     private static final int NUMPTS = 6;
  72     protected BasicStroke solid = new BasicStroke(10.0f,
  73             BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND);
  74     protected BasicStroke dashed = new BasicStroke(10.0f,
  75             BasicStroke.CAP_BUTT, BasicStroke.JOIN_ROUND, 10, new float[] { 5 },
  76             0);
  77     private float[] animpts = new float[NUMPTS * 2];
  78     private float[] deltas = new float[NUMPTS * 2];
  79     protected Paint fillPaint, drawPaint;
  80     protected boolean doFill = true;
  81     protected boolean doDraw = true;
  82     protected GradientPaint gradient;
  83     protected BasicStroke stroke;
  84 
  85     public BezierAnim() {
  86         setBackground(WHITE);
  87         gradient = new GradientPaint(0, 0, RED, 200, 200, YELLOW);
  88         fillPaint = gradient;
  89         drawPaint = BLUE;
  90         stroke = solid;
  91         setControls(new Component[] { new DemoControls(this) });
  92     }
  93 
  94     public void animate(float[] pts, float[] deltas, int index, int limit) {
  95         float newpt = pts[index] + deltas[index];
  96         if (newpt <= 0) {
  97             newpt = -newpt;
  98             deltas[index] = (float) (Math.random() * 4.0 + 2.0);
  99         } else if (newpt >= limit) {
 100             newpt = 2.0f * limit - newpt;
 101             deltas[index] = -(float) (Math.random() * 4.0 + 2.0);
 102         }
 103         pts[index] = newpt;
 104     }
 105 
 106     @Override
 107     public void reset(int w, int h) {
 108         for (int i = 0; i < animpts.length; i += 2) {
 109             animpts[i + 0] = (float) (Math.random() * w);
 110             animpts[i + 1] = (float) (Math.random() * h);
 111             deltas[i + 0] = (float) (Math.random() * 6.0 + 4.0);
 112             deltas[i + 1] = (float) (Math.random() * 6.0 + 4.0);
 113             if (animpts[i + 0] > w / 2.0f) {
 114                 deltas[i + 0] = -deltas[i + 0];
 115             }
 116             if (animpts[i + 1] > h / 2.0f) {
 117                 deltas[i + 1] = -deltas[i + 1];
 118             }
 119         }
 120         gradient = new GradientPaint(0, 0, RED, w * .7f, h * .7f, YELLOW);
 121     }
 122 
 123     @Override
 124     public void step(int w, int h) {
 125         for (int i = 0; i < animpts.length; i += 2) {
 126             animate(animpts, deltas, i + 0, w);
 127             animate(animpts, deltas, i + 1, h);
 128         }
 129     }
 130 
 131     @Override
 132     public void render(int w, int h, Graphics2D g2) {
 133         float[] ctrlpts = animpts;
 134         int len = ctrlpts.length;
 135         float prevx = ctrlpts[len - 2];
 136         float prevy = ctrlpts[len - 1];
 137         float curx = ctrlpts[0];
 138         float cury = ctrlpts[1];
 139         float midx = (curx + prevx) / 2.0f;
 140         float midy = (cury + prevy) / 2.0f;
 141         GeneralPath gp = new GeneralPath(Path2D.WIND_NON_ZERO);
 142         gp.moveTo(midx, midy);
 143         for (int i = 2; i <= ctrlpts.length; i += 2) {
 144             float x1 = (midx + curx) / 2.0f;
 145             float y1 = (midy + cury) / 2.0f;
 146             prevx = curx;
 147             prevy = cury;
 148             if (i < ctrlpts.length) {
 149                 curx = ctrlpts[i + 0];
 150                 cury = ctrlpts[i + 1];
 151             } else {
 152                 curx = ctrlpts[0];
 153                 cury = ctrlpts[1];
 154             }
 155             midx = (curx + prevx) / 2.0f;
 156             midy = (cury + prevy) / 2.0f;
 157             float x2 = (prevx + midx) / 2.0f;
 158             float y2 = (prevy + midy) / 2.0f;
 159             gp.curveTo(x1, y1, x2, y2, midx, midy);
 160         }
 161         gp.closePath();
 162         if (doDraw) {
 163             g2.setPaint(drawPaint);
 164             g2.setStroke(stroke);
 165             g2.draw(gp);
 166         }
 167         if (doFill) {
 168             if (fillPaint instanceof GradientPaint) {
 169                 fillPaint = gradient;
 170             }
 171             g2.setPaint(fillPaint);
 172             g2.fill(gp);
 173         }
 174     }
 175 
 176     public static void main(String[] argv) {
 177         createDemoFrame(new BezierAnim());
 178     }
 179 
 180 
 181     static class DemoControls extends CustomControls implements ActionListener {
 182 
 183         static final TexturePaint tp1, tp2;
 184 
 185         static {
 186             BufferedImage bi = new BufferedImage(2, 1,
 187                     BufferedImage.TYPE_INT_RGB);
 188             bi.setRGB(0, 0, 0xff00ff00);
 189             bi.setRGB(1, 0, 0xffff0000);
 190             tp1 = new TexturePaint(bi, new Rectangle(0, 0, 2, 1));
 191             bi = new BufferedImage(2, 1, BufferedImage.TYPE_INT_RGB);
 192             bi.setRGB(0, 0, 0xff0000ff);
 193             bi.setRGB(1, 0, 0xffff0000);
 194             tp2 = new TexturePaint(bi, new Rectangle(0, 0, 2, 1));
 195         }
 196         BezierAnim demo;
 197         static Paint[] drawPaints = { new Color(0, 0, 0, 0), BLUE, new Color(0,
 198             0, 255, 126),
 199             BLUE, tp2 };
 200         static String[] drawName = { "No Draw", "Blue", "Blue w/ Alpha",
 201             "Blue Dash", "Texture" };
 202         static Paint[] fillPaints = { new Color(0, 0, 0, 0), GREEN, new Color(0,
 203             255, 0, 126),
 204             tp1, new GradientPaint(0, 0, RED, 30, 30, YELLOW) };
 205         String[] fillName = { "No Fill", "Green", "Green w/ Alpha", "Texture",
 206             "Gradient" };
 207         JMenu fillMenu, drawMenu;
 208         JMenuItem[] fillMI = new JMenuItem[fillPaints.length];
 209         JMenuItem[] drawMI = new JMenuItem[drawPaints.length];
 210         PaintedIcon[] fillIcons = new PaintedIcon[fillPaints.length];
 211         PaintedIcon[] drawIcons = new PaintedIcon[drawPaints.length];
 212         Font font = new Font(Font.SERIF, Font.PLAIN, 10);
 213 
 214         @SuppressWarnings("LeakingThisInConstructor")
 215         public DemoControls(BezierAnim demo) {
 216             super(demo.name);
 217             this.demo = demo;
 218 
 219             JMenuBar drawMenuBar = new JMenuBar();
 220             add(drawMenuBar);
 221 
 222             JMenuBar fillMenuBar = new JMenuBar();
 223             add(fillMenuBar);
 224 
 225             drawMenu = drawMenuBar.add(new JMenu("Draw Choice"));
 226             drawMenu.setFont(font);
 227 
 228             for (int i = 0; i < drawPaints.length; i++) {
 229                 drawIcons[i] = new PaintedIcon(drawPaints[i]);
 230                 drawMI[i] = drawMenu.add(new JMenuItem(drawName[i]));
 231                 drawMI[i].setFont(font);
 232                 drawMI[i].setIcon(drawIcons[i]);
 233                 drawMI[i].addActionListener(this);
 234             }
 235             drawMenu.setIcon(drawIcons[1]);
 236 
 237             fillMenu = fillMenuBar.add(new JMenu("Fill Choice"));
 238             fillMenu.setFont(font);
 239             for (int i = 0; i < fillPaints.length; i++) {
 240                 fillIcons[i] = new PaintedIcon(fillPaints[i]);
 241                 fillMI[i] = fillMenu.add(new JMenuItem(fillName[i]));
 242                 fillMI[i].setFont(font);
 243                 fillMI[i].setIcon(fillIcons[i]);
 244                 fillMI[i].addActionListener(this);
 245             }
 246             fillMenu.setIcon(fillIcons[fillPaints.length - 1]);
 247         }
 248 
 249         @Override
 250         public void actionPerformed(ActionEvent e) {
 251             Object obj = e.getSource();
 252             for (int i = 0; i < fillPaints.length; i++) {
 253                 if (obj.equals(fillMI[i])) {
 254                     demo.doFill = true;
 255                     demo.fillPaint = fillPaints[i];
 256                     fillMenu.setIcon(fillIcons[i]);
 257                     break;
 258                 }
 259             }
 260             for (int i = 0; i < drawPaints.length; i++) {
 261                 if (obj.equals(drawMI[i])) {
 262                     demo.doDraw = true;
 263                     demo.drawPaint = drawPaints[i];
 264                     if (((JMenuItem) obj).getText().endsWith("Dash")) {
 265                         demo.stroke = demo.dashed;
 266                     } else {
 267                         demo.stroke = demo.solid;
 268                     }
 269                     drawMenu.setIcon(drawIcons[i]);
 270                     break;
 271                 }
 272             }
 273             if (obj.equals(fillMI[0])) {
 274                 demo.doFill = false;
 275             } else if (obj.equals(drawMI[0])) {
 276                 demo.doDraw = false;
 277             }
 278             if (!demo.animating.running()) {
 279                 demo.repaint();
 280             }
 281         }
 282 
 283         @Override
 284         public Dimension getPreferredSize() {
 285             return new Dimension(200, 36);
 286         }
 287 
 288         @Override
 289         @SuppressWarnings("SleepWhileHoldingLock")
 290         public void run() {
 291             Thread me = Thread.currentThread();
 292             while (thread == me) {
 293                 for (JMenuItem dmi : drawMI) {
 294                     dmi.doClick();
 295                     for (JMenuItem fmi : fillMI) {
 296                         fmi.doClick();
 297                         try {
 298                             Thread.sleep(3000 + (long) (Math.random() * 3000));
 299                         } catch (InterruptedException e) {
 300                             break;
 301                         }
 302                     }
 303                 }
 304             }
 305             thread = null;
 306         }
 307 
 308 
 309         static class PaintedIcon implements Icon {
 310 
 311             Paint paint;
 312 
 313             public PaintedIcon(Paint p) {
 314                 this.paint = p;
 315             }
 316 
 317             @Override
 318             public void paintIcon(Component c, Graphics g, int x, int y) {
 319                 Graphics2D g2 = (Graphics2D) g;
 320                 g2.setPaint(paint);
 321                 g2.fillRect(x, y, getIconWidth(), getIconHeight());
 322                 g2.setColor(GRAY);
 323                 g2.draw3DRect(x, y, getIconWidth() - 1, getIconHeight() - 1,
 324                         true);
 325             }
 326 
 327             @Override
 328             public int getIconWidth() {
 329                 return 12;
 330             }
 331 
 332             @Override
 333             public int getIconHeight() {
 334                 return 12;
 335             }
 336         } // End PaintedIcon class
 337     } // End DemoControls class
 338 } // End BezierAnim class
 339