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 }