/* * * Copyright (c) 2007, 2018, Oracle and/or its affiliates. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * - Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * - Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * - Neither the name of Oracle nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package java2d.demos.Paint; import java.awt.Color; import java.awt.Component; import java.awt.Dimension; import java.awt.GradientPaint; import java.awt.Graphics2D; import java.awt.LinearGradientPaint; import java.awt.MultipleGradientPaint.CycleMethod; import java.awt.Paint; import java.awt.RadialGradientPaint; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.Point2D; import java2d.AnimatingControlsSurface; import java2d.CustomControls; import javax.swing.JComboBox; /** * GradientPaint animation. */ @SuppressWarnings("serial") public class GradAnim extends AnimatingControlsSurface { private static final int BASIC_GRADIENT = 0; private static final int LINEAR_GRADIENT = 1; private static final int RADIAL_GRADIENT = 2; private static final int FOCUS_GRADIENT = 3; private static final int MAX_HUE = 256 * 6; private animval x1, y1, x2, y2; private int hue = (int) (Math.random() * MAX_HUE); private int gradientType; public GradAnim() { setBackground(Color.white); setControls(new Component[] { new DemoControls(this) }); x1 = new animval(0, 300, 2, 10); y1 = new animval(0, 300, 2, 10); x2 = new animval(0, 300, 2, 10); y2 = new animval(0, 300, 2, 10); gradientType = BASIC_GRADIENT; } @Override public void reset(int w, int h) { x1.newlimits(0, w); y1.newlimits(0, h); x2.newlimits(0, w); y2.newlimits(0, h); } @Override public void step(int w, int h) { x1.anim(); y1.anim(); x2.anim(); y2.anim(); hue = (hue + (int) (Math.random() * 10)) % MAX_HUE; } public static Color getColor(int hue) { int leg = (hue / 256) % 6; int step = (hue % 256) * 2; int falling = (step < 256) ? 255 : 511 - step; int rising = (step < 256) ? step : 255; int r, g, b; r = g = b = 0; switch (leg) { case 0: r = 255; break; case 1: r = falling; g = rising; break; case 2: g = 255; break; case 3: g = falling; b = rising; break; case 4: b = 255; break; case 5: b = falling; r = rising; break; } return new Color(r, g, b); } @Override public void render(int w, int h, Graphics2D g2) { float fx1 = x1.getFlt(); float fy1 = y1.getFlt(); float fx2 = x2.getFlt(); float fy2 = y2.getFlt(); if ((fx1 == fx2) && (fy1 == fy2)) { // just to prevent the points from being coincident fx2++; fy2++; } Color c1 = getColor(hue); Color c2 = getColor(hue + 256 * 3); Paint gp; switch (gradientType) { case BASIC_GRADIENT: default: gp = new GradientPaint(fx1, fy1, c1, fx2, fy2, c2, true); break; case LINEAR_GRADIENT: { float[] fractions = new float[] { 0.0f, 0.2f, 1.0f }; Color c3 = getColor(hue + 256 * 2); Color[] colors = new Color[] { c1, c2, c3 }; gp = new LinearGradientPaint(fx1, fy1, fx2, fy2, fractions, colors, CycleMethod.REFLECT); } break; case RADIAL_GRADIENT: { float[] fractions = { 0.0f, 0.2f, 0.8f, 1.0f }; Color c3 = getColor(hue + 256 * 2); Color c4 = getColor(hue + 256 * 4); Color[] colors = new Color[] { c1, c2, c3, c4 }; float radius = (float) Point2D.distance(fx1, fy1, fx2, fy2); gp = new RadialGradientPaint(fx1, fy1, radius, fractions, colors, CycleMethod.REFLECT); } break; case FOCUS_GRADIENT: { float[] fractions = { 0.0f, 0.2f, 0.8f, 1.0f }; Color c3 = getColor(hue + 256 * 4); Color c4 = getColor(hue + 256 * 2); Color[] colors = new Color[] { c1, c2, c3, c4 }; float radius = (float) Point2D.distance(fx1, fy1, fx2, fy2); float max = Math.max(w, h); // This function will map the smallest radius to // max/10 when the points are next to each other, // max when the points are max distance apart, // and >max when they are further apart (in which // case the focus clipping code in RGP will clip // the focus to be inside the radius). radius = max * (((radius / max) * 0.9f) + 0.1f); gp = new RadialGradientPaint(fx2, fy2, radius, fx1, fy1, fractions, colors, CycleMethod.REPEAT); } break; } g2.setPaint(gp); g2.fillRect(0, 0, w, h); g2.setColor(Color.yellow); g2.drawLine(x1.getInt(), y1.getInt(), x2.getInt(), y2.getInt()); } public final class animval { float curval; float lowval; float highval; float currate; float lowrate; float highrate; public animval(int lowval, int highval, int lowrate, int highrate) { this.lowval = lowval; this.highval = highval; this.lowrate = lowrate; this.highrate = highrate; this.curval = randval(lowval, highval); this.currate = randval(lowrate, highrate); } public float randval(float low, float high) { return (float) (low + Math.random() * (high - low)); } public float getFlt() { return curval; } public int getInt() { return (int) curval; } public void anim() { curval += currate; clip(); } public void clip() { if (curval > highval) { curval = highval - (curval - highval); if (curval < lowval) { curval = highval; } currate = -randval(lowrate, highrate); } else if (curval < lowval) { curval = lowval + (lowval - curval); if (curval > highval) { curval = lowval; } currate = randval(lowrate, highrate); } } public void newlimits(int lowval, int highval) { this.lowval = lowval; this.highval = highval; clip(); } } public static void main(String[] argv) { createDemoFrame(new GradAnim()); } class DemoControls extends CustomControls implements ActionListener { GradAnim demo; JComboBox combo; @SuppressWarnings("LeakingThisInConstructor") public DemoControls(GradAnim demo) { super(demo.name); this.demo = demo; combo = new JComboBox<>(); combo.addActionListener(this); combo.addItem("2-color GradientPaint"); combo.addItem("3-color LinearGradientPaint"); combo.addItem("4-color RadialGradientPaint"); combo.addItem("4-color RadialGradientPaint with focus"); combo.setSelectedIndex(0); add(combo); } @Override public void actionPerformed(ActionEvent e) { int index = combo.getSelectedIndex(); if (index >= 0) { demo.gradientType = index; } if (!demo.animating.running()) { demo.repaint(); } } @Override public Dimension getPreferredSize() { return new Dimension(200, 41); } @Override @SuppressWarnings("SleepWhileHoldingLock") public void run() { Thread me = Thread.currentThread(); while (thread == me) { for (int i = 0; i < combo.getItemCount(); i++) { combo.setSelectedIndex(i); try { Thread.sleep(4444); } catch (InterruptedException e) { return; } } } thread = null; } } }