
import java.applet.Applet;
import java.awt.*;
import java.awt.event.*;
import java.applet.*;
import java.net.*;
import javax.swing.*;
import java.awt.event.*;
import java.awt.event.WindowAdapter;

import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.geometry.Sphere;
import com.sun.j3d.utils.geometry.Box;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.image.TextureLoader;
import com.sun.j3d.utils.behaviors.mouse.*;
import javax.media.j3d.*;
import javax.vecmath.*;

/**
 * Title: LittleScene class
 * Description: This class contains a small scene with some objects and lights
 * Copyright: Copyright (c) 2001
 * Company: Uni Frankfurt
 * @author Martin Klossek
 * @version 1.0
 */

public class LittleScene extends JApplet {

	/* member variables for some transform groups */
	TransformGroup objTrans, objRotIntPol,
		objPointLightGroup, objPointLightHoodGroup,
		tgLittleScene,
		objSphereHoodGroup, objBoxHoodGroup, objTetraederHoodGroup;

	/* some further 3Dish member variables */
	float angle = 0.0f;
	Transform3D trans = new Transform3D();
	private SimpleUniverse u = null;
	URL urlTexture1 = null;
	static String m_sTextureFileName1 = "stone.jpg";

	/* and some other member variables for different needs */
	JButton buttonRotate = new JButton("Rotate");
        boolean isStandalone = false;



        /**
	 * Get a parameter value
	 */
        public String getParameter(String key, String def) {
                return isStandalone ? System.getProperty(key, def) :
                        (getParameter(key) != null ? getParameter(key) : def);
        }

	/**
	 * Method returns a fresh transform group which is capable of transform
	 * reads and writes during runtime
	 *
	 * @return a new TransformGroup instance with allowtransformread|write set
	 */
	private TransformGroup getActiveTransformGroup () {

		/* create new object */
		TransformGroup tgNew = new TransformGroup ();

		/* set the capabilties for the new group */
		tgNew.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		tgNew.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);

