/*
 * @(#)TestCase.java
 *
 * Copyright (c) 2001-02, Pharmix Corp.  All Rights Reserved.
 * 
 * This software is the confidential and proprietary information of 
 * Pharmix Corp. ("Confidential Information").  You shall not
 * disclose such Confidential Information.  This software is provided for
 * evaluation purposes only.  Commercial use is prohibited.
 *   
 */

import java.awt.*;
import javax.swing.*;

import javax.media.j3d.*;
import javax.vecmath.*;

import com.sun.j3d.utils.behaviors.mouse.*;
import com.sun.j3d.utils.universe.*;


/**
 * A simple class for Java3D test cases.
 *
 * @author  Sean Sylvis
 */
public class TestCase extends JFrame
{
    // Constants
    public static final int kDefaultWidth = 800;
    public static final int kDefaultHeight = 600;
    
    // Members
    protected SimpleUniverse mUniverse;

    protected BranchGroup mGraphBranch;
    protected TransformGroup mSceneTransform;
    protected TransformGroup mViewTransform;


    /**
     * Constructs a default TestCase.
     */
    public TestCase()
    {
        this(kDefaultWidth, kDefaultHeight);
    }


    /**
     * Constructs a TestCase with the parameter dimensions.
     *
     * @param pWidth  the drawing canvas width
     * @param pHeight  the drawing canvas height
     */
    public TestCase(int pWidth, int pHeight)
    {
        try
        {
            // Initialize frame properties
            super.setTitle("Java3D Simple Viewer");
            
            super.setSize(pWidth, pHeight);
            super.setDefaultCloseOperation(super.EXIT_ON_CLOSE);
            
            // Add a canvas
            Canvas3D vCanvas = new Canvas3D(createGraphicsConfig());
            super.getContentPane().add(vCanvas, BorderLayout.CENTER);

            // Setup universe
            mUniverse = new SimpleUniverse(vCanvas);
            setupSceneBranch();
            setupViewBranch();
            
            mUniverse.getViewingPlatform().setNominalViewingTransform();
            
            super.setVisible(true);
        }
        
        catch (Exception e)
        {
            System.out.println("Could not create TestCase.");
        }
    }


    /**
     * Runs the test case.
     */
    public void runTest()
    {
        int kNumChildren = 4;

        // Create branch group
        BranchGroup vGroup = new BranchGroup();
        vGroup.setCapability(BranchGroup.ALLOW_CHILDREN_READ);

        System.out.println("\nWithout compile");
        
        // Add null children
        for (int i = 0; i < kNumChildren; i++)
            vGroup.addChild(null);
        System.out.println("children added");
        
        System.out.println("#children: " + vGroup.numChildren());
        System.out.println("set children");

        // Set children
        for (int i = 0; i < kNumChildren; i++)
            vGroup.setChild(new BranchGroup(), i);


        // Create branch group
        vGroup = new BranchGroup();
        vGroup.setCapability(BranchGroup.ALLOW_CHILDREN_READ);

        System.out.println("\nWith compile");

        // Add null children
        for (int i = 0; i < kNumChildren; i++)
            vGroup.addChild(null);
        System.out.println("children added");
        
        System.out.println("#children (before compile): " + vGroup.numChildren());
        vGroup.compile();
        System.out.println("#children (after compile): " + vGroup.numChildren());
        System.out.println("set children");

        // Set children
        for (int i = 0; i < kNumChildren; i++)
            vGroup.setChild(new BranchGroup(), i);
    }


