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.Paint;
  33 
  34 
  35 import static java.awt.Color.BLACK;
  36 import static java.awt.Color.GRAY;
  37 import static java.awt.Color.LIGHT_GRAY;
  38 import static java.awt.Color.WHITE;
  39 import java.awt.Color;
  40 import java.awt.Component;
  41 import java.awt.Dimension;
  42 import java.awt.Graphics;
  43 import java.awt.Graphics2D;
  44 import java.awt.Image;
  45 import java.awt.Rectangle;
  46 import java.awt.TexturePaint;
  47 import java.awt.event.ActionEvent;
  48 import java.awt.event.ActionListener;
  49 import java.awt.image.BufferedImage;
  50 import java2d.AnimatingControlsSurface;
  51 import java2d.CustomControls;
  52 import javax.swing.AbstractButton;
  53 import javax.swing.Icon;
  54 import javax.swing.JComboBox;
  55 import javax.swing.JMenu;
  56 import javax.swing.JMenuBar;
  57 import javax.swing.JMenuItem;
  58 import javax.swing.JToggleButton;
  59 import javax.swing.JToolBar;
  60 import javax.swing.plaf.metal.MetalBorders.ButtonBorder;
  61 
  62 
  63 /**
  64  * TexturePaint animation with controls for transformations.
  65  */
  66 @SuppressWarnings("serial")
  67 public final class TextureAnim extends AnimatingControlsSurface {
  68 
  69     public static final Color colorblend = new Color(0f, 0f, 1f, .5f);
  70     protected static BufferedImage textureImg;
  71     protected int bNum;
  72     protected int tilesize;
  73     private boolean newtexture;
  74     private TexturePaint texturePaint;
  75     private Rectangle tilerect;
  76     private boolean bouncesize = false;
  77     private boolean bouncerect = true;
  78     private boolean rotate = false;
  79     private boolean shearx = false;
  80     private boolean sheary = false;
  81     private boolean showanchor = true;
  82     private AnimVal w, h, x, y, rot, shx, shy;
  83     private static Image[] img = new Image[2];
  84 
  85     public TextureAnim() {
  86         img[0] = getImage("duke.gif");   // 8 bit gif
  87         img[1] = getImage("duke.png");   // 24 bit png
  88 
  89         textureImg = makeImage(32, 0);
  90         tilesize = textureImg.getWidth();
  91         w = new AnimVal(0, 200, 3, 10, tilesize);
  92         h = new AnimVal(0, 200, 3, 10, tilesize);
  93         x = new AnimVal(0, 200, 3, 10, 0);
  94         y = new AnimVal(0, 200, 3, 10, 0);
  95         rot = new AnimVal(-360, 360, 5, 15, 0);
  96         shx = new AnimVal(-50, 50, 3, 10, 0);
  97         shy = new AnimVal(-50, 50, 3, 10, 0);
  98         tilerect = new Rectangle(x.getInt(), y.getInt(),
  99                 w.getInt(), h.getInt());
 100         texturePaint = new TexturePaint(textureImg, tilerect);
 101         setControls(new Component[] { new DemoControls(this) });
 102     }
 103 
 104     protected BufferedImage makeImage(int size, int num) {
 105         newtexture = true;
 106         switch (bNum = num) {
 107             case 0:
 108                 return makeRGBImage(size);
 109             case 1:
 110                 return makeGIFImage(size);
 111             case 2:
 112                 return makePNGImage(size);
 113         }
 114         return null;
 115     }
 116 
 117     private BufferedImage makeRGBImage(int size) {
 118         BufferedImage bi = new BufferedImage(size, size,
 119                 BufferedImage.TYPE_INT_RGB);
 120         Graphics2D big = bi.createGraphics();
 121         big.setColor(WHITE);
 122         big.fillRect(0, 0, size, size);
 123         for (int j = 0; j < size; j++) {
 124             float RED = j / (float) size;
 125             for (int i = 0; i < size; i++) {
 126                 float GREEN = i / (float) size;
 127                 big.setColor(new Color(1.0f - RED, 1.0f - GREEN, 0.0f, 1.0f));
 128                 big.drawLine(i, j, i, j);
 129             }
 130         }
 131         return bi;
 132     }
 133 
 134     private BufferedImage makeGIFImage(int d) {
 135         BufferedImage bi = new BufferedImage(d, d, BufferedImage.TYPE_INT_RGB);
 136         Graphics2D big = bi.createGraphics();
 137         big.drawImage(img[0], 0, 0, d, d, new Color(204, 204, 255), null);
 138         return bi;
 139     }
 140 
 141     private BufferedImage makePNGImage(int d) {
 142         BufferedImage bi = new BufferedImage(d, d, BufferedImage.TYPE_INT_RGB);
 143         Graphics2D big = bi.createGraphics();
 144         big.drawImage(img[1], 0, 0, d, d, LIGHT_GRAY, null);
 145         return bi;
 146     }
 147 
 148     @Override
 149     public void reset(int width, int height) {
 150         x.newlimits(-width / 4, width / 4 - w.getInt());
 151         y.newlimits(-height / 4, height / 4 - h.getInt());
 152     }
 153 
 154     @Override
 155     public void step(int width, int height) {
 156         if (tilesize != textureImg.getWidth()) {
 157             tilesize = textureImg.getWidth();
 158         }
 159         if (bouncesize) {
 160             w.anim();
 161             h.anim();
 162             x.newlimits(-width / 4, width / 4 - w.getInt());
 163             y.newlimits(-height / 4, height / 4 - h.getInt());
 164         } else {
 165             if (w.getInt() != tilesize) {
 166                 w.set(tilesize);
 167                 x.newlimits(-width / 4, width / 4 - w.getInt());
 168             }
 169             if (h.getInt() != tilesize) {
 170                 h.set(tilesize);
 171                 y.newlimits(-height / 4, height / 4 - h.getInt());
 172             }
 173         }
 174         if (bouncerect) {
 175             x.anim();
 176             y.anim();
 177         }
 178         if (newtexture || x.getInt() != tilerect.x || y.getInt() != tilerect.y || w.
 179                 getInt() != tilerect.width || h.getInt() != tilerect.height) {
 180             newtexture = false;
 181             int X = x.getInt();
 182             int Y = y.getInt();
 183             int W = w.getInt();
 184             int H = h.getInt();
 185             tilerect = new Rectangle(X, Y, W, H);
 186             texturePaint = new TexturePaint(textureImg, tilerect);
 187         }
 188     }
 189 
 190     @Override
 191     public void render(int width, int height, Graphics2D g2) {
 192 
 193         g2.translate(width / 2, height / 2);
 194         if (rotate) {
 195             rot.anim();
 196             g2.rotate(Math.toRadians(rot.getFlt()));
 197         } else {
 198             rot.set(0);
 199         }
 200         if (shearx) {
 201             shx.anim();
 202             g2.shear(shx.getFlt() / 100, 0.0f);
 203         } else {
 204             shx.set(0);
 205         }
 206         if (sheary) {
 207             shy.anim();
 208             g2.shear(0.0f, shy.getFlt() / 100);
 209         } else {
 210             shy.set(0);
 211         }
 212         g2.setPaint(texturePaint);
 213         g2.fillRect(-1000, -1000, 2000, 2000);
 214         if (showanchor) {
 215             g2.setColor(BLACK);
 216             g2.setColor(colorblend);
 217             g2.fill(tilerect);
 218         }
 219     }
 220 
 221     public static void main(String[] argv) {
 222         createDemoFrame(new TextureAnim());
 223     }
 224 
 225 
 226     static final class AnimVal {
 227 
 228         float curval;
 229         float lowval;
 230         float highval;
 231         float currate;
 232         float lowrate;
 233         float highrate;
 234 
 235         public AnimVal(int lowval, int highval,
 236                 int lowrate, int highrate) {
 237             this.lowval = lowval;
 238             this.highval = highval;
 239             this.lowrate = lowrate;
 240             this.highrate = highrate;
 241             this.curval = randval(lowval, highval);
 242             this.currate = randval(lowrate, highrate);
 243         }
 244 
 245         public AnimVal(int lowval, int highval,
 246                 int lowrate, int highrate,
 247                 int pos) {
 248             this(lowval, highval, lowrate, highrate);
 249             set(pos);
 250         }
 251 
 252         public float randval(float low, float high) {
 253             return (float) (low + Math.random() * (high - low));
 254         }
 255 
 256         public float getFlt() {
 257             return curval;
 258         }
 259 
 260         public int getInt() {
 261             return (int) curval;
 262         }
 263 
 264         public void anim() {
 265             curval += currate;
 266             clip();
 267         }
 268 
 269         public void set(float val) {
 270             curval = val;
 271             clip();
 272         }
 273 
 274         public void clip() {
 275             if (curval > highval) {
 276                 curval = highval - (curval - highval);
 277                 if (curval < lowval) {
 278                     curval = highval;
 279                 }
 280                 currate = -randval(lowrate, highrate);
 281             } else if (curval < lowval) {
 282                 curval = lowval + (lowval - curval);
 283                 if (curval > highval) {
 284                     curval = lowval;
 285                 }
 286                 currate = randval(lowrate, highrate);
 287             }
 288         }
 289 
 290         public void newlimits(int lowval, int highval) {
 291             this.lowval = lowval;
 292             this.highval = highval;
 293             clip();
 294         }
 295     }  // End AnimVal class
 296 
 297 
 298     final class DemoControls extends CustomControls implements ActionListener {
 299 
 300         TextureAnim demo;
 301         JToolBar toolbar;
 302         JComboBox combo;
 303         JMenu menu;
 304         JMenuItem[] menuitems;
 305         int iconSize = 20;
 306         ButtonBorder buttonBorder = new ButtonBorder();
 307 
 308         @SuppressWarnings("LeakingThisInConstructor")
 309         public DemoControls(TextureAnim demo) {
 310             super(demo.name);
 311             this.demo = demo;
 312             menuitems = new JMenuItem[3];
 313             add(toolbar = new JToolBar());
 314             toolbar.setFloatable(false);
 315             addTool("BO", "bounce", true);
 316             addTool("SA", "show anchor", true);
 317             addTool("RS", "resize", false);
 318             addTool("RO", "rotate", false);
 319             addTool("SX", "shear x", false);
 320             addTool("SY", "shear y", false);
 321             add(combo = new JComboBox());
 322             combo.addActionListener(this);
 323             combo.addItem("8");
 324             combo.addItem("16");
 325             combo.addItem("32");
 326             combo.addItem("64");
 327             combo.addItem("80");
 328             combo.setSelectedIndex(2);
 329 
 330             JMenuBar menuBar = new JMenuBar();
 331             menu = menuBar.add(new JMenu());
 332             for (int i = 0; i < 3; i++) {
 333                 BufferedImage bimg = demo.makeImage(iconSize, i);
 334                 TexturedIcon icon = new TexturedIcon(bimg);
 335                 menuitems[i] = menu.add(new JMenuItem(icon));
 336                 menuitems[i].addActionListener(this);
 337             }
 338             menu.setIcon(menuitems[0].getIcon());
 339             add(menuBar);
 340             demo.bNum = 0;
 341         }
 342 
 343         public void addTool(String str, String toolTip, boolean state) {
 344             JToggleButton b =
 345                     (JToggleButton) toolbar.add(new JToggleButton(str));
 346             b.setBorder(buttonBorder);
 347             b.setFocusPainted(false);
 348             b.setSelected(state);
 349             b.setToolTipText(toolTip);
 350             b.addActionListener(this);
 351             int width = b.getPreferredSize().width+10;
 352             Dimension prefSize = new Dimension(width, 21);
 353             b.setPreferredSize(prefSize);
 354             b.setMaximumSize(prefSize);
 355             b.setMinimumSize(prefSize);
 356         }
 357 
 358         @Override
 359         public void actionPerformed(ActionEvent e) {
 360             Object obj = e.getSource();
 361             if (obj instanceof JComboBox) {
 362                 String selItem = (String) combo.getSelectedItem();
 363                 if (selItem != null) {
 364                     int size = Integer.parseInt(selItem);
 365                     TextureAnim.textureImg = demo.makeImage(size, demo.bNum);
 366                 }
 367             } else if (obj instanceof JMenuItem) {
 368                 for (int i = 0; i < menuitems.length; i++) {
 369                     if (obj.equals(menuitems[i])) {
 370                         TextureAnim.textureImg =
 371                                 demo.makeImage(demo.tilesize, i);
 372                         menu.setIcon(menuitems[i].getIcon());
 373                         break;
 374                     }
 375                 }
 376             } else {
 377                 JToggleButton b = (JToggleButton) obj;
 378                 if (b.getText().equals("BO")) {
 379                     demo.bouncerect = b.isSelected();
 380                 } else if (b.getText().equals("SA")) {
 381                     demo.showanchor = b.isSelected();
 382                 } else if (b.getText().equals("RS")) {
 383                     demo.bouncesize = b.isSelected();
 384                 } else if (b.getText().equals("RO")) {
 385                     demo.rotate = b.isSelected();
 386                 } else if (b.getText().equals("SX")) {
 387                     demo.shearx = b.isSelected();
 388                 } else if (b.getText().equals("SY")) {
 389                     demo.sheary = b.isSelected();
 390                 }
 391             }
 392             if (!demo.animating.running()) {
 393                 demo.repaint();
 394             }
 395         }
 396 
 397         @Override
 398         public Dimension getPreferredSize() {
 399             return new Dimension(200, 41);
 400         }
 401 
 402         @Override
 403         @SuppressWarnings("SleepWhileHoldingLock")
 404         public void run() {
 405             Thread me = Thread.currentThread();
 406             while (thread == me) {
 407                 for (int i = 2; i < toolbar.getComponentCount(); i++) {
 408                     try {
 409                         Thread.sleep(4444);
 410                     } catch (InterruptedException e) {
 411                         return;
 412                     }
 413                     ((AbstractButton) toolbar.getComponentAtIndex(i)).doClick();
 414                 }
 415             }
 416             thread = null;
 417         }
 418 
 419 
 420         class TexturedIcon implements Icon {
 421 
 422             BufferedImage bi;
 423 
 424             public TexturedIcon(BufferedImage bi) {
 425                 this.bi = bi;
 426             }
 427 
 428             @Override
 429             public void paintIcon(Component c, Graphics g, int x, int y) {
 430                 Graphics2D g2 = (Graphics2D) g;
 431                 Rectangle r = new Rectangle(x, y, iconSize, iconSize);
 432                 g2.setPaint(new TexturePaint(bi, r));
 433                 g2.fillRect(x, y, iconSize, iconSize);
 434                 g2.setColor(GRAY);
 435                 g2.draw3DRect(x, y, iconSize - 1, iconSize - 1, true);
 436             }
 437 
 438             @Override
 439             public int getIconWidth() {
 440                 return iconSize;
 441             }
 442 
 443             @Override
 444             public int getIconHeight() {
 445                 return iconSize;
 446             }
 447         } // End TexturedIcon class
 448     } // End DemoControls class
 449 } // End TextureAnim class
 450