import java.applet.Applet;
import java.awt.event.*;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.*;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import java.awt.*;
import com.sun.j3d.utils.image.TextureLoader;
import java.awt.image.BufferedImage;

public class TextureDraw extends Applet {
    MyAppearance appearance = new MyAppearance();

    public BranchGroup createSceneGraph() {
        BranchGroup objRoot = new BranchGroup();
        Box b = new Box( 0.3f, 0.3f, 0.3f, Primitive.GENERATE_TEXTURE_COORDS, appearance );
        objRoot.addChild( b );
        objRoot.compile();
        return objRoot;
    }
    public TextureDraw() {
        setLayout(new BorderLayout());
        Canvas3D c = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
        add("Center", c);

        BranchGroup scene = createSceneGraph();
        SimpleUniverse u = new SimpleUniverse(c);
        u.getViewingPlatform().setNominalViewingTransform();
        u.addBranchGraph(scene);

        Button b = new Button( "Edit" );
        b.addActionListener( new ActionListener(){
            public void actionPerformed( ActionEvent e ){
                appearance.change();
            }
        });
        add( "North", b );
    }
    public static void main(String[] args) {
        new MainFrame(new TextureDraw(), 256, 256);
    }
    class MyAppearance extends Appearance{
        Color color;
        DrawingTexture tex;
        int w = 1024, h = 1024;

        public MyAppearance(){
            BufferedImage image = new BufferedImage( w, h, BufferedImage.TYPE_3BYTE_BGR );
            Graphics g = image.getGraphics();
            g.setColor( Color.gray );
            g.fillRect( 0, 0, w, h );
            tex = new DrawingTexture( image, w, h );
            setTexture( tex );
        }
        public void change(){
            color = color == Color.red ? Color.white : Color.red;
            Graphics g = tex.getGraphics();
            g.setColor( color );
            g.fillRect( w/3, h/3, w/3, h/3 );
            tex.swap();
        }
    }
    class DrawingTexture extends Texture2D{
        private Graphics graphics;
        private Image backgroundImage;
        private BufferedImage image;
        private ImageComponent2D[] imcomp = new ImageComponent2D[2];
        private int curImcomp = 0;
        private int width, height;
        final boolean byReference = true;
        final boolean yUp = true;

        public DrawingTexture( Image img, int w, int h ){
            super( Texture.BASE_LEVEL, Texture.RGB, w, h );
            setCapability( Texture.ALLOW_IMAGE_WRITE );
            width = w;
            height = h;
            backgroundImage = img;
            image = new BufferedImage( w, h, BufferedImage.TYPE_3BYTE_BGR );
            graphics = image.getGraphics();
            drawBackground();
            imcomp[0] = new ImageComponent2D( ImageComponent.FORMAT_RGB, w, h, byReference, yUp );
            imcomp[0].set( image );
            imcomp[1] = new ImageComponent2D( ImageComponent.FORMAT_RGB, w, h, byReference, yUp );
            imcomp[1].set( image );
            setImage( 0, imcomp[curImcomp] );
        }
        public Graphics getGraphics(){
            return graphics;
        }
        public void swap(){
            curImcomp = curImcomp == 0 ? 1 : 0;
            imcomp[curImcomp].set( image );
            setImage( 0, imcomp[curImcomp] );
        }
        public void drawBackground(){
            graphics.drawImage( backgroundImage, 0, 0, null );
        }
    }
}
