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.Mix;
  33 
  34 
  35 import static java.awt.Color.LIGHT_GRAY;
  36 import static java.awt.Color.WHITE;
  37 import static java.lang.Math.random;
  38 import java.awt.AlphaComposite;
  39 import java.awt.BasicStroke;
  40 import java.awt.Color;
  41 import java.awt.Component;
  42 import java.awt.Dimension;
  43 import java.awt.Font;
  44 import java.awt.FontMetrics;
  45 import java.awt.Graphics2D;
  46 import java.awt.Image;
  47 import java.awt.RenderingHints;
  48 import java.awt.event.ActionEvent;
  49 import java.awt.event.ActionListener;
  50 import java.awt.geom.GeneralPath;
  51 import java.awt.geom.Path2D;
  52 import java.awt.geom.PathIterator;
  53 import java.awt.image.BufferedImage;
  54 import java.io.BufferedReader;
  55 import java.io.FileReader;
  56 import java.util.ArrayList;
  57 import java.util.List;
  58 import java.util.logging.Level;
  59 import java.util.logging.Logger;
  60 import java2d.AnimatingControlsSurface;
  61 import java2d.CustomControls;
  62 import javax.swing.AbstractButton;
  63 import javax.swing.JToggleButton;
  64 import javax.swing.JToolBar;
  65 
  66 
  67 /**
  68  * Animated Bezier Curve shape with images at the control points.
  69  * README.txt file scrolling up. Composited Image fading in and out.
  70  */
  71 @SuppressWarnings("serial")
  72 public class BezierScroller extends AnimatingControlsSurface {
  73 
  74     private static String[] appletStrs = { " ", "J2Ddemo",
  75         "BezierScroller - Animated Bezier Curve shape with images",
  76         "For README.txt file scrolling run in application mode", " " };
  77     private static final int NUMPTS = 6;
  78     private static Color greenBlend = new Color(0, 255, 0, 100);
  79     private static Color blueBlend = new Color(0, 0, 255, 100);
  80     private static Font font = new Font(Font.SERIF, Font.PLAIN, 12);
  81     private static BasicStroke bs = new BasicStroke(3.0f);
  82     private static Image hotj_img;
  83     private static BufferedImage img;
  84     private static final int UP = 0;
  85     private static final int DOWN = 1;
  86     private float[] animpts = new float[NUMPTS * 2];
  87     private float[] deltas = new float[NUMPTS * 2];
  88     private BufferedReader reader;
  89     private int nStrs;
  90     private int strH;
  91     private int yy, ix, iy, imgX;
  92     private List<String> vector, appletVector;
  93     private float alpha = 0.2f;
  94     private int alphaDirection;
  95     protected boolean doImage, doShape, doText;
  96     protected boolean buttonToggle;
  97 
  98     /*
  99      * Using this to scale down globe.png since we want a smaller version,
 100      * I know it is 100 x 160 and has a transparent pixel.
 101      */
 102     private Image scaled(Image src) {
 103         int sw = src.getWidth(null);
 104         int sh = src.getHeight(null);
 105         int dw = sw/5;
 106         int dh = sh/5;
 107         BufferedImage bi =
 108             new BufferedImage(dw, dh, BufferedImage.TYPE_INT_ARGB);
 109         Graphics2D g2d = bi.createGraphics();
 110         g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION,
 111                              RenderingHints.VALUE_INTERPOLATION_BICUBIC);
 112         g2d.drawImage(src, 0, 0, dw, dh, 0, 0, sw, sh, null);
 113         g2d.dispose();
 114         return bi;
 115     }
 116 
 117     @SuppressWarnings("LeakingThisInConstructor")
 118     public BezierScroller() {
 119         setBackground(WHITE);
 120         doShape = doText = true;
 121         hotj_img = scaled(getImage("globe.png"));
 122         Image image = getImage("jumptojavastrip.png");
 123         int iw = image.getWidth(this);
 124         int ih = image.getHeight(this);
 125         img = new BufferedImage(iw, ih, BufferedImage.TYPE_INT_RGB);
 126         img.createGraphics().drawImage(image, 0, 0, this);
 127         setControls(new Component[] { new DemoControls(this) });
 128     }
 129 
 130     public void animate(float[] pts, float[] deltas, int index, int limit) {
 131         float newpt = pts[index] + deltas[index];
 132         if (newpt <= 0) {
 133             newpt = -newpt;
 134             deltas[index] = (float) (random() * 4.0 + 2.0);
 135         } else if (newpt >= limit) {
 136             newpt = 2.0f * limit - newpt;
 137             deltas[index] = -(float) (random() * 4.0 + 2.0);
 138         }
 139         pts[index] = newpt;
 140     }
 141 
 142     public void getFile() {
 143         try {
 144             String fName = "README.txt";
 145             if ((reader = new BufferedReader(new FileReader(fName))) != null) {
 146                 getLine();
 147             }
 148         } catch (Exception e) {
 149             reader = null;
 150         }
 151         if (reader == null) {
 152             appletVector = new ArrayList<String>(100);
 153             for (int i = 0; i < 100; i++) {
 154                 appletVector.add(appletStrs[i % appletStrs.length]);
 155             }
 156             getLine();
 157         }
 158         buttonToggle = true;
 159     }
 160 
 161     public String getLine() {
 162         String str = null;
 163         if (reader != null) {
 164             try {
 165                 if ((str = reader.readLine()) != null) {
 166                     if (str.length() == 0) {
 167                         str = " ";
 168                     }
 169                     vector.add(str);
 170                 }
 171             } catch (Exception e) {
 172                 Logger.getLogger(BezierScroller.class.getName()).log(
 173                         Level.SEVERE,
 174                         null, e);
 175                 reader = null;
 176             }
 177         } else {
 178             if (!appletVector.isEmpty()) {
 179                 vector.add(str = appletVector.remove(0));
 180             }
 181         }
 182         return str;
 183     }
 184 
 185     @Override
 186     public void reset(int w, int h) {
 187         for (int i = 0; i < animpts.length; i += 2) {
 188             animpts[i + 0] = (float) (random() * w);
 189             animpts[i + 1] = (float) (random() * h);
 190             deltas[i + 0] = (float) (random() * 6.0 + 4.0);
 191             deltas[i + 1] = (float) (random() * 6.0 + 4.0);
 192             if (animpts[i + 0] > w / 2.0f) {
 193                 deltas[i + 0] = -deltas[i + 0];
 194             }
 195             if (animpts[i + 1] > h / 2.0f) {
 196                 deltas[i + 1] = -deltas[i + 1];
 197             }
 198         }
 199         FontMetrics fm = getFontMetrics(font);
 200         strH = fm.getAscent() + fm.getDescent();
 201         nStrs = h / strH + 2;
 202         vector = new ArrayList<String>(nStrs);
 203         ix = (int) (random() * (w - 80));
 204         iy = (int) (random() * (h - 80));
 205     }
 206 
 207     @Override
 208     public void step(int w, int h) {
 209         if (doText && vector.isEmpty()) {
 210             getFile();
 211         }
 212         if (doText) {
 213             String s = getLine();
 214             if (s == null || vector.size() == nStrs && !vector.isEmpty()) {
 215                 vector.remove(0);
 216             }
 217             yy = (s == null) ? 0 : h - vector.size() * strH;
 218         }
 219 
 220         for (int i = 0; i < animpts.length && doShape; i += 2) {
 221             animate(animpts, deltas, i + 0, w);
 222             animate(animpts, deltas, i + 1, h);
 223         }
 224         if (doImage && alphaDirection == UP) {
 225             if ((alpha += 0.025) > .99) {
 226                 alphaDirection = DOWN;
 227                 alpha = 1.0f;
 228             }
 229         } else if (doImage && alphaDirection == DOWN) {
 230             if ((alpha -= .02) < 0.01) {
 231                 alphaDirection = UP;
 232                 alpha = 0;
 233                 ix = (int) (random() * (w - 80));
 234                 iy = (int) (random() * (h - 80));
 235             }
 236         }
 237         if (doImage) {
 238             if ((imgX += 80) == 800) {
 239                 imgX = 0;
 240             }
 241         }
 242     }
 243 
 244     @Override
 245     public void render(int w, int h, Graphics2D g2) {
 246 
 247         if (doText) {
 248             g2.setColor(LIGHT_GRAY);
 249             g2.setFont(font);
 250             float y = yy;
 251             //for (int i = 0; i < vector.size(); i++) {
 252             for (String string : vector) {
 253                 g2.drawString(string, 1, y += strH);
 254             }
 255         }
 256 
 257         if (doShape) {
 258             float[] ctrlpts = animpts;
 259             int len = ctrlpts.length;
 260             float prevx = ctrlpts[len - 2];
 261             float prevy = ctrlpts[len - 1];
 262             float curx = ctrlpts[0];
 263             float cury = ctrlpts[1];
 264             float midx = (curx + prevx) / 2.0f;
 265             float midy = (cury + prevy) / 2.0f;
 266             GeneralPath gp = new GeneralPath(Path2D.WIND_NON_ZERO);
 267             gp.moveTo(midx, midy);
 268             for (int i = 2; i <= ctrlpts.length; i += 2) {
 269                 float x1 = (midx + curx) / 2.0f;
 270                 float y1 = (midy + cury) / 2.0f;
 271                 prevx = curx;
 272                 prevy = cury;
 273                 if (i < ctrlpts.length) {
 274                     curx = ctrlpts[i + 0];
 275                     cury = ctrlpts[i + 1];
 276                 } else {
 277                     curx = ctrlpts[0];
 278                     cury = ctrlpts[1];
 279                 }
 280                 midx = (curx + prevx) / 2.0f;
 281                 midy = (cury + prevy) / 2.0f;
 282                 float x2 = (prevx + midx) / 2.0f;
 283                 float y2 = (prevy + midy) / 2.0f;
 284                 gp.curveTo(x1, y1, x2, y2, midx, midy);
 285             }
 286             gp.closePath();
 287 
 288             g2.setColor(blueBlend);
 289             g2.setStroke(bs);
 290             g2.draw(gp);
 291             g2.setColor(greenBlend);
 292             g2.fill(gp);
 293 
 294             PathIterator pi = gp.getPathIterator(null);
 295             float[] pts = new float[6];
 296             while (!pi.isDone()) {
 297                 if (pi.currentSegment(pts) == PathIterator.SEG_CUBICTO) {
 298                     g2.drawImage(hotj_img, (int) pts[0], (int) pts[1], this);
 299                 }
 300                 pi.next();
 301             }
 302         }
 303 
 304         if (doImage) {
 305             AlphaComposite ac = AlphaComposite.getInstance(
 306                     AlphaComposite.SRC_OVER, alpha);
 307             g2.setComposite(ac);
 308             g2.drawImage(img.getSubimage(imgX, 0, 80, 80), ix, iy, this);
 309         }
 310     }
 311 
 312     public static void main(String[] argv) {
 313         createDemoFrame(new BezierScroller());
 314     }
 315 
 316 
 317     static final class DemoControls extends CustomControls implements
 318             ActionListener {
 319 
 320         BezierScroller demo;
 321         JToolBar toolbar;
 322 
 323         public DemoControls(BezierScroller demo) {
 324             super(demo.name);
 325             this.demo = demo;
 326             add(toolbar = new JToolBar());
 327             toolbar.setFloatable(false);
 328             addTool("Image", false);
 329             addTool("Shape", true);
 330             addTool("Text", true);
 331         }
 332 
 333         public void addTool(String str, boolean state) {
 334             JToggleButton b =
 335                     (JToggleButton) toolbar.add(new JToggleButton(str));
 336             b.setFocusPainted(false);
 337             b.setSelected(state);
 338             b.addActionListener(this);
 339             int width = b.getPreferredSize().width;
 340             Dimension prefSize = new Dimension(width, 21);
 341             b.setPreferredSize(prefSize);
 342             b.setMaximumSize(prefSize);
 343             b.setMinimumSize(prefSize);
 344         }
 345 
 346         @Override
 347         public void actionPerformed(ActionEvent e) {
 348             JToggleButton b = (JToggleButton) e.getSource();
 349             if (b.getText().equals("Image")) {
 350                 demo.doImage = b.isSelected();
 351             } else if (b.getText().equals("Shape")) {
 352                 demo.doShape = b.isSelected();
 353             } else {
 354                 demo.doText = b.isSelected();
 355             }
 356             if (!demo.animating.running()) {
 357                 demo.repaint();
 358             }
 359         }
 360 
 361         @Override
 362         public Dimension getPreferredSize() {
 363             return new Dimension(200, 40);
 364         }
 365 
 366         @Override
 367         @SuppressWarnings("SleepWhileHoldingLock")
 368         public void run() {
 369             Thread me = Thread.currentThread();
 370             int i = 0;
 371             while (thread == me) {
 372                 try {
 373                     Thread.sleep(250);
 374                 } catch (InterruptedException e) {
 375                     return;
 376                 }
 377                 if (demo.buttonToggle) {
 378                     ((AbstractButton) toolbar.getComponentAtIndex(i++ % 2)).
 379                             doClick();
 380                     demo.buttonToggle = false;
 381                 }
 382             }
 383             thread = null;
 384         }
 385     } // End DemoControls
 386 } // End BezierScroller
 387