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 java.awt.Color;
  36 import java.awt.Component;
  37 import java.awt.Dimension;
  38 import java.awt.GradientPaint;
  39 import java.awt.Graphics2D;
  40 import java.awt.LinearGradientPaint;
  41 import java.awt.MultipleGradientPaint.CycleMethod;
  42 import java.awt.Paint;
  43 import java.awt.RadialGradientPaint;
  44 import java.awt.event.ActionEvent;
  45 import java.awt.event.ActionListener;
  46 import java.awt.geom.Point2D;
  47 import java2d.AnimatingControlsSurface;
  48 import java2d.CustomControls;
  49 import javax.swing.JComboBox;
  50 
  51 
  52 /**
  53  * GradientPaint animation.
  54  */
  55 @SuppressWarnings("serial")
  56 public class GradAnim extends AnimatingControlsSurface {
  57 
  58     private static final int BASIC_GRADIENT = 0;
  59     private static final int LINEAR_GRADIENT = 1;
  60     private static final int RADIAL_GRADIENT = 2;
  61     private static final int FOCUS_GRADIENT = 3;
  62     private static final int MAX_HUE = 256 * 6;
  63     private animval x1, y1, x2, y2;
  64     private int hue = (int) (Math.random() * MAX_HUE);
  65     private int gradientType;
  66 
  67     public GradAnim() {
  68         setBackground(Color.white);
  69         setControls(new Component[] { new DemoControls(this) });
  70         x1 = new animval(0, 300, 2, 10);
  71         y1 = new animval(0, 300, 2, 10);
  72         x2 = new animval(0, 300, 2, 10);
  73         y2 = new animval(0, 300, 2, 10);
  74         gradientType = BASIC_GRADIENT;
  75     }
  76 
  77     @Override
  78     public void reset(int w, int h) {
  79         x1.newlimits(0, w);
  80         y1.newlimits(0, h);
  81         x2.newlimits(0, w);
  82         y2.newlimits(0, h);
  83     }
  84 
  85     @Override
  86     public void step(int w, int h) {
  87         x1.anim();
  88         y1.anim();
  89         x2.anim();
  90         y2.anim();
  91         hue = (hue + (int) (Math.random() * 10)) % MAX_HUE;
  92     }
  93 
  94     public static Color getColor(int hue) {
  95         int leg = (hue / 256) % 6;
  96         int step = (hue % 256) * 2;
  97         int falling = (step < 256) ? 255 : 511 - step;
  98         int rising = (step < 256) ? step : 255;
  99         int r, g, b;
 100         r = g = b = 0;
 101         switch (leg) {
 102             case 0:
 103                 r = 255;
 104                 break;
 105             case 1:
 106                 r = falling;
 107                 g = rising;
 108                 break;
 109             case 2:
 110                 g = 255;
 111                 break;
 112             case 3:
 113                 g = falling;
 114                 b = rising;
 115                 break;
 116             case 4:
 117                 b = 255;
 118                 break;
 119             case 5:
 120                 b = falling;
 121                 r = rising;
 122                 break;
 123         }
 124         return new Color(r, g, b);
 125     }
 126 
 127     @Override
 128     public void render(int w, int h, Graphics2D g2) {
 129         float fx1 = x1.getFlt();
 130         float fy1 = y1.getFlt();
 131         float fx2 = x2.getFlt();
 132         float fy2 = y2.getFlt();
 133 
 134         if ((fx1 == fx2) && (fy1 == fy2)) {
 135             // just to prevent the points from being coincident
 136             fx2++;
 137             fy2++;
 138         }
 139 
 140         Color c1 = getColor(hue);
 141         Color c2 = getColor(hue + 256 * 3);
 142         Paint gp;
 143 
 144         switch (gradientType) {
 145             case BASIC_GRADIENT:
 146             default:
 147                 gp = new GradientPaint(fx1, fy1, c1,
 148                         fx2, fy2, c2,
 149                         true);
 150                 break;
 151             case LINEAR_GRADIENT: {
 152                 float[] fractions = new float[] { 0.0f, 0.2f, 1.0f };
 153                 Color c3 = getColor(hue + 256 * 2);
 154                 Color[] colors = new Color[] { c1, c2, c3 };
 155                 gp = new LinearGradientPaint(fx1, fy1,
 156                         fx2, fy2,
 157                         fractions, colors,
 158                         CycleMethod.REFLECT);
 159             }
 160             break;
 161 
 162             case RADIAL_GRADIENT: {
 163                 float[] fractions = { 0.0f, 0.2f, 0.8f, 1.0f };
 164                 Color c3 = getColor(hue + 256 * 2);
 165                 Color c4 = getColor(hue + 256 * 4);
 166                 Color[] colors = new Color[] { c1, c2, c3, c4 };
 167                 float radius = (float) Point2D.distance(fx1, fy1, fx2, fy2);
 168                 gp = new RadialGradientPaint(fx1, fy1, radius,
 169                         fractions, colors,
 170                         CycleMethod.REFLECT);
 171             }
 172             break;
 173 
 174             case FOCUS_GRADIENT: {
 175                 float[] fractions = { 0.0f, 0.2f, 0.8f, 1.0f };
 176                 Color c3 = getColor(hue + 256 * 4);
 177                 Color c4 = getColor(hue + 256 * 2);
 178                 Color[] colors = new Color[] { c1, c2, c3, c4 };
 179                 float radius = (float) Point2D.distance(fx1, fy1, fx2, fy2);
 180                 float max = Math.max(w, h);
 181                 // This function will map the smallest radius to
 182                 // max/10 when the points are next to each other,
 183                 // max when the points are max distance apart,
 184                 // and >max when they are further apart (in which
 185                 // case the focus clipping code in RGP will clip
 186                 // the focus to be inside the radius).
 187                 radius = max * (((radius / max) * 0.9f) + 0.1f);
 188                 gp = new RadialGradientPaint(fx2, fy2, radius,
 189                         fx1, fy1,
 190                         fractions, colors,
 191                         CycleMethod.REPEAT);
 192             }
 193             break;
 194         }
 195         g2.setPaint(gp);
 196         g2.fillRect(0, 0, w, h);
 197         g2.setColor(Color.yellow);
 198         g2.drawLine(x1.getInt(), y1.getInt(), x2.getInt(), y2.getInt());
 199     }
 200 
 201 
 202     public final class animval {
 203 
 204         float curval;
 205         float lowval;
 206         float highval;
 207         float currate;
 208         float lowrate;
 209         float highrate;
 210 
 211         public animval(int lowval, int highval,
 212                 int lowrate, int highrate) {
 213             this.lowval = lowval;
 214             this.highval = highval;
 215             this.lowrate = lowrate;
 216             this.highrate = highrate;
 217             this.curval = randval(lowval, highval);
 218             this.currate = randval(lowrate, highrate);
 219         }
 220 
 221         public float randval(float low, float high) {
 222             return (float) (low + Math.random() * (high - low));
 223         }
 224 
 225         public float getFlt() {
 226             return curval;
 227         }
 228 
 229         public int getInt() {
 230             return (int) curval;
 231         }
 232 
 233         public void anim() {
 234             curval += currate;
 235             clip();
 236         }
 237 
 238         public void clip() {
 239             if (curval > highval) {
 240                 curval = highval - (curval - highval);
 241                 if (curval < lowval) {
 242                     curval = highval;
 243                 }
 244                 currate = -randval(lowrate, highrate);
 245             } else if (curval < lowval) {
 246                 curval = lowval + (lowval - curval);
 247                 if (curval > highval) {
 248                     curval = lowval;
 249                 }
 250                 currate = randval(lowrate, highrate);
 251             }
 252         }
 253 
 254         public void newlimits(int lowval, int highval) {
 255             this.lowval = lowval;
 256             this.highval = highval;
 257             clip();
 258         }
 259     }
 260 
 261     public static void main(String[] argv) {
 262         createDemoFrame(new GradAnim());
 263     }
 264 
 265 
 266     class DemoControls extends CustomControls implements ActionListener {
 267 
 268         GradAnim demo;
 269         JComboBox<String> combo;
 270 
 271         @SuppressWarnings("LeakingThisInConstructor")
 272         public DemoControls(GradAnim demo) {
 273             super(demo.name);
 274             this.demo = demo;
 275             combo = new JComboBox<>();
 276             combo.addActionListener(this);
 277             combo.addItem("2-color GradientPaint");
 278             combo.addItem("3-color LinearGradientPaint");
 279             combo.addItem("4-color RadialGradientPaint");
 280             combo.addItem("4-color RadialGradientPaint with focus");
 281             combo.setSelectedIndex(0);
 282             add(combo);
 283         }
 284 
 285         @Override
 286         public void actionPerformed(ActionEvent e) {
 287             int index = combo.getSelectedIndex();
 288             if (index >= 0) {
 289                 demo.gradientType = index;
 290             }
 291             if (!demo.animating.running()) {
 292                 demo.repaint();
 293             }
 294         }
 295 
 296         @Override
 297         public Dimension getPreferredSize() {
 298             return new Dimension(200, 41);
 299         }
 300 
 301         @Override
 302         @SuppressWarnings("SleepWhileHoldingLock")
 303         public void run() {
 304             Thread me = Thread.currentThread();
 305             while (thread == me) {
 306                 for (int i = 0; i < combo.getItemCount(); i++) {
 307                     combo.setSelectedIndex(i);
 308                     try {
 309                         Thread.sleep(4444);
 310                     } catch (InterruptedException e) {
 311                         return;
 312                     }
 313                 }
 314             }
 315             thread = null;
 316         }
 317     }
 318 }