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 java.awt.image.*;
import java.awt.color.*;

public class RenderOnce1 extends Applet {
    int w = 1024, h = 1024;
    long minFrameSpeed = 1000;
    Graphics graphics;
    boolean inColor = true;
    DrawingTexture tex;
    boolean big = false;
    View view;
    boolean manualRender = true;
    Appearance appearance;
    final TransformGroup TG = new TransformGroup();{
        TG.setCapability( TransformGroup.ALLOW_TRANSFORM_WRITE );
    }

    public BranchGroup createSceneGraph() {
        BufferedImage foregroundImage = DrawingTexture.createBufferedImage( w, h, inColor );
        graphics = foregroundImage.getGraphics();
        tex = new DrawingTexture( foregroundImage, w, h );

        appearance = new Appearance();
        appearance.setTexture( tex );

        BranchGroup objRoot = new BranchGroup();
        Box b = new Box( 0.3f, 0.3f, 0.3f, Primitive.GENERATE_TEXTURE_COORDS, appearance );
        objRoot.addChild( TG );
        TG.addChild( b );
        Behavior animate = new Behavior(){
            WakeupCondition wakeup = new WakeupOnElapsedFrames( 0 );
            public void initialize(){
                wakeupOn( wakeup );
            }
            public void processStimulus( java.util.Enumeration criteria ){
                change();
                wakeupOn( wakeup );
            }
        };
        animate.setSchedulingBounds( new BoundingSphere() );
        objRoot.addChild( animate );
        objRoot.compile();
        return objRoot;
    }
    public RenderOnce1() {
        setLayout(new BorderLayout());
        Canvas3D c = new Canvas3D(SimpleUniverse.getPreferredConfiguration());
        add("Center", c);
        final Button b = new Button( "renderOnce" );
        b.setEnabled( manualRender );
        b.addActionListener( new ActionListener(){
            public void actionPerformed( ActionEvent e ){
                view.renderOnce();
            }
        });
        add( "North", b );
        Button b2 = new Button( "switch mode" );
        b2.addActionListener( new ActionListener(){
            public void actionPerformed( ActionEvent e ){
                manualRender = !manualRender;
                b.setEnabled( manualRender );
                if( manualRender ){
                    view.stopView();
                }else{
                    view.startView();
                }
            }
        });
        add( "South", b2 );

        BranchGroup scene = createSceneGraph();
        SimpleUniverse u = new SimpleUniverse(c);
        u.getViewingPlatform().setNominalViewingTransform();
        u.addBranchGraph(scene);
        view = u.getViewer().getView();
        view.stopView();
        view.setMinimumFrameCycleTime( minFrameSpeed );
    }
    public void change(){
        Transform3D T = new Transform3D();
        big = !big;
        if( big ){
            graphics.setColor( Color.blue );
            T.setScale( 2 );
        }else{
            graphics.setColor( Color.yellow );
            T.setScale( 1 );
        }
        graphics.fillRect( 0, 0, w, h );
        tex.update();
        TG.setTransform( T );
    }
    public static void main(String[] args) {
        new MainFrame(new RenderOnce1(), 256, 256);
    }
    static class DrawingTexture extends Texture2D{
        ImageComponent2D imcomp;

        public DrawingTexture( BufferedImage image, int w, int h ){
            //image : image to be drawn on
            //w : width
            //h : height
            super( Texture.BASE_LEVEL, Texture.RGB, w, h );
            setCapability( Texture.ALLOW_IMAGE_WRITE );
            int imageType = image.getType();
            int type2D;
            if( imageType == BufferedImage.TYPE_BYTE_GRAY ){
                type2D = ImageComponent.FORMAT_CHANNEL8;
            }else{
                type2D = ImageComponent.FORMAT_RGB8;
            }
            imcomp = new ImageComponent2D( type2D, w, h, true, true );
            imcomp.set( image );
            setImage( 0, imcomp );
        }
        public static BufferedImage createBufferedImage( int w, int h, boolean color ){
            //utility to simplify the creation of the right format image
            //w : width
            //h : height
            // color : color or B/W
            BufferedImage bi;
            if( color ){
                ColorSpace cs = ColorSpace.getInstance( ColorSpace.CS_sRGB );
                int[] nbits = {
                    8,8,8
                };
                ColorModel cm = new ComponentColorModel( cs, nbits, false, false, java.awt.Transparency.OPAQUE, 0 );
                int[] bandoffset = {
                    0,1,2
                };
                WritableRaster wr = java.awt.image.Raster.createInterleavedRaster( DataBuffer.TYPE_BYTE, w, h, w*3, 3, bandoffset, null );
                bi = new BufferedImage( cm, wr, false, null );
            }else{
                bi = new BufferedImage( w, h, BufferedImage.TYPE_BYTE_GRAY );
            }
            return bi;
        }
        public void update(){
            //must call update whenever edits to the image need to be visible
            setImage( 0, imcomp );
        }
    }
}
