package boeing.eng.structanalysis.modes.modest;

import java.applet.Applet;
import java.io.*;
import java.awt.*;
import java.awt.image.BufferedImage;
import javax.swing.*;
import java.awt.event.*;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import com.sun.j3d.utils.behaviors.vp.OrbitBehavior;
import com.sun.image.codec.jpeg.*;

public class MorphCapture extends Applet implements ActionListener {

    private SimpleUniverse u = null;
    private Canvas3D cDisplay = null;
    private Canvas3D cOffScreen = null;
    private JButton capButton = null;
    private JButton morphButton = null;
    private MorphingBehavior mBeh = null;
    private int captureCount = 0;

    private BranchGroup createSceneGraph() {
        
        // Create the root of the branch graph
        BranchGroup objRoot = new BranchGroup();

        // Create a Transformgroup to scale all objects so they
        // appear in the scene.
        TransformGroup objScale = new TransformGroup();
        Transform3D t3d = new Transform3D();
        t3d.setScale(0.4);
        objScale.setTransform(t3d);
        objRoot.addChild(objScale);

        // Create a bounds for the background and behavior
        BoundingSphere bounds =
            new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);

        QuadArray g[] = new QuadArray[3];
        g[0] = new ColorPyramidUp();
        g[1] = new ColorCube();
        g[2] = new ColorPyramidDown();

        Appearance a = new Appearance();

        //
        // Create a Morph node, and set the appearance and input geometry
        // arrays.  Set the Morph node's capability bits to allow the weights
        // to be modified at runtime.
        //
        Morph morph = new Morph((GeometryArray[]) g, a);
        morph.setCapability(Morph.ALLOW_WEIGHTS_READ);
        morph.setCapability(Morph.ALLOW_WEIGHTS_WRITE);

        objScale.addChild(morph);
 
        // Now create the Alpha object that controls the speed of the
        // morphing operation.
        Alpha morphAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE |
                                     Alpha.DECREASING_ENABLE,
                                     0, 0,
                                     4000, 1000, 500,
                                     4000, 1000, 500);

        // Finally, create the morphing behavior
        mBeh = new MorphingBehavior(morphAlpha, morph);
        mBeh.setSchedulingBounds(bounds);
        
        /* Comment out this statement to disable the Morph Behavior */
        objScale.addChild(mBeh);
 
        return objRoot;
    }

    public MorphCapture() {
    }

    public void init() {
        
        setLayout(new BorderLayout());
        
        GraphicsConfiguration config =
           SimpleUniverse.getPreferredConfiguration();

        // Define the Canvas that will be rendered into for the On-Screen Display
        cDisplay = new Canvas3D(config);
        add("Center", cDisplay);

        // Create the universe
        u = new SimpleUniverse(cDisplay);
        
        // get the view from the SimpleUniverse
        javax.media.j3d.View view = u.getViewer().getView();
        
        // Create an Off-Screen Canvas, and add to the view
        cOffScreen = new Canvas3D(config,true);
        view.addCanvas3D(cOffScreen);

        // This will move the ViewPlatform back a bit so the
        // objects in the scene can be viewed.
        u.getViewingPlatform().setNominalViewingTransform();

        // Create a simple scene and attach it to the virtual universe
        BranchGroup scene = createSceneGraph();
        scene.compile();
        u.addBranchGraph(scene);

        // Add controls for generating events to capture the image, and to 
        // stop & start the morph behavior
        capButton = new JButton("Capture");
        capButton.addActionListener(this);
        morphButton = new JButton("Toggle Morph");
        morphButton.addActionListener(this);

        // Collect the controls at the bottom of the frame.
        JPanel buttonPanel = new JPanel();
        buttonPanel.add(capButton);
        buttonPanel.add(morphButton);
        add("South",buttonPanel);
    
        // Add an orbit behavior to the view platform so the user can move 
        // around the object
        OrbitBehavior ob = new OrbitBehavior(cDisplay,
                     OrbitBehavior.REVERSE_ALL|OrbitBehavior.PROPORTIONAL_ZOOM);
        ob.setSchedulingBounds(new BoundingSphere(new Point3d(), 
                                                     Double.POSITIVE_INFINITY));
        u.getViewingPlatform().setViewPlatformBehavior(ob);
        ob.setRotationCenter(new Point3d());
        
    }

    public void destroy() {
        u.removeAllLocales();
    }

    public static void main(String[] args) {
        new MainFrame(new MorphCapture(), 700, 700);
    }
 
    public void actionPerformed(ActionEvent e) {
        
        if (e.getSource() == capButton) {
            
            // Obtain the size of the displayed canvas 
            Rectangle rect = cDisplay.getBounds();
            
            // Create a buffer for the Off Screen Canvas large enough to contain the displayed image
            BufferedImage img = new BufferedImage(rect.width,rect.height,BufferedImage.TYPE_INT_RGB);
            ImageComponent2D buf = new ImageComponent2D(ImageComponent.FORMAT_RGB,img);
            
            // provide the buffer to the off-screen canvas
            cOffScreen.setOffScreenBuffer(buf);
            
            // get the Screen3d associated with this canvas, and set the physical dimensions
            Screen3D screen = cOffScreen.getScreen3D();
            Screen3D screenDisplay = cDisplay.getScreen3D();
     
            screen.setSize(screenDisplay.getSize());
            screen.setPhysicalScreenWidth(screenDisplay.getPhysicalScreenWidth());
            screen.setPhysicalScreenHeight(screenDisplay.getPhysicalScreenHeight());
            
            // Request that the Off-Screen canvas is rendered
            cOffScreen.renderOffScreenBuffer();
            
            // wait for the rendering to complete
            cOffScreen.waitForOffScreenRendering();
            
            // obtain the image from the Off-Screen canvas 
            ImageComponent2D image = cOffScreen.getOffScreenBuffer();
            BufferedImage img2 = image.getImage();
            
            try {
                FileOutputStream out = new FileOutputStream("Capture"+captureCount+".jpg");
                JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
                JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(img2);
                param.setQuality(0.9f,false); // 90% qualith JPEG
                encoder.setJPEGEncodeParam(param);
                encoder.encode(img2);
                out.close();
                captureCount++;
            } catch ( IOException e2 ) {
                System.out.println("I/O exception!");
            }
            
        } else if (e.getSource() == morphButton) {
            mBeh.setEnable(!mBeh.getEnable());
        }
    }
}
