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}