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.awt.*; 020import java.awt.geom.*; 021import java.awt.image.*; 022import java.util.*; 023 024public class ShatterFilter extends AbstractBufferedImageOp { 025 private float centreX = 0.5f, centreY = 0.5f; 026 private float distance; 027 private float transition; 028 private float rotation; 029 private float zoom; 030 private float startAlpha = 1; 031 private float endAlpha = 1; 032 private int iterations = 5; 033 private int tile; 034 035 public ShatterFilter() { 036 } 037 038 public void setTransition( float transition ) { 039 this.transition = transition; 040 } 041 042 public float getTransition() { 043 return transition; 044 } 045 046 public void setDistance( float distance ) { 047 this.distance = distance; 048 } 049 050 public float getDistance() { 051 return distance; 052 } 053 054 public void setRotation( float rotation ) { 055 this.rotation = rotation; 056 } 057 058 public float getRotation() { 059 return rotation; 060 } 061 062 public void setZoom( float zoom ) { 063 this.zoom = zoom; 064 } 065 066 public float getZoom() { 067 return zoom; 068 } 069 070 public void setStartAlpha( float startAlpha ) { 071 this.startAlpha = startAlpha; 072 } 073 074 public float getStartAlpha() { 075 return startAlpha; 076 } 077 078 public void setEndAlpha( float endAlpha ) { 079 this.endAlpha = endAlpha; 080 } 081 082 public float getEndAlpha() { 083 return endAlpha; 084 } 085 086 public void setCentreX( float centreX ) { 087 this.centreX = centreX; 088 } 089 090 public float getCentreX() { 091 return centreX; 092 } 093 094 public void setCentreY( float centreY ) { 095 this.centreY = centreY; 096 } 097 098 public float getCentreY() { 099 return centreY; 100 } 101 102 public void setCentre( Point2D centre ) { 103 this.centreX = (float)centre.getX(); 104 this.centreY = (float)centre.getY(); 105 } 106 107 public Point2D getCentre() { 108 return new Point2D.Float( centreX, centreY ); 109 } 110 111 public void setIterations( int iterations ) { 112 this.iterations = iterations; 113 } 114 115 public int getIterations() { 116 return iterations; 117 } 118 119 public void setTile( int tile ) { 120 this.tile = tile; 121 } 122 123 public int getTile() { 124 return tile; 125 } 126 127 static class Tile { 128 float x, y, vx, vy, w, h; 129 float rotation; 130 Shape shape; 131 } 132 133 public BufferedImage filter( BufferedImage src, BufferedImage dst ) { 134 if ( dst == null ) 135 dst = createCompatibleDestImage( src, null ); 136 float width = (float)src.getWidth(); 137 float height = (float)src.getHeight(); 138 float cx = (float)src.getWidth() * centreX; 139 float cy = (float)src.getHeight() * centreY; 140 float imageRadius = (float)Math.sqrt( cx*cx + cy*cy ); 141 142// BufferedImage[] tiles = new BufferedImage[iterations]; 143 int numTiles = iterations*iterations; 144 Tile[] shapes = new Tile[numTiles]; 145 float[] rx = new float[numTiles]; 146 float[] ry = new float[numTiles]; 147 float[] rz = new float[numTiles]; 148 149 Graphics2D g = dst.createGraphics(); 150// g.drawImage( src, null, null ); 151 152 Random random = new Random( 0 ); 153 float lastx = 0, lasty = 0; 154/* 155 for ( int i = 0; i <= numTiles; i++ ) { 156 double angle = (double)i * 2*Math.PI / numTiles; 157 float x = cx + width*(float)Math.cos(angle); 158 float y = cy + height*(float)Math.sin(angle); 159 g.setColor( Color.black ); 160 g.setColor( Color.getHSBColor( (float)angle, 1, 1 ) ); 161 if ( i != 0 ) { 162 rz[i-1] = tile*(2*random.nextFloat()-1); 163 ry[i-1] = tile*random.nextFloat(); 164 rz[i-1] = tile*random.nextFloat(); 165 GeneralPath p = new GeneralPath(); 166 p.moveTo( cx, cy ); 167 p.lineTo( lastx, lasty ); 168 p.lineTo( x, y ); 169 p.closePath(); 170 shapes[i-1] = p; 171// Rectangle r = p.getBounds(); 172// r.intersect( r, new Rectangle( (int)width, (int)height ), r ); 173 } 174 lastx = x; 175 lasty = y; 176 } 177*/ 178 for ( int y = 0; y < iterations; y++ ) { 179 int y1 = (int)height*y/iterations; 180 int y2 = (int)height*(y+1)/iterations; 181 for ( int x = 0; x < iterations; x++ ) { 182 int i = y*iterations+x; 183 int x1 = (int)width*x/iterations; 184 int x2 = (int)width*(x+1)/iterations; 185 rx[i] = tile*random.nextFloat(); 186 ry[i] = tile*random.nextFloat(); 187 rx[i] = 0; 188 ry[i] = 0; 189 rz[i] = tile*(2*random.nextFloat()-1); 190 Shape p = new Rectangle( x1, y1, x2-x1, y2-y1 ); 191 shapes[i] = new Tile(); 192 shapes[i].shape = p; 193 shapes[i].x = (x1+x2)*0.5f; 194 shapes[i].y = (y1+y2)*0.5f; 195 shapes[i].vx = width-(cx-x); 196 shapes[i].vy = height-(cy-y); 197 shapes[i].w = x2-x1; 198 shapes[i].h = y2-y1; 199 } 200 } 201 202 for ( int i = 0; i < numTiles; i++ ) { 203 float h = (float)i / numTiles; 204 double angle = h * 2*Math.PI; 205 float x = transition * width*(float)Math.cos(angle); 206 float y = transition * height*(float)Math.sin(angle); 207 208 Tile tile = shapes[i]; 209 Rectangle r = tile.shape.getBounds(); 210 AffineTransform t = g.getTransform(); 211x = tile.x + transition * tile.vx; 212y = tile.y + transition * tile.vy; 213 g.translate( x, y ); 214// g.translate( tile.w*0.5f, tile.h*0.5f ); 215 g.rotate( transition * rz[i] ); 216// g.scale( (float)Math.cos( transition * rx[i] ), (float)Math.cos( transition * ry[i] ) ); 217// g.translate( -tile.w*0.5f, -tile.h*0.5f ); 218 g.setColor( Color.getHSBColor( h, 1, 1 ) ); 219 Shape clip = g.getClip(); 220 g.clip( tile.shape ); 221 g.drawImage( src, 0, 0, null ); 222 g.setClip( clip ); 223 g.setTransform( t ); 224 } 225 226 g.dispose(); 227 return dst; 228 } 229 230 public String toString() { 231 return "Transition/Shatter..."; 232 } 233}