/*
 * @(#)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 TestCase 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();
            
            // Adjust the view z-coordinate
            Vector3d vView = new Vector3d(0, 0, 30);

            // Move the viewpoint in the universe
            Transform3D vTransform = new Transform3D();
            vTransform.setTranslation(vView);
            mViewTransform.setTransform(vTransform);
            
            super.setVisible(true);
        }
        
        catch (Exception e)
        {
            System.out.println("Could not create TestCase.");
        }
    }


    /**
     * Runs the test case.
     */
    public void runTest()
    {
        boolean kUseReference = false;

        int vNumCoords = 4;
        
        double[] vCoordinates = new double[vNumCoords*3];
        float[] vNormals = new float[vNumCoords*3];

        // Create strip count array
        int[] vStripCounts = { vNumCoords };

        // Set flags
        int vFlags = GeometryArray.COORDINATES | GeometryArray.NORMALS;
        if (kUseReference)
            vFlags |= GeometryArray.BY_REFERENCE;
        
        TriangleStripArray vTriangles = new TriangleStripArray(4, vFlags, vStripCounts);
        
        // Set coordinates
        vCoordinates[0] = 0;
        vCoordinates[1] = 1;
        vCoordinates[2] = 0;

        vCoordinates[3] = 0;
        vCoordinates[4] = 0;
        vCoordinates[5] = 0;

        vCoordinates[6] = 1;
        vCoordinates[7] = 1;
        vCoordinates[8] = 0;

        vCoordinates[9] = 1;
        vCoordinates[10] = 0;
        vCoordinates[11] = 0;

        // Set normals
        vNormals[0] = 0;
        vNormals[1] = 0;
        vNormals[2] = 1;

        vNormals[3] = 0;
        vNormals[4] = 0;
        vNormals[5] = 1;

        vNormals[6] = 0;
        vNormals[7] = 0;
        vNormals[8] = 1;

        vNormals[9] = 0;
        vNormals[10] = 0;
        vNormals[11] = 1;

        // Set arrays
        if (kUseReference)
        {
            vTriangles.setCoordRefDouble(vCoordinates);
            vTriangles.setNormalRefFloat(vNormals);
        }
        else
        {
            vTriangles.setCoordinates(0, vCoordinates);
            vTriangles.setNormals(0, vNormals);
        }

        // Create appearance
        Appearance vAppearance = new Appearance();

        // Set color
        Material vMaterial = new Material();
        vMaterial.setDiffuseColor(new Color3f(Color.red));
        vAppearance.setMaterial(vMaterial);

        PolygonAttributes vPolygon = new PolygonAttributes();
        vPolygon.setPolygonMode(PolygonAttributes.POLYGON_LINE);
        vAppearance.setPolygonAttributes(vPolygon);
        
        BranchGroup vObject = new BranchGroup();
        vObject.addChild(new Shape3D(vTriangles, vAppearance));
        
        mGraphBranch.addChild(vObject);
    }


    /**
     * 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();
        }
    }
    
}

