// class BounceOff by Alexander Barth, Gerd Trautner, yuri(RR) 1998
// alexander.barth@fhs-hagenberg.ac.at
// gerd@mond.at
// http://yuri.weirdoz.org

import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.event.*;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.universe.*;
import com.sun.j3d.utils.geometry.*;
import javax.media.j3d.*;
import javax.vecmath.*;

public class BounceOff extends Applet{
	
	private BallBehavior ballBhv;
	
	private BranchGroup createSceneGraph() {
    	
		// define an appearance and radius of sphere
		Color3f white = new Color3f(1.0f, 1.0f, 1.0f);
	        Color3f black = new Color3f(0.0f, 0.0f, 0.0f);
		Appearance whiteApp = new Appearance();
		whiteApp.setMaterial(new Material(white, black, white, white, 20.0f));
		float sRadius = 0.5f;

		// defining an appearance and radius/height of cylinder
		Color3f red = new Color3f(1.0f, 0.0f, 0.0f);
		Appearance redApp = new Appearance();
		redApp.setMaterial(new Material(red, black, red, red, 10.0f));
		float gRadius = 2f;
		float height = 1f;

		// define a sphere - startposition
		Vector3d sPosition = new Vector3d(0.0, 5.5, 0.0);

		// ==============================================================================
		// Create the root of the branch graph
		// ==============================================================================		
		BranchGroup objRoot = new BranchGroup();
		
		// ==============================================================================		
		// Create a bounds for the background and lights
		// ==============================================================================		
		BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 10);
		
		// ==============================================================================	
		// Set up the background
		// ==============================================================================		
		Background bg = new Background();
		bg.setApplicationBounds(bounds);
		objRoot.addChild(bg);
		
		// ==============================================================================	
		// Set up the global lights
		// ==============================================================================		
		Color3f lColor1 = new Color3f(0.7f, 0.7f, 0.7f);
		Vector3f lDir1  = new Vector3f(-1.0f, -1.0f, -1.0f);
		Color3f alColor = new Color3f(0.2f, 0.2f, 0.2f);
	
		AmbientLight aLgt = new AmbientLight(alColor);
		aLgt.setInfluencingBounds(bounds);
		DirectionalLight lgt1 = new DirectionalLight(lColor1, lDir1);
		lgt1.setInfluencingBounds(bounds);
		objRoot.addChild(aLgt);
		objRoot.addChild(lgt1);
				
		// ==============================================================================	
		// create a sphere with a BallBehavior and attach it to objRoot
		// ==============================================================================		
		TransformGroup sphereTrans = new TransformGroup();
		Transform3D stranslate = new Transform3D();

		sphereTrans.setTransform(stranslate);
		stranslate.setTranslation(sPosition);
		// Set the Capability to allow Transformgroup read and write)
			try{
				sphereTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
				sphereTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
			}
			catch(RestrictedAccessException e){
				System.out.println("Capability bit 'transform read/write' of sphereTrans not set!");
				System.out.println(e);
			}
		objRoot.addChild(sphereTrans);
	
		// create Sphere		
		Sphere sphere = new Sphere(sRadius, Sphere.GENERATE_NORMALS, 15, whiteApp);
		// Set the CollisionBounds of the Sphere
		sphere.setCollisionBounds(new BoundingSphere(new Point3d(0.0,0.0,0.0), sRadius));
		// Set the Capability to allow CollisionBounds read)	
			try{
				sphere.setCapability(Sphere.ALLOW_COLLISION_BOUNDS_READ);
			}
			catch(RestrictedAccessException e){
				System.out.println("Capability bit 'transform read/write' of sphereTrans not set!");
				System.out.println(e);
			}
		sphereTrans.addChild(sphere);

		ballBhv = new BallBehavior(sphere, sphereTrans, sPosition);
		ballBhv.setSchedulingBounds(new BoundingSphere(new Point3d(0.0,0.0,0.0), 35.0));
		sphereTrans.addChild(ballBhv);

				
		// ==============================================================================
		// create a ground where the sphere can bounce off
		// ==============================================================================		
		TransformGroup groundTrans = new TransformGroup();
		Transform3D translate = new Transform3D();
		translate.setTranslation(new Vector3d(0.0, -3.0, 0.0));

		
		Sphere ground = new Sphere(gRadius, Sphere.GENERATE_NORMALS, 15, redApp);
		ground.setCollisionBounds(new BoundingSphere(new Point3d(0.0,0.0,0.0),gRadius));

		groundTrans.addChild(ground);
		groundTrans.setTransform(translate);
		objRoot.addChild(groundTrans);		
		
		// ==============================================================================
		// let JAVA3D perform optimizations on this Group
		// ==============================================================================				
	        objRoot.compile();
        	
		return objRoot;
    }
    	
    public BounceOff() {
    	setLayout(new BorderLayout()); Canvas3D c = new Canvas3D(null); add("Center", c);

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


	    // This will move the ViewPlatform back a bit so the objects 
	    //in the scene can be viewed.

		Viewer viewer = new Viewer(c);
		
		ViewingPlatform viewing = new ViewingPlatform();
		TransformGroup Viewtransform = viewing.getViewPlatformTransform();


		Transform3D Viewtrans3D = new Transform3D();
		Viewtrans3D.set(new Vector3d(0.0, 0.0, 20.0));
		Viewtransform.setTransform(Viewtrans3D);
		
		SimpleUniverse u = new SimpleUniverse(viewing,viewer);
			    
	        u.getViewingPlatform().getViewPlatform().setActivationRadius(30.0f);
		u.addBranchGraph(scene);
    }

    
    // run as an application as well as an applet:
        
    public static void main(String[] args) {
		new MainFrame(new BounceOff(), 640, 480);
    }
}
