package a3test.canvases;

import jp.sourceforge.acerola3d.a3.*;

import java.awt.*;
import java.awt.geom.AffineTransform;
import java.awt.image.*;
import javax.swing.*;

public class A3FilterTest implements A3Filter {
    static JA3Canvas2 c;
    public static void main(String args[]) throws Exception {
        JFrame f = new JFrame("JA3Canvas2Test");
        f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        c = JA3Canvas2.createJA3Canvas(300,300);
        f.add(c);
        f.pack();
        f.setVisible(true);
        c.setNavigationMode(A3CanvasInterface.NaviMode.EDIT);
        A3Background b = new A3Background(0.8f,0.8f,0.5f);
        c.setBackground(b);
        Action3D a3 = new Action3D("x-res:///axis.a3");
        c.add(a3);
        c.addA3Filter(new A3FilterTest());

        while (true) {
            System.out.println(c.getFPS());
            a3.change("vertigo");
            Thread.sleep(1000);
        }
    }
    public BufferedImage filter(BufferedImage in) {
        //return filter0(in);
        //return filter1(in);
        //return filter2(in);
        //return filter3(in);
        //return filter4(in);
        return filter5(in);
    }

    public BufferedImage filter0(BufferedImage in) {
        return in;
    }

    double t=0.0;
    BufferedImage out = null;
    public BufferedImage filter1(BufferedImage in) {
        t = t + 0.1;
        int w = in.getWidth();
        int h = in.getHeight();
        if (out==null||(w!=out.getWidth()||h!=out.getHeight()))
            out = new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB);
        for (int x=0;x<w;x++) {
            for (int y=0;y<h;y++) {
                double d = 0.01*Math.sqrt(x*x+y*y);
                int xx = x + (int)(100.0*Math.sin(d+t));
                int yy = y + (int)(100.0*Math.cos(d+t));
                if (xx<0)xx=0;if (xx>=w)xx=w-1;
                if (yy<0)yy=0;if (yy>=h)yy=h-1;
                out.setRGB(x,y,in.getRGB(xx,yy));
            }
        }
        return out;
    }

    int rgbArrayIn[];
    int rgbArrayOut[];
    //filter1と処理速度かわらず
    public BufferedImage filter2(BufferedImage in) {
        t = t + 0.1;
        int w = in.getWidth();
        int h = in.getHeight();
        if (out==null||(w!=out.getWidth()||h!=out.getHeight())) {
            out = new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB);
            rgbArrayIn = new int[w*h];
            rgbArrayOut = new int[w*h];
        }
        in.getRGB(0,0,w,h,rgbArrayIn,0,w);
        for (int x=0;x<w;x++) {
            for (int y=0;y<h;y++) {
                double d = 0.01*Math.sqrt(x*x+y*y);
                int xx = x + (int)(100.0*Math.sin(d+t));
                int yy = y + (int)(100.0*Math.cos(d+t));
                if (xx<0)xx=0;if (xx>=w)xx=w-1;
                if (yy<0)yy=0;if (yy>=h)yy=h-1;
                rgbArrayOut[x+w*y] = rgbArrayIn[xx+w*yy];
            }
        }
        out.setRGB(0,0,w,h,rgbArrayOut,0,w);
        return out;
    }

    MemoryImageSource ms;
    Graphics2D g;
    //filter1の2倍ぐらいのスピードになった
    public BufferedImage filter3(BufferedImage in) {
        t = t + 0.1;
        int w = in.getWidth();
        int h = in.getHeight();
        if (out==null||(w!=out.getWidth()||h!=out.getHeight())) {
            rgbArrayOut = new int[w*h];
            ms = new MemoryImageSource(w,h,rgbArrayOut,0,w);
            out = new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB);
            g = out.createGraphics();
        }
        PixelGrabber pg = new PixelGrabber(in,0,0,w,h,false);
        try{ pg.grabPixels(); }catch(InterruptedException e){}
        rgbArrayIn = (int[])pg.getPixels();
        for (int x=0;x<w;x++) {
            for (int y=0;y<h;y++) {
                double d = 0.01*Math.sqrt(x*x+y*y);
                int xx = x + (int)(100.0*Math.sin(d+t));
                int yy = y + (int)(100.0*Math.cos(d+t));
                if (xx<0)xx=0;if (xx>=w)xx=w-1;
                if (yy<0)yy=0;if (yy>=h)yy=h-1;
                rgbArrayOut[x+w*y] = rgbArrayIn[xx+w*yy];
            }
        }
        Image img = c.createImage(ms);
        g.drawImage(img,0,0,null);
        return out;
    }

    //BufferedImageOpの実装の一つのAffineTransformOpを使ってみたら
    //そこそこのスピードは出るけどAffineTransformOpのソースを辿っていったら
    //実際の処理はnative実装になっていた
    //上と処理内容は違うけど、だいたいfilter1の5倍ぐらいのスピード
    public BufferedImage filter4(BufferedImage in) {
        t = t + 0.01;
        int w = in.getWidth();
        int h = in.getHeight();
        if (out==null||(w!=out.getWidth()||h!=out.getHeight())) {
            out = new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB);
        }
        double sx = Math.sin(t)+1.0;
        double sy = Math.cos(t)+1.0;
        AffineTransformOp atOp = new AffineTransformOp(AffineTransform.getScaleInstance(sx,sy), AffineTransformOp.TYPE_BILINEAR);
        atOp.filter(in,out);
        return out;
    }

    //このぐらいの処理だと、まあまあ使えるかな。
    //処理内容全然違うけどfilter1の10倍ぐらいのスピード
    public BufferedImage filter5(BufferedImage in) {
        int w = in.getWidth();
        int h = in.getHeight();
        if (out==null||(w!=out.getWidth()||h!=out.getHeight())) {
            out = new BufferedImage(w,h,BufferedImage.TYPE_INT_ARGB);
            g = out.createGraphics();
            g.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER,0.01F));
        }
        g.drawImage(in,0,0,null);
        return out;
    }
}