    /**
     * Sets up the scene branch part of the Java3D scene graph.
     *
     * First, creates the root of the branch, then adds a transform and mouse 
     * behaviors and the root of the scene objects.
     */
    protected void setupSceneBranch()
    {
        // Create root of scene branch
        BranchGroup vSceneBranch = new BranchGroup();
        vSceneBranch.setCapability(BranchGroup.ALLOW_DETACH);

        // Create transform group of mouse behavior
        TransformGroup vMouseTransform = new TransformGroup();
        vMouseTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
        vMouseTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

        // Create transform group of scene branch
        mSceneTransform = new TransformGroup();
        mSceneTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
        mSceneTransform.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

        vMouseTransform.addChild(mSceneTransform);
        vSceneBranch.addChild(vMouseTransform);

        // Behaviors
        BoundingSphere vBounds = new BoundingSphere(new Point3d(0,0,0),
                                                    60.0f);
        
        MouseRotate vRotate = new MouseRotate(vMouseTransform);
        vRotate.setSchedulingBounds(vBounds);

        MouseTranslate vTranslate = new MouseTranslate(vMouseTransform);
        vTranslate.setSchedulingBounds(vBounds);

        MouseZoom vZoom = new MouseZoom(vMouseTransform);
        vZoom.setSchedulingBounds(vBounds);

        // Link behaviors to view branch
        vMouseTransform.addChild(vRotate);
        vMouseTransform.addChild(vTranslate);
        vMouseTransform.addChild(vZoom);

        // Setup base of graph branch
        mGraphBranch = new BranchGroup();
        mGraphBranch.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
        mGraphBranch.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
        mGraphBranch.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);

        // Attach to scene branch
        mSceneTransform.addChild(mGraphBranch);

        vSceneBranch.compile();
        mUniverse.addBranchGraph(vSceneBranch);
    }


    /**
     * Sets up the view branch part of the Java3D scene graph.
     *
     * Sets the clipping distances, window resize policy, and adds the
     * lighting properties.
     */
    protected void setupViewBranch()
    {
        View vView = mUniverse.getViewer().getView();
        
        // Set the clipping distances
        vView.setBackClipDistance(80.0);
        
        vView.setWindowResizePolicy(View.VIRTUAL_WORLD);
        vView.setTransparencySortingPolicy(View.TRANSPARENCY_SORT_GEOMETRY);
        vView.setSceneAntialiasingEnable(true);

        // Set view transform
        mViewTransform = mUniverse.getViewingPlatform().getMultiTransformGroup().getTransformGroup(0);

        // Create lighting branch
        BranchGroup vLighting = new BranchGroup();
        addLighting(vLighting);

        // Compile and attach to locale
        vLighting.compile();
        mUniverse.addBranchGraph(vLighting);
    }


    /**
     * Creates an ambient and directional light, sets up their influencing bounds,
     * and adds them to the view branch.
     *
     * @param pLighting  the root of lighting branch
     */
    protected void addLighting(BranchGroup pLighting)
    {
        // Set universe bounds of influence
        BoundingSphere vBounds = new BoundingSphere(new Point3d(0,0,0), 60.0f);
        
        // Create a lighting model
        AmbientLight vAmbient = new AmbientLight();
        DirectionalLight vDirectional = new DirectionalLight();

        // Setup influencing region
        vAmbient.setInfluencingBounds(vBounds);
        vDirectional.setInfluencingBounds(vBounds);

        // Add to scene graph
        pLighting.addChild(vAmbient);
        pLighting.addChild(vDirectional);
    }


    /**
     * Creates a graphics template that Canvas3D uses to create a canvas and
     * returns the configuration.
     */
    public static GraphicsConfiguration createGraphicsConfig()
    {
        // Create the template
        GraphicsConfigTemplate3D vGraphicsTemplate = new GraphicsConfigTemplate3D();
        
        vGraphicsTemplate.setStereo(GraphicsConfigTemplate3D.PREFERRED);
        vGraphicsTemplate.setSceneAntialiasing(GraphicsConfigTemplate3D.PREFERRED);

        // Then find a configuration that fits
        GraphicsDevice vDevice = 
            GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice();

        return vDevice.getBestConfiguration(vGraphicsTemplate);
    }


    /**
     *
     */
    public static void main(String[] pArguments)
    {
        try
        {
            TestCase vTest = new TestCase();
            vTest.runTest();
        }

        catch (Exception e)
        {
            e.printStackTrace();
        }
    }
    
}