		/* and give it back to caller */
		return tgNew;
	}

	/**
	 * Load a texture into a new Texture3D instance
	 */
	private Texture loadTexture () {

	        Texture texNew = null;

	        try {
			/* load texture in sFileName into object */
			// TextureLoader tlNew = new TextureLoader (new URL(getCodeBase().toString() + sFileName), this);
			TextureLoader tlNew = new TextureLoader (urlTexture1, this);
			ImageComponent2D imgNew = tlNew.getImage();

			/* set probably loaded texture to the texNew variable */
			texNew = tlNew.getTexture();

		} catch (Exception ex) {
			System.out.println ( "could not load texture from " + m_sTextureFileName1 );
			ex.printStackTrace();
		}

		/* return to caller */
		return texNew;
	}

	/**
	 * Creates the top BranchGroup containing our whole little scene
	 */
	public BranchGroup createSceneGraph() {

		/* Create the root of the branch graph */
		BranchGroup objRoot = new BranchGroup();

		/* Create some transform group nodes to positionate our objects. Add
		it them to the root of the subgraph. */
		objTrans = getActiveTransformGroup();
		objRotIntPol = getActiveTransformGroup();
		objPointLightGroup = getActiveTransformGroup();
		objPointLightHoodGroup = new TransformGroup();

		/* the following transformgroups contains the box, sphere and tetraeder
		plus a group containing all the hoodgroups for behaviour playing */
		tgLittleScene = getActiveTransformGroup();
		objSphereHoodGroup = new TransformGroup();
		objBoxHoodGroup = new TransformGroup();
		objTetraederHoodGroup = new TransformGroup();

		/* create box appearance instance */
		Appearance objBoxAppearance = new Appearance ();
		objBoxAppearance.setTransparencyAttributes(new TransparencyAttributes(
			TransparencyAttributes.NICEST, 0.2f
		));
		Material objBoxMaterial = new Material(new Color3f(.2f,.2f,.2f),
			new Color3f(.0f,.0f,.6f),
			new Color3f(0.5f,0.5f,0.5f),
			new Color3f(.8f,.8f,.8f),
			96.0f);
		objBoxAppearance.setMaterial (objBoxMaterial);

		/* create sphere appearance instance */
		Appearance objSphereAppearance = new Appearance ();
		objSphereAppearance.setTransparencyAttributes(new TransparencyAttributes(
			TransparencyAttributes.FASTEST, 0.2f
		));
		Material objSphereMaterial = new Material(new Color3f(.0f,.4f,.0f),
			new Color3f(.0f,.2f,.0f),
			new Color3f(0.8f,0.8f,0.8f),
			new Color3f(.8f,.8f,.8f),
			64.0f);
		objSphereAppearance.setMaterial (objSphereMaterial);

		/* create tetraeder appearance instance with texture */
		Appearance objTetraederAppearance = new Appearance ();
		Texture texTetraeder = loadTexture ();
		if (texTetraeder != null) { objTetraederAppearance.setTexture(texTetraeder); }
	        TextureAttributes texAttr = new TextureAttributes();
	        texAttr.setTextureMode(TextureAttributes.MODULATE);
	        objTetraederAppearance.setTextureAttributes(texAttr);
		Material objTetraederMaterial = new Material(new Color3f(.2f,.2f,.2f),
			new Color3f(.8f,.0f,.0f),
			new Color3f(1.0f,1.0f,1.0f),
			new Color3f(.8f,.8f,.8f),
			96.0f);
		objTetraederAppearance.setMaterial (objTetraederMaterial);

		/* create a sphere, move it to (5|0|0) in world coordinates and embed it in our scene */
		Sphere sphereOne = new Sphere (1.0f, Sphere.GENERATE_NORMALS | Sphere.GENERATE_TEXTURE_COORDS, 20, objSphereAppearance);
		objSphereHoodGroup.addChild (sphereOne);
		Transform3D tfSphere = new Transform3D();
		tfSphere.setTranslation(new Vector3f(5.0f, 0.0f, 0.0f));
		objSphereHoodGroup.setTransform (tfSphere);
		tgLittleScene.addChild (objSphereHoodGroup);

		/* create a box, move it to (-5|0|0) in world coordinates and embed it in our scene */
		Box boxOne = new Box (1.0f, 1.0f, 1.0f, objBoxAppearance);
		objBoxHoodGroup.addChild (boxOne);
		Transform3D tfBox = new Transform3D();
		tfBox.setTranslation(new Vector3f(-5.0f, 0.0f, 0.0f));
		objBoxHoodGroup.setTransform (tfBox);
		tgLittleScene.addChild (objBoxHoodGroup);

		/* create the tetraeder and add it to the scene graph at (0|0|0) */
		Tetraeder tetraederOne = new Tetraeder (objTetraederAppearance);
		objTetraederHoodGroup.addChild (tetraederOne);
		Transform3D tfTetraeder = new Transform3D();
		tfTetraeder.setTranslation(new Vector3f(-1.0f, -1.0f, 1.0f));
		tfTetraeder.setScale(2.0);
		objTetraederHoodGroup.setTransform (tfTetraeder);
		tgLittleScene.addChild(objTetraederHoodGroup);

		/* make a rotation around both the x- and y-axis */
		/* Transform3D objTransform1 = new Transform3D ();
		objTransform1.setTranslation(new Vector3f(0.5f,0.0f,0.0f));
		Transform3D objTransform2 = new Transform3D ();
		objTransform2.rotX(Math.PI / 4.0d);
		Transform3D objTransform3 = new Transform3D ();
		objTransform3.rotY(Math.PI / 4.0d);
		objTransform2.mul(objTransform3);
		// objRotIntPol.setTransform (objTransform1);
		// objTransform2.mul(objTransform1);
		objTrans.setTransform(objTransform2); */

		/* make some tests with the Alpha class (well, -1 means loop
		forever and 4000 are 4 seconds for one loop) */
		// Alpha objAlpha1 = new Alpha (-1, 4000);
		// sinus pendulum time generator: Alpha objAlpha1 = new Alpha (-1, Alpha.INCREASING_ENABLE | Alpha.DECREASING_ENABLE, 0, 0,
		//	2000, 4000, 0, 2000, 4000, 0 );
		/* Alpha objAlpha1 = new Alpha (-1, Alpha.INCREASING_ENABLE, 0, 0,
		        2000, 0, 0, 2000, 4000, 0 ); */

		/* and now introduce the rotationinterpolator */
		BoundingSphere bounds = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
		/* RotationInterpolator objRotIntPol1 = new RotationInterpolator (objAlpha1, objRotIntPol,
			new Transform3D(), 0, (float)Math.PI*2.0f); // if you use a transform matrix not the identity
			// matrix you can make translations and more... (like objTransform1)
		objRotIntPol1.setSchedulingBounds(bounds);
		objRotIntPol.addChild(objRotIntPol1); */

		/* create the AWTInteractionBehavior for behaviour control via an awt-button */
		/* AWTInteractionBehavior awtBehavior = new AWTInteractionBehavior(objTrans);
		buttonRotate.addActionListener(awtBehavior);
		awtBehavior.setSchedulingBounds(bounds2);
		objRoot.addChild(awtBehavior); */

		/* switch on the light! ambient and directlight */
		AmbientLight lightAmbient1 = new AmbientLight(new Color3f(.7f, .7f, .7f));
		BoundingSphere bounds2 = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
		lightAmbient1.setInfluencingBounds(bounds2);
		objRoot.addChild(lightAmbient1);
		DirectionalLight lightDirec1 = new DirectionalLight(new Color3f(.4f, .4f, .4f), new Vector3f(1.0f,1.0f,-1.0f));
		lightDirec1.setInfluencingBounds(bounds2);
		objRoot.addChild(lightDirec1);

		/* create a moving point light */
		PointLight lightPoint1 = new PointLight(new Color3f (0.7f, 0.2f, 0.2f), new Point3f(.0f, .0f, .0f), new Point3f(.5f, 0.0f, 0.0f));
		lightPoint1.setInfluencingBounds(bounds2);
		objPointLightGroup.addChild(lightPoint1);
		// DEBUG: objPointLightGroup.addChild(new ColorCube(0.05));

		/* and now introduce the rotationinterpolator for the light */
		Alpha objPointLightRotatorAlpha = new Alpha (-1, Alpha.INCREASING_ENABLE, 0, 0,
		        5000, 0, 0, 5000, 0, 0 );
		Transform3D objPointLightTransform = new Transform3D ();
		objPointLightTransform.setTranslation(new Vector3f(8.0f,0.0f,0.0f));
		RotationInterpolator objPointLightRotator = new RotationInterpolator (objPointLightRotatorAlpha, objPointLightGroup,
			objPointLightTransform, 0, (float)Math.PI*2.0f);
		objPointLightRotator.setSchedulingBounds(bounds);
		objPointLightGroup.addChild(objPointLightRotator);

		Transform3D objPointLightHoodTransform = new Transform3D ();
		objPointLightHoodTransform.setTranslation(new Vector3f(-8.0f,0.0f,0.0f));
		objPointLightHoodGroup.setTransform(objPointLightHoodTransform);
		objPointLightHoodGroup.addChild (objPointLightGroup);
		objRoot.addChild (objPointLightHoodGroup);

		/* make it zoomable via mouse */
		BoundingSphere boundsLittleScene = new BoundingSphere(new Point3d(0.0, 0.0, 0.0), 100.0);
		MouseBehavior bvrMouseZoom = new MouseZoom();
		 bvrMouseZoom.setTransformGroup (tgLittleScene);
		 bvrMouseZoom.setSchedulingBounds (boundsLittleScene);
		 tgLittleScene.addChild(bvrMouseZoom);
		MouseBehavior bvrMouseRotate = new MouseRotate();
		 bvrMouseRotate.setTransformGroup (tgLittleScene);
		 bvrMouseRotate.setSchedulingBounds (boundsLittleScene);
		 tgLittleScene.addChild(bvrMouseRotate);
		MouseBehavior bvrMouseTranslate = new MouseTranslate();
		 bvrMouseTranslate.setTransformGroup (tgLittleScene);
		 bvrMouseTranslate.setSchedulingBounds (boundsLittleScene);
		 tgLittleScene.addChild(bvrMouseTranslate);
		objRoot.addChild (tgLittleScene);

		/* functions returns a branchgroup which will be connected to the
		locale as the content graph */
		return objRoot;
	}

	/**
	 * Construct the applet
	 */
	public LittleScene() { }

	/**
	 * Construct the application with url to texture file
	 *
	 * @param urlTextureFile url to an image which should be used as the
	 * texture for the tetraeder
	 */
	public LittleScene(java.net.URL urlTextureFile) {
	        urlTexture1 = urlTextureFile;
	}

        /**
	 * Initialize the applet
	 */
        public void init() {

		/* in applet mode the texture image is not loaded */
		if (urlTexture1 == null) {
			try {
				urlTexture1 = new URL (getCodeBase().toString() + m_sTextureFileName1);
			} catch (Exception ex) {
				System.out.println ("error loading file " + m_sTextureFileName1);
			}
		}

		/* make the borland game... */
                try {
                        jbInit();
                }
                catch(Exception e) {
                        e.printStackTrace();
                }
        }

	/**
	 * applet killing method
	 */
	public void destroy() {
		u.removeAllLocales();
	}

        /** Component initialization from jbuilder */
        private void jbInit() throws Exception {
                this.setSize(new Dimension(400,300));

		getContentPane().setLayout(new BorderLayout());
		GraphicsConfiguration config =
		   SimpleUniverse.getPreferredConfiguration();

		Canvas3D c = new Canvas3D(config);
		getContentPane().add("Center", c);

		// JPanel p = new JPanel();
		// p.add(buttonRotate);
		// getContentPane().add("North", p);

		/* Create a simple scene and attach it to the virtual universe */
		BranchGroup scene = createSceneGraph();
		scene.setCapability( BranchGroup.ALLOW_BOUNDS_READ );

		/* create a new simple universe (simple because we do not have
		to think about view platforms, etc. */
		u = new SimpleUniverse(c);

		/* This will move the ViewPlatform back a bit so the
		objects in the scene can be viewed (the viewer is not at 0,0,2.41 */
		u.getViewingPlatform().setNominalViewingTransform();

		/* Move the ViewPlatform to a point where we can see the whole
		scene with its three objects */
                Transform3D oTransform3D = new Transform3D();
                // u.getViewingPlatform().getMultiTransformGroup().getTransformGroup(0).getTransform( oTransform3D );
                oTransform3D.set( new Vector3d( 0, 0, 17 ) );
                u.getViewingPlatform().getMultiTransformGroup().getTransformGroup(0).setTransform( oTransform3D );

		/* and add our scene to the the universe */
		u.addBranchGraph(scene);

        }

        /**
	 * Get Applet information
	 */
        public String getAppletInfo() {
                return "Applet Information";
        }

        /**
	 * Get parameter info
	 */
        public String[][] getParameterInfo() {
                return null;
        }

        /* static initializer for setting look & feel */
        static {
                try {
                        //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                        //UIManager.setLookAndFeel(UIManager.getCrossPlatformLookAndFeelClassName());
                }
                catch(Exception e) {
                }
        }

	/**
	 * The method method in conjunction with the MainFrame class from java3d
	 * makes the applet run as app to with no further handcoded functionality
	 */
	public static void main(String[] args) {

		/* get an image for the tetraeder texture in application mode */
		java.net.URL urlTextureFile = null;
		try {
	                urlTextureFile = new java.net.URL("file:" + m_sTextureFileName1);
		} catch (java.net.MalformedURLException ex) {
		        System.out.println(ex.getMessage());
		        System.exit(1);
		}

		/* create the mainframe with the embedded applet instance */
	        new MainFrame (new LittleScene(urlTextureFile), 256, 256);

        }

}
