1 /* 2 * Copyright (c) 2010, 2013, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package javafx.scene.effect; 27 28 import javafx.beans.property.DoubleProperty; 29 import javafx.beans.property.DoublePropertyBase; 30 import javafx.beans.property.ObjectProperty; 31 import javafx.scene.Node; 32 33 import com.sun.javafx.util.Utils; 34 import com.sun.javafx.effect.EffectDirtyBits; 35 import com.sun.javafx.geom.BaseBounds; 36 import com.sun.javafx.geom.transform.BaseTransform; 37 import com.sun.javafx.scene.BoundsAccessor; 38 39 40 /** 41 * A motion blur effect using a Gaussian convolution kernel, with a 42 * configurable radius and angle. 43 * 44 * <p> 45 * Example: 46 * <pre><code> 47 * MotionBlur motionBlur = new MotionBlur(); 48 * motionBlur.setRadius(30); 49 * motionBlur.setAngle(-15.0); 50 * 51 * Text text = new Text(); 52 * text.setX(20.0); 53 * text.setY(100.0); 54 * text.setText("Motion!"); 55 * text.setFill(Color.web("0x3b596d")); 56 * text.setFont(Font.font(null, FontWeight.BOLD, 60)); 57 * text.setEffect(motionBlur); 58 * </pre></code> 59 * <p> 60 * The code above produces the following: 61 * </p> 62 * <p> 63 * <img src="doc-files/motionblur.png"/> 64 * </p> 65 * @since JavaFX 2.0 66 */ 67 public class MotionBlur extends Effect { 68 /** 69 * Creates a new instance of MotionBlur with default parameters. 70 */ 71 public MotionBlur() {} 72 73 /** 74 * Creates a new instance of MotionBlur with the specified angle and radius. 75 * @param angle the angle of the motion effect, in degrees 76 * @param radius the radius of the blur kernel 77 * @since JavaFX 2.1 78 */ 79 public MotionBlur(double angle, double radius) { 80 setAngle(angle); 81 setRadius(radius); 82 } 83 84 @Override 85 com.sun.scenario.effect.MotionBlur impl_createImpl() { 86 return new com.sun.scenario.effect.MotionBlur(); 87 }; 88 /** 89 * The input for this {@code Effect}. 90 * If set to {@code null}, or left unspecified, a graphical image of 91 * the {@code Node} to which the {@code Effect} is attached will be 92 * used as the input. 93 * @defaultValue null 94 */ 95 private ObjectProperty<Effect> input; 96 97 98 public final void setInput(Effect value) { 99 inputProperty().set(value); 100 } 101 102 public final Effect getInput() { 103 return input == null ? null : input.get(); 104 } 105 106 public final ObjectProperty<Effect> inputProperty() { 107 if (input == null) { 108 input = new EffectInputProperty("input"); 109 } 110 return input; 111 } 112 113 @Override 114 boolean impl_checkChainContains(Effect e) { 115 Effect localInput = getInput(); 116 if (localInput == null) 117 return false; 118 if (localInput == e) 119 return true; 120 return localInput.impl_checkChainContains(e); 121 } 122 123 /** 124 * The radius of the blur kernel. 125 * <pre> 126 * Min: 0.0 127 * Max: 63.0 128 * Default: 10.0 129 * Identity: 0.0 130 * </pre> 131 * @defaultValue 10.0 132 */ 133 private DoubleProperty radius; 134 135 136 public final void setRadius(double value) { 137 radiusProperty().set(value); 138 } 139 140 public final double getRadius() { 141 return radius == null ? 10 : radius.get(); 142 } 143 144 public final DoubleProperty radiusProperty() { 145 if (radius == null) { 146 radius = new DoublePropertyBase(10) { 147 148 @Override 149 public void invalidated() { 150 markDirty(EffectDirtyBits.EFFECT_DIRTY); 151 effectBoundsChanged(); 152 } 153 154 @Override 155 public Object getBean() { 156 return MotionBlur.this; 157 } 158 159 @Override 160 public String getName() { 161 return "radius"; 162 } 163 }; 164 } 165 return radius; 166 } 167 168 /** 169 * The angle of the motion effect, in degrees. 170 * <pre> 171 * Min: n/a 172 * Max: n/a 173 * Default: 0.0 174 * Identity: n/a 175 * </pre> 176 * @defaultValue 0.0 177 */ 178 private DoubleProperty angle; 179 180 181 public final void setAngle(double value) { 182 angleProperty().set(value); 183 } 184 185 public final double getAngle() { 186 return angle == null ? 0 : angle.get(); 187 } 188 189 public final DoubleProperty angleProperty() { 190 if (angle == null) { 191 angle = new DoublePropertyBase() { 192 193 @Override 194 public void invalidated() { 195 markDirty(EffectDirtyBits.EFFECT_DIRTY); 196 effectBoundsChanged(); 197 } 198 199 @Override 200 public Object getBean() { 201 return MotionBlur.this; 202 } 203 204 @Override 205 public String getName() { 206 return "angle"; 207 } 208 }; 209 } 210 return angle; 211 } 212 213 private float getClampedRadius() { 214 return (float)Utils.clamp(0, getRadius(), 63); 215 } 216 217 @Override 218 void impl_update() { 219 Effect localInput = getInput(); 220 if (localInput != null) { 221 localInput.impl_sync(); 222 } 223 224 com.sun.scenario.effect.MotionBlur peer = 225 (com.sun.scenario.effect.MotionBlur) impl_getImpl(); 226 peer.setInput(localInput == null ? null : localInput.impl_getImpl()); 227 peer.setRadius(getClampedRadius()); 228 peer.setAngle((float)Math.toRadians(getAngle())); 229 } 230 231 private int getHPad() { 232 return (int) Math.ceil(Math.abs(Math.cos(Math.toRadians(getAngle()))) 233 * getClampedRadius()); 234 } 235 236 private int getVPad() { 237 return (int) Math.ceil(Math.abs(Math.sin(Math.toRadians(getAngle()))) 238 * getClampedRadius()); 239 } 240 241 /** 242 * @treatAsPrivate implementation detail 243 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 244 */ 245 @Deprecated 246 @Override 247 public BaseBounds impl_getBounds(BaseBounds bounds, 248 BaseTransform tx, 249 Node node, 250 BoundsAccessor boundsAccessor) { 251 bounds = getInputBounds(bounds, 252 BaseTransform.IDENTITY_TRANSFORM, 253 node, boundsAccessor, 254 getInput()); 255 256 int hpad = getHPad(); 257 int vpad = getVPad(); 258 bounds = bounds.deriveWithPadding(hpad, vpad, 0); 259 260 return transformBounds(tx, bounds); 261 } 262 263 /** 264 * @treatAsPrivate implementation detail 265 * @deprecated This is an internal API that is not intended for use and will be removed in the next version 266 */ 267 @Deprecated 268 @Override 269 public Effect impl_copy() { 270 MotionBlur mb = new MotionBlur(this.getAngle(), this.getRadius()); 271 mb.setInput(mb.getInput()); 272 return mb; 273 274 } 275 }