1 /* 2 * Copyright (c) 2009, 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.impl.state; 27 28 import java.nio.FloatBuffer; 29 import com.sun.scenario.effect.impl.BufferUtil; 30 31 /** 32 * The state and implementation class for calculating 1 dimensional 33 * linear convolution kernels for performing gaussian blurs. 34 */ 35 public class GaussianBlurState extends HVSeparableKernel { 36 private float hradius; 37 private float vradius; 38 private FloatBuffer weights; 39 40 void checkRadius(float radius) { 41 if (radius < 0f || radius > 63f) { 42 throw new IllegalArgumentException("Radius must be in the range [1,63]"); 43 } 44 } 45 46 public float getRadius() { 47 return (hradius + vradius) / 2.0f; 48 } 49 50 public void setRadius(float radius) { 51 checkRadius(radius); 52 this.hradius = radius; 53 this.vradius = radius; 54 } 55 56 public float getHRadius() { 57 return hradius; 58 } 59 60 public void setHRadius(float hradius) { 61 checkRadius(hradius); 62 this.hradius = hradius; 63 } 64 65 public float getVRadius() { 66 return vradius; 67 } 68 69 public void setVRadius(float vradius) { 70 checkRadius(vradius); 71 this.vradius = vradius; 72 } 73 74 float getRadius(int pass) { 75 return (pass == 0 ? hradius : vradius); 76 } 77 78 @Override 79 public boolean isNop() { 80 return hradius == 0 && vradius == 0; 81 } 82 83 @Override 84 public boolean isNop(int pass) { 85 return getRadius(pass) == 0; 86 } 87 88 public int getPad(int pass) { 89 return (int) Math.ceil(getRadius(pass)); 90 } 91 92 public int getScaledPad(int pass) { 93 return getPad(pass); 94 } 95 96 public float getScaledRadius(int pass) { 97 return getRadius(pass); 98 } 99 100 @Override 101 public int getKernelSize(int pass) { 102 return getPad(pass) * 2 + 1; 103 } 104 105 public float getSpread() { 106 return 0f; 107 } 108 109 @Override 110 public FloatBuffer getWeights(int pass) { 111 float r0 = getScaledRadius(0); 112 float r1 = getScaledRadius(1); 113 // We need to apply the spread on only one pass 114 // Prefer pass1 if r1 is not tiny (or at least bigger than r0) 115 // Otherwise use pass 0 so that it doesn't disappear 116 int spreadpass = (r1 > 1f || r1 >= r0) ? 1 : 0; 117 118 float r = (pass == 0) ? r0 : r1; 119 float s = (pass == spreadpass) ? getSpread() : 0f; 120 weights = getGaussianWeights(weights, getScaledPad(pass), r, s); 121 return weights; 122 } 123 124 static FloatBuffer getGaussianWeights(FloatBuffer weights, 125 int pad, 126 float radius, 127 float spread) 128 { 129 int r = pad; 130 int klen = (r * 2) + 1; 131 if (weights == null) { 132 weights = BufferUtil.newFloatBuffer(128); 133 } 134 weights.clear(); 135 float sigma = radius / 3; 136 float sigma22 = 2 * sigma * sigma; 137 if (sigma22 < Float.MIN_VALUE) { 138 // Avoid divide by 0 below (it can generate NaN values). 139 sigma22 = Float.MIN_VALUE; 140 } 141 float total = 0.0F; 142 for (int row = -r; row <= r; row++) { 143 float kval = (float) Math.exp(-(row * row) / sigma22); 144 weights.put(kval); 145 total += kval; 146 } 147 total += (weights.get(0) - total) * spread; 148 for (int i = 0; i < klen; i++) { 149 weights.put(i, weights.get(i) / total); 150 } 151 int limit = getPeerSize(klen); 152 while (weights.position() < limit) { 153 weights.put(0.0F); 154 } 155 weights.limit(limit); 156 weights.rewind(); 157 return weights; 158 } 159 }