001/* 002Copyright 2006 Jerry Huxtable 003 004Licensed under the Apache License, Version 2.0 (the "License"); 005you may not use this file except in compliance with the License. 006You may obtain a copy of the License at 007 008 http://www.apache.org/licenses/LICENSE-2.0 009 010Unless required by applicable law or agreed to in writing, software 011distributed under the License is distributed on an "AS IS" BASIS, 012WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013See the License for the specific language governing permissions and 014limitations under the License. 015*/ 016 017package com.jhlabs.image; 018 019import java.util.*; 020import java.awt.*; 021import java.awt.image.*; 022import com.jhlabs.math.*; 023 024public class PlasmaFilter extends WholeImageFilter { 025 026 public float turbulence = 1.0f; 027 private float scaling = 0.0f; 028 private Colormap colormap = new LinearColormap(); 029 private Random randomGenerator; 030 private long seed = 567; 031 private boolean useColormap = false; 032 private boolean useImageColors = false; 033 034 public PlasmaFilter() { 035 randomGenerator = new Random(); 036 } 037 038 /** 039 * Specifies the turbulence of the texture. 040 * @param turbulence the turbulence of the texture. 041 * @min-value 0 042 * @max-value 10 043 * @see #getTurbulence 044 */ 045 public void setTurbulence(float turbulence) { 046 this.turbulence = turbulence; 047 } 048 049 /** 050 * Returns the turbulence of the effect. 051 * @return the turbulence of the effect. 052 * @see #setTurbulence 053 */ 054 public float getTurbulence() { 055 return turbulence; 056 } 057 058 public void setScaling(float scaling) { 059 this.scaling = scaling; 060 } 061 062 public float getScaling() { 063 return scaling; 064 } 065 066 /** 067 * Set the colormap to be used for the filter. 068 * @param colormap the colormap 069 * @see #getColormap 070 */ 071 public void setColormap(Colormap colormap) { 072 this.colormap = colormap; 073 } 074 075 /** 076 * Get the colormap to be used for the filter. 077 * @return the colormap 078 * @see #setColormap 079 */ 080 public Colormap getColormap() { 081 return colormap; 082 } 083 084 public void setUseColormap(boolean useColormap) { 085 this.useColormap = useColormap; 086 } 087 088 public boolean getUseColormap() { 089 return useColormap; 090 } 091 092 public void setUseImageColors(boolean useImageColors) { 093 this.useImageColors = useImageColors; 094 } 095 096 public boolean getUseImageColors() { 097 return useImageColors; 098 } 099 100 public void setSeed(int seed) { 101 this.seed = seed; 102 } 103 104 public int getSeed() { 105 return (int)seed; 106 } 107 108 public void randomize() { 109 seed = new Date().getTime(); 110 } 111 112 private int randomRGB(int[] inPixels, int x, int y) { 113 if (useImageColors) { 114 return inPixels[y*originalSpace.width+x]; 115 } else { 116 int r = (int)(255 * randomGenerator.nextFloat()); 117 int g = (int)(255 * randomGenerator.nextFloat()); 118 int b = (int)(255 * randomGenerator.nextFloat()); 119 return 0xff000000 | (r << 16) | (g << 8) | b; 120 } 121 } 122 123 private int displace(int rgb, float amount) { 124 int r = (rgb >> 16) & 0xff; 125 int g = (rgb >> 8) & 0xff; 126 int b = rgb & 0xff; 127 r = PixelUtils.clamp(r + (int)(amount * (randomGenerator.nextFloat()-0.5))); 128 g = PixelUtils.clamp(g + (int)(amount * (randomGenerator.nextFloat()-0.5))); 129 b = PixelUtils.clamp(b + (int)(amount * (randomGenerator.nextFloat()-0.5))); 130 return 0xff000000 | (r << 16) | (g << 8) | b; 131 } 132 133 private int average(int rgb1, int rgb2) { 134 return PixelUtils.combinePixels(rgb1, rgb2, PixelUtils.AVERAGE); 135 } 136 137 private int getPixel(int x, int y, int[] pixels, int stride) { 138 return pixels[y*stride+x]; 139 } 140 141 private void putPixel(int x, int y, int rgb, int[] pixels, int stride) { 142 pixels[y*stride+x] = rgb; 143 } 144 145 private boolean doPixel(int x1, int y1, int x2, int y2, int[] pixels, int stride, int depth, int scale) { 146 int mx, my; 147 148 if (depth == 0) { 149 int ml, mr, mt, mb, mm, t; 150 151 int tl = getPixel(x1, y1, pixels, stride); 152 int bl = getPixel(x1, y2, pixels, stride); 153 int tr = getPixel(x2, y1, pixels, stride); 154 int br = getPixel(x2, y2, pixels, stride); 155 156 float amount = (256.0f / (2.0f * scale)) * turbulence; 157 158 mx = (x1 + x2) / 2; 159 my = (y1 + y2) / 2; 160 161 if (mx == x1 && mx == x2 && my == y1 && my == y2) 162 return true; 163 164 if (mx != x1 || mx != x2) { 165 ml = average(tl, bl); 166 ml = displace(ml, amount); 167 putPixel(x1, my, ml, pixels, stride); 168 169 if (x1 != x2){ 170 mr = average(tr, br); 171 mr = displace(mr, amount); 172 putPixel(x2, my, mr, pixels, stride); 173 } 174 } 175 176 if (my != y1 || my != y2){ 177 if (x1 != mx || my != y2){ 178 mb = average(bl, br); 179 mb = displace(mb, amount); 180 putPixel(mx, y2, mb, pixels, stride); 181 } 182 183 if (y1 != y2){ 184 mt = average(tl, tr); 185 mt = displace(mt, amount); 186 putPixel(mx, y1, mt, pixels, stride); 187 } 188 } 189 190 if (y1 != y2 || x1 != x2) { 191 mm = average(tl, br); 192 t = average(bl, tr); 193 mm = average(mm, t); 194 mm = displace(mm, amount); 195 putPixel(mx, my, mm, pixels, stride); 196 } 197 198 if (x2-x1 < 3 && y2-y1 < 3) 199 return false; 200 return true; 201 } 202 203 mx = (x1 + x2) / 2; 204 my = (y1 + y2) / 2; 205 206 doPixel(x1, y1, mx, my, pixels, stride, depth-1, scale+1); 207 doPixel(x1, my, mx ,y2, pixels, stride, depth-1, scale+1); 208 doPixel(mx, y1, x2 , my, pixels, stride, depth-1, scale+1); 209 return doPixel(mx, my, x2, y2, pixels, stride, depth-1, scale+1); 210 } 211 212 protected int[] filterPixels( int width, int height, int[] inPixels, Rectangle transformedSpace ) { 213 int[] outPixels = new int[width * height]; 214 215 randomGenerator.setSeed(seed); 216 217 int w1 = width-1; 218 int h1 = height-1; 219 putPixel(0, 0, randomRGB(inPixels, 0, 0), outPixels, width); 220 putPixel(w1, 0, randomRGB(inPixels, w1, 0), outPixels, width); 221 putPixel(0, h1, randomRGB(inPixels, 0, h1), outPixels, width); 222 putPixel(w1, h1, randomRGB(inPixels, w1, h1), outPixels, width); 223 putPixel(w1/2, h1/2, randomRGB(inPixels, w1/2, h1/2), outPixels, width); 224 putPixel(0, h1/2, randomRGB(inPixels, 0, h1/2), outPixels, width); 225 putPixel(w1, h1/2, randomRGB(inPixels, w1, h1/2), outPixels, width); 226 putPixel(w1/2, 0, randomRGB(inPixels, w1/2, 0), outPixels, width); 227 putPixel(w1/2, h1, randomRGB(inPixels, w1/2, h1), outPixels, width); 228 229 int depth = 1; 230 while (doPixel(0, 0, width-1, height-1, outPixels, width, depth, 0)) 231 depth++; 232 233 if (useColormap && colormap != null) { 234 int index = 0; 235 for (int y = 0; y < height; y++) { 236 for (int x = 0; x < width; x++) { 237 outPixels[index] = colormap.getColor((outPixels[index] & 0xff)/255.0f); 238 index++; 239 } 240 } 241 } 242 return outPixels; 243 } 244 245 public String toString() { 246 return "Texture/Plasma..."; 247 } 248 249}