
import com.sun.j3d.utils.geometry.Sphere;
import com.sun.j3d.utils.universe.*;
import javax.media.j3d.*;
import javax.vecmath.*;
import java.awt.*;
import com.sun.j3d.utils.image.TextureLoader;
import com.sun.j3d.utils.geometry.Primitive;


/* Phases of the Moon Application
 * 
 * Developed by Cristina Vinas Vinuales - Institute for Biocomputation and Physics of Complex Systems (BIFI) - Zaragoza
 * for Science on Stage on January 2012
 * 
 */

public class Animation extends javax.swing.JPanel  {
   
	/**
	 * 
	 */
	private static final long serialVersionUID = 4736196693696740998L;
	/***********************************************************************************************************************/
	/*   TYPES AND CONSTANTS DEFINITIONS  */
    /***********************************************************************************************************************/
	
    // Constants for type of light to use
    private static final int DIRECTIONAL_LIGHT = 0;
    private static final int POINT_LIGHT = 1;
    private static final int SPOT_LIGHT = 2;

    // Flag indicates type of lights: directional, point, or spot
    // lights.  This flag is set based on command line argument
    private static int lightType = POINT_LIGHT;

 
    /***********************************************************************************************************************/
    /*   METHODS  */
    /***********************************************************************************************************************/
	
    public BranchGroup createSceneGraph() {
    
		Color3f moonColor = new Color3f(0.1f, 0.1f, 0.1f); 		//moon colors
		Color3f emismoonColor = new Color3f(0.3f, 0.3f, 0.3f); 
		Color3f specmoonColor = new Color3f(1.0f, 1.0f, 1.0f);			
		Color3f lColor2   = new Color3f(1.0f, 1.0f, 0.4f); 		//sun yellow color
		Color3f alColor   = new Color3f(0.3f, 0.3f, 0.3f);		//ambient color		
		Color3f bgColor   = new Color3f(0.05f, 0.05f, 0.1f); 	//background
	
		// Create the root of the branch graph
		BranchGroup objRoot = new BranchGroup();
	
	    // Create a Transformgroup to scale all objects so they appear in the scene.
	    objScale = new TransformGroup();
	    Transform3D t3d = new Transform3D();
	    t3d.setScale(0.4);
	    objScale.setTransform(t3d);
	    objRoot.addChild(objScale);
	
		// Create a bounds for the background and lights
		BoundingSphere bounds =  new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0);
	
		// Set up the background
		Background bg = new Background(bgColor);
		bg.setApplicationBounds(bounds);
		objScale.addChild(bg);
		
		// Ambient Light
		AmbientLight aLgt = new AmbientLight(alColor);
		aLgt.setInfluencingBounds(bounds);
		objScale.addChild(aLgt);

		//EARTH ---------------------------------------------------------------------		
		// Set up colors
	    Color3f black = new Color3f(0.2f, 0.2f, 0.2f);
	    Color3f blue = new Color3f(0.4f, .4f, .75f);
		
		// Set up the texture map
	    TextureLoader loader = new TextureLoader("images/Earth.jpg","RGB", new Container());
	    Texture texture = loader.getTexture();
	    texture.setBoundaryModeS(Texture.WRAP);
	    texture.setBoundaryModeT(Texture.WRAP);
	    texture.setBoundaryColor(new Color4f(0.0f, 1.0f, 0.0f, 0.0f));
	    TextureAttributes texAttr = new TextureAttributes();
	    texAttr.setTextureMode(TextureAttributes.MODULATE);
	    
		//Create the Transform Group Tree
		TransformGroup EarthRotation = new TransformGroup();
		EarthRotation.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		objScale.addChild(EarthRotation);
		Transform3D tr = new Transform3D();
		Vector3d posEarth = new Vector3d(0.0,0.0,0.0);
		tr.set(posEarth);
		tr.rotX(Math.PI/2.0);
		TransformGroup tgEarth = new TransformGroup(tr);
		EarthRotation.addChild(tgEarth);
		
		// Create a Sphere object, and add it into the scene graph.
		Appearance a = new Appearance();
		a.setTexture(texture);
		a.setTextureAttributes(texAttr);
		a.setMaterial(new Material(blue, black, blue, black, 1.f));
		int primflags = Primitive.GENERATE_NORMALS + Primitive.GENERATE_TEXTURE_COORDS;
		Sphere sph = new Sphere(0.8f, primflags, 80, a);
		tgEarth.addChild(sph);
		
