1 /* 2 * Copyright (c) 2008, 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 com.sun.scenario.effect; 27 28 import com.sun.javafx.geom.BaseBounds; 29 import com.sun.javafx.geom.DirtyRegionContainer; 30 import com.sun.javafx.geom.DirtyRegionPool; 31 import com.sun.javafx.geom.RectBounds; 32 import com.sun.javafx.geom.Rectangle; 33 import com.sun.javafx.geom.transform.BaseTransform; 34 import com.sun.scenario.effect.impl.Renderer; 35 import com.sun.scenario.effect.impl.state.MotionBlurState; 36 37 /** 38 * A motion blur effect using a Gaussian convolution kernel, with a 39 * configurable radius and angle. 40 */ 41 public class MotionBlur extends CoreEffect { 42 43 private MotionBlurState state = new MotionBlurState(); 44 45 /** 46 * Constructs a new {@code MotionBlur} effect with the default radius 47 * (10.0) and default angle (0.0), using the default input for source 48 * data. 49 * This is a shorthand equivalent to: 50 * <pre> 51 * new MotionBlur(10f, 0f, DefaultInput) 52 * </pre> 53 */ 54 public MotionBlur() { 55 this(10f, 0f, DefaultInput); 56 } 57 58 /** 59 * Constructs a new {@code MotionBlur} effect with the given radius 60 * and angle, using the default input for source data. 61 * This is a shorthand equivalent to: 62 * <pre> 63 * new MotionBlur(radius, angle, DefaultInput) 64 * </pre> 65 * 66 * @param radius the radius of the Gaussian kernel 67 * @param angle the angle of the motion effect, in radians 68 * @throws IllegalArgumentException if {@code radius} is outside the 69 * allowable range 70 */ 71 public MotionBlur(float radius, float angle) { 72 this(radius, angle, DefaultInput); 73 } 74 75 /** 76 * Constructs a new {@code MotionBlur} effect with the given radius 77 * and angle. 78 * 79 * @param radius the radius of the Gaussian kernel 80 * @param angle the angle of the motion effect, in radians 81 * @param input the single input {@code Effect} 82 * @throws IllegalArgumentException if {@code radius} is outside the 83 * allowable range 84 */ 85 public MotionBlur(float radius, float angle, Effect input) { 86 super(input); 87 setRadius(radius); 88 setAngle(angle); 89 } 90 91 @Override 92 Object getState() { 93 return state; 94 } 95 96 @Override 97 public AccelType getAccelType(FilterContext fctx) { 98 return Renderer.getRenderer(fctx).getAccelType(); 99 } 100 101 /** 102 * Returns the input for this {@code Effect}. 103 * 104 * @return the input for this {@code Effect} 105 */ 106 public final Effect getInput() { 107 return getInputs().get(0); 108 } 109 110 /** 111 * Sets the input for this {@code Effect} to a specific {@code Effect} 112 * or to the default input if {@code input} is {@code null}. 113 * 114 * @param input the input for this {@code Effect} 115 */ 116 public void setInput(Effect input) { 117 setInput(0, input); 118 } 119 120 /** 121 * Returns the radius of the Gaussian kernel. 122 * 123 * @return the radius of the Gaussian kernel 124 */ 125 public float getRadius() { 126 return state.getRadius(); 127 } 128 129 /** 130 * Sets the radius of the Gaussian kernel. 131 * <pre> 132 * Min: 0.0 133 * Max: 63.0 134 * Default: 10.0 135 * Identity: 0.0 136 * </pre> 137 * 138 * @param radius the radius of the Gaussian kernel 139 * @throws IllegalArgumentException if {@code radius} is outside the 140 * allowable range 141 */ 142 public void setRadius(float radius) { 143 float old = state.getRadius(); 144 state.setRadius(radius); 145 } 146 147 /** 148 * Returns the angle of the motion effect, in radians. 149 * 150 * @return the angle of the motion effect, in radians 151 */ 152 public float getAngle() { 153 return state.getAngle(); 154 } 155 156 /** 157 * Sets the angle of the motion effect, in radians. 158 * <pre> 159 * Min: n/a 160 * Max: n/a 161 * Default: 0.0 162 * Identity: n/a 163 * </pre> 164 * 165 * @param angle the angle of the motion effect, in radians 166 */ 167 public void setAngle(float angle) { 168 float old = state.getAngle(); 169 state.setAngle(angle); 170 } 171 172 @Override 173 public BaseBounds getBounds(BaseTransform transform, Effect defaultInput) { 174 BaseBounds r = super.getBounds(null, defaultInput); 175 int hpad = state.getHPad(); 176 int vpad = state.getVPad(); 177 BaseBounds ret = new RectBounds(r.getMinX(), r.getMinY(), r.getMaxX(), r.getMaxY()); 178 ((RectBounds) ret).grow(hpad, vpad); 179 return transformBounds(transform, ret); 180 } 181 182 @Override 183 public Rectangle getResultBounds(BaseTransform transform, 184 Rectangle outputClip, 185 ImageData... inputDatas) 186 { 187 Rectangle r = super.getResultBounds(transform, outputClip, inputDatas); 188 int hpad = state.getHPad(); 189 int vpad = state.getVPad(); 190 Rectangle ret = new Rectangle(r); 191 ret.grow(hpad, vpad); 192 return ret; 193 } 194 195 @Override 196 public ImageData filterImageDatas(FilterContext fctx, 197 BaseTransform transform, 198 Rectangle outputClip, 199 ImageData... inputs) 200 { 201 return state.filterImageDatas(this, fctx, transform, outputClip, inputs); 202 } 203 204 @Override 205 public boolean operatesInUserSpace() { 206 return true; 207 } 208 209 @Override 210 protected Rectangle getInputClip(int inputIndex, 211 BaseTransform transform, 212 Rectangle outputClip) 213 { 214 // A blur needs as much "fringe" data from its input as it creates 215 // around its output so we use the same expansion as is used in the 216 // result bounds. 217 if (outputClip != null) { 218 int hpad = state.getHPad(); 219 int vpad = state.getVPad(); 220 if ((hpad | vpad) != 0) { 221 outputClip = new Rectangle(outputClip); 222 outputClip.grow(hpad, vpad); 223 } 224 } 225 return outputClip; 226 } 227 228 @Override 229 public boolean reducesOpaquePixels() { 230 if (!state.isNop()) { 231 return true; 232 } 233 final Effect input = getInput(); 234 return input != null && input.reducesOpaquePixels(); 235 } 236 237 @Override 238 public DirtyRegionContainer getDirtyRegions(Effect defaultInput, DirtyRegionPool regionPool) { 239 Effect di = getDefaultedInput(0, defaultInput); 240 DirtyRegionContainer drc = di.getDirtyRegions(defaultInput, regionPool); 241 242 drc.grow(state.getHPad(), state.getVPad()); 243 244 return drc; 245 } 246 }