		// Behaviour
		Transform3D axisRot = new Transform3D();
		axisRot.rotX(Math.PI/2.0);	
		Alpha earthAlpha = new Alpha(-1, Alpha.INCREASING_ENABLE,  0, 0, 1034, 0, 0, 0, 0, 0); //1034 to make 29 rotations in 30 seconds 
		rotatorEarth = new RotationInterpolator(earthAlpha, EarthRotation, axisRot,  0.0f, (float) Math.PI*2.0f);
		rotatorEarth.setSchedulingBounds(bounds);
		EarthRotation.addChild(rotatorEarth);
		

		//MOON ---------------------------------------------------------------------
		// Create the transform group node for the moon. Enable the TRANSFORM_WRITE capability so that
		// our behavior code can modify it at runtime.  Add them to the root of the subgraph.
		
		TransformGroup lMoonRotTrans = new TransformGroup();
		lMoonRotTrans.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		lMoonRotTrans.setCapability(TransformGroup.ALLOW_CHILDREN_WRITE);
		lMoonRotTrans.setCapability(TransformGroup.ALLOW_CHILDREN_EXTEND);
		objScale.addChild(lMoonRotTrans);
		
		BranchGroup moonBG = new BranchGroup();
		moonBG.setCapability(BranchGroup.ALLOW_DETACH);
		moonBG.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
		lMoonRotTrans.addChild(moonBG);
		
		// Create position for the Moon
		Transform3D tm = new Transform3D();
		Vector3d lPosMoon =  new Vector3d(1.5, 0.0, 0.0);
		tm.set(lPosMoon);
		
		//Create TG for the moon to attach the position and the sphere
		TransfMoon = new TransformGroup(tm);	
		TransfMoon.setCapability(TransformGroup.ALLOW_CHILDREN_WRITE);
		TransfMoon.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
		TransfMoon.setCapability(TransformGroup.ALLOW_CHILDREN_EXTEND);
		moonBG.addChild(TransfMoon);
			
		//Material Moon
		Appearance appMoon = new Appearance();
		Material mMoon = new Material(moonColor, emismoonColor, moonColor, specmoonColor, 5.0f);
		mMoon.setLightingEnable(true);
		appMoon.setMaterial(mMoon);
		TransfMoon.addChild(new Sphere(0.15f, Sphere.GENERATE_NORMALS, 80, appMoon));
						
				
		//SUN ------------------------------------------------------------------
		Transform3D ts = new Transform3D();
		Vector3d lPosSun = new Vector3d(10.2, 0.0, 0.0);
		ts.set(lPosSun);
		TransformGroup TransfSun = new TransformGroup(ts);
		objScale.addChild(TransfSun);	
		// Create Geometry for point lights
		ColoringAttributes caLSun = new ColoringAttributes();
		caLSun.setColor(lColor2);
		Appearance appL2 = new Appearance();
		appL2.setColoringAttributes(caLSun);
		TransfSun.addChild(new Sphere(7.5f, Sphere.GENERATE_NORMALS, 80, appL2));		
		//light
		Light lgtSun = null;
		Point3f lPoint  = new Point3f(0.0f, 0.0f, 0.0f);
		Point3f atten = new Point3f(0.5f, 0.0f, 0.0f);
		Vector3f lDirect2 = new Vector3f(lPosSun);
		lDirect2.negate();
		switch (lightType) {
		case DIRECTIONAL_LIGHT:
			lgtSun = new DirectionalLight(lColor2, lDirect2);
		    break;
		case POINT_LIGHT:
			lgtSun = new PointLight(lColor2, lPoint, atten);
		    break;
		case SPOT_LIGHT:
			lgtSun = new SpotLight(lColor2, lPoint, atten, lDirect2, 25.0f * (float)Math.PI / 180.0f, 10.0f);
		    break;
		}
		// Set the influencing bounds	
		lgtSun.setInfluencingBounds(bounds);
		// Add the lights into the scene graph	
		TransfSun.addChild(lgtSun);
		
		//--------------------------------------------------------------------------
		//3D Texts
		//Create the Transform Group Tree
		Transform3D tr4 = new Transform3D();
		tr4.setScale(0.10);
		TransformGroup TG = new TransformGroup(tr4);
		objScale.addChild(TG);
		
		addTextGraph(TG, "New Moon", new Vector3d(17.0f, 0.0f, 0.0f));
		addTextGraph(TG, "Waxing Crescent", new Vector3d(12.0f, 12.0f, 0.0f));
		addTextGraph(TG, "First Quarter", new Vector3d(-2.5f, 17.0f, 0.0f));
		addTextGraph(TG, "Waxing Gibbous", new Vector3d(-19.0f, 12.0f, 0.0f));
		addTextGraph(TG, "Full Moon", new Vector3d(-22.0f, 0.0f, 0.0f));
		addTextGraph(TG, "Waning Gibbous", new Vector3d(-19.0f, -13.0f, 0.0f));
		addTextGraph(TG, "Third Quarter", new Vector3d(-2.5f, -18.0f, 0.0f));
		addTextGraph(TG, "Waning Crescent", new Vector3d(12.0f, -13.0f, 0.0f));
		
		
	    // Let Java 3D perform optimizations on this scene graph.
	    objRoot.compile();
	
	    return objRoot;
    }
    
    /***********************************************************************************************************************/
    
    private void addTextGraph(TransformGroup TrGr, String text, Vector3d position) {
    	
    	//Add the 'text' to a TrGr' group to see in the scene at a 'position'
    	Appearance a4 = new Appearance();
		ColoringAttributes caLTxt = new ColoringAttributes();
		caLTxt.setColor(new Color3f(0.3f, 0.3f, 0.3f));
		a4.setColoringAttributes(caLTxt);
		Shape extrusionShape = new java.awt.geom.Line2D.Double(0, 0, 0, 0);
		Font3D f3d = new Font3D(new Font("Full Moon", Font.PLAIN, 1), new FontExtrusion(extrusionShape));
		
    	Text3D txt1 = new Text3D(f3d,text,new Point3f((float) position.x, (float)position.y, (float) position.z));				
		Shape3D s3D1 = new Shape3D();
	    s3D1.setGeometry(txt1);
	    s3D1.setAppearance(a4);		    
	    TrGr.addChild(s3D1);
    	
    }
    /***********************************************************************************************************************/
	
    private Canvas3D createUniverse() {
    	
		// Get the preferred graphics configuration for the default screen
		GraphicsConfiguration config =
		    SimpleUniverse.getPreferredConfiguration();
	
		// Create a Canvas3D using the preferred configuration
		Canvas3D c = new Canvas3D(config);
	
		// Create simple universe with view branch
		univ = new SimpleUniverse(c);
	
		// This will move the ViewPlatform back a bit so the
		// objects in the scene can be viewed.
		univ.getViewingPlatform().setNominalViewingTransform();
	
		// Ensure at least 5 msec per frame (i.e., < 200Hz)
		univ.getViewer().getView().setMinimumFrameCycleTime(5);
	
		return c;
    }

    /***********************************************************************************************************************/
	/**
     * Creates the animation
    */
    public Animation() {                  	
   		
		// Initialize the GUI components
		initComponents();
	
		// Create Canvas3D and SimpleUniverse; add canvas to drawing panel
		Canvas3D c = createUniverse();
		drawingPanel.add(c, java.awt.BorderLayout.CENTER);
	
		// Create the content branch and add it to the universe
		scene = createSceneGraph();
		univ.addBranchGraph(scene);
		
    }

    /***********************************************************************************************************************/
	
    public void stopAnimation(){
    	
    	rotatorEarth.getAlpha().pause();
    	
    }
    
    /***********************************************************************************************************************/
    
    public void setMoonPosition(Vector3d pos){
    
    	// Create transformations for the Moon
    	Transform3D tm = new Transform3D();
    	tm.set(pos);
    	TransfMoon.setTransform(tm);
    }
    
    /***********************************************************************************************************************/
        
    public Vector3d getMoonPosition(){
    	
    	//return the moon position
    	Vector3d position = new Vector3d();
    	Transform3D t1 = new Transform3D();
    	TransfMoon.getTransform(t1);
    	t1.get(position);
    	return position;
    	
    }
    
    /***********************************************************************************************************************/
    
    public void startAnimation(){
    	
    	rotatorEarth.getAlpha().resume();
    	
    }
    
    /***********************************************************************************************************************/
       
    private void initComponents() {
    	
        drawingPanel = new javax.swing.JPanel();
        drawingPanel.setLayout(new java.awt.BorderLayout());
        drawingPanel.setPreferredSize(new java.awt.Dimension(800, 600));
        add(drawingPanel, java.awt.BorderLayout.CENTER);

    }    
    
    /***********************************************************************************************************************/
	/*   VARIABLES DECLARATION  */
    /***********************************************************************************************************************/
	
    private javax.swing.JPanel drawingPanel;
    
    TransformGroup objScale;             //main object
    private SimpleUniverse univ = null;  //main object
    private BranchGroup scene = null;    //main object
    static TransformGroup TransfMoon;    //position
    RotationInterpolator rotatorEarth;   //rotator of the earth
            
}
