
 /*
  *  Human.java  from "Java3d Jumpstart" ( modified by Paul Flavin )
  * 
  *  note: You _can_ animate VRML  H-Anim Avatars  with Java3d and
  *  ----  this does _NOT_ animate H-Anim Avatars ( see below )
  */

 /*
  * http://www.frontiernet.net/~imaging/java3d_and_vrml.html	// ~ real ~ H-Anim
  *
  * http://web3dbooks.com/java3d/jumpstart/Java3DExplorer.html	//  pseudo  H-Anim
  * http://web3dbooks.com/java3d/jumpstart/J3DJumpStart.zip		//  
  *
  * http://www.frontiernet.net/~imaging/games_with_java3d.html	//  Games with Java3d
  * http://www.frontiernet.net/~imaging/H-Anim_Avatars.html		//  Interactive H-Anim
  * http://www.web3d.org/WorkingGroups/web3d-mpeg/hypermail/2001/0159.html
  * http://www.frontiernet.net/~imaging/sourcecode/Human.java	//  this file.
  *
  * Human with Controlled Arm using VRML Human Model datafile
  * ---------------------------------------------------------
  * http://www.frontiernet.net/~imaging/sourcecode/HumanWithControlledArm_VRML.java 
  * http://www.frontiernet.net/~imaging/sourcecode/stickChickMinimal.wrl	
  *
  * To compile & run on Linux box with a Java JDK installed
  * Type:  javac Human.java ; java Human
  * If you're running Microsoft Windows:  Get a Clue & Get Linux. 
  *
  */

 import java.applet.Applet;
 import java.awt.*;
 import java.awt.event.*;
 import javax.swing.*;
 import javax.swing.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.*;
 import com.sun.j3d.utils.behaviors.mouse.*;



   public class Human extends Applet implements ChangeListener, ActionListener 
   {    
    SimpleUniverse 	u;			// Java3d Universe, View, Canvas
    Canvas3D  		canvas;
    View            view;

    TransformGroup 	Human_body,       Human_skullbase;  //  H-Anim naming convention, sort of ...
    TransformGroup 	Human_r_shoulder, Human_r_elbow;    //  not H-Anim, inferior method.
    TransformGroup 	Human_l_shoulder, Human_l_elbow;    //  If you're going to do it ... 
    												//  do it right,  NOT like this !    
    
    int			rShoulderRot = 0, 	rElbowRot = 0,  lShoulderRot = 0, 	lElbowRot = 0;
    JSlider		rShoulderSlider,    rElbowSlider,   lShoulderSlider,    lElbowSlider;
    JLabel 		rShoulderSliderLabel, rElbowSliderLabel, lShoulderSliderLabel, lElbowSliderLabel;
  
    AxisAngle4f		rShoulderAA = new AxisAngle4f( 0.0f, 0.0f,-1.0f, 0.0f );
    AxisAngle4f		rElbowAA    = new AxisAngle4f( 0.0f, 0.0f,-1.0f, 0.0f );
    AxisAngle4f		lShoulderAA = new AxisAngle4f( 0.0f, 0.0f, 1.0f, 0.0f );
    AxisAngle4f		lElbowAA    = new AxisAngle4f( 0.0f, 0.0f, 1.0f, 0.0f );
 
 
    								// Temporaries that are reused
    Transform3D		tmpTrans 	= new Transform3D();
    Vector3f		tmpVector 	= new Vector3f();
    AxisAngle4f		tmpAxisAngle = new AxisAngle4f();
			       
    								// geometric constants
    final Point3f		origin = new Point3f( 0.0f, 0.0f, 0.0f );
    final Vector3f		yAxis = new Vector3f( 0.0f, 1.0f, 0.0f );

        

	    			// Creates the Human Scenegraph TransformGroup 
    
    void createHuman( ) 
    {
    Cylinder		tmpCyl;
    Sphere		tmpSphere;
    TransformGroup	tmpTG; 
    					// colors for used for the body
    Color3f 		red   = new Color3f( 1.0f, 0.0f, 0.0f );
    Color3f 		black = new Color3f( 0.0f, 0.0f, 0.0f );
    Color3f 		white = new Color3f( 1.0f, 1.0f, 1.0f );


	Human_body = new TransformGroup();

 /* Note: Probably a better way is to Load a VRML model data file like this:
  * -----------------------------------------------------------------------
  * http://www.frontiernet.net/~imaging/sourcecode/HumanWithControlledArm_VRML.javfa 
  * http://www.frontiernet.net/~imaging/sourcecode/stickChickMinimal.wrl	
  */

	// center the body
	tmpVector.set( 0.0f, -2.0f, 0.0f );
//	tmpVector.set( 0.0f, -1.5f, 0.0f );     // orig
	tmpTrans.set(tmpVector);
	Human_body.setTransform( tmpTrans );

        // Set up an appearance to make the body with red ambient,
        // black emmissive, red diffuse and white specular coloring
        
        Material material = new Material(red, black, red, white, 64);
        Appearance appearance = new Appearance();
        appearance.setMaterial(material);

	// offset and place the cylinder for the body
	tmpTG = new TransformGroup();
	// offset the shape
	tmpVector.set(0.0f, 1.5f, 0.0f);
	tmpTrans.set(tmpVector);
	tmpTG.setTransform(tmpTrans);
	tmpCyl = new Cylinder(0.75f, 3.0f, appearance); 
	tmpTG.addChild(tmpCyl);

	// add the shape to the body
	Human_body.addChild(tmpTG);

	// create the r_shoulder TransformGroup
	Human_r_shoulder = new TransformGroup();
	Human_r_shoulder.setCapability( TransformGroup.ALLOW_TRANSFORM_READ  );
	Human_r_shoulder.setCapability( TransformGroup.ALLOW_TRANSFORM_WRITE );
	// translate from the waist
	tmpVector.set( -0.95f, 2.9f,-0.2f );
	tmpTrans.set(   tmpVector );
	Human_r_shoulder.setTransform(tmpTrans);

	// place the sphere for the r_shoulder
        
	tmpSphere = new Sphere(0.22f, appearance); 
	Human_r_shoulder.addChild(tmpSphere);

	// offset and place the cylinder for the r_shoulder
	tmpTG = new TransformGroup();
	// offset the shape 
	tmpVector.set(0.0f,-0.5f, 0.0f);
	tmpTrans.set(tmpVector);
	tmpTG.setTransform(tmpTrans);
	tmpCyl = new Cylinder(0.2f, 1.0f, appearance); 
	tmpTG.addChild(tmpCyl);

	// add the shape to the r_shoulder
	Human_r_shoulder.addChild(tmpTG);

	// add the shoulder to the body group
	Human_body.addChild(Human_r_shoulder);

	// create the r_elbow TransformGroup
	Human_r_elbow = new TransformGroup();
	Human_r_elbow.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
	Human_r_elbow.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
	tmpVector.set(0.0f, -1.054f, 0.0f);
	tmpTrans.set(tmpVector);
	Human_r_elbow.setTransform(tmpTrans);

	// place the sphere for the r_elbow
	tmpSphere = new Sphere(0.22f, appearance); 
	Human_r_elbow.addChild(tmpSphere);

	// offset and place the cylinder for the r_shoulder
	tmpTG = new TransformGroup();
	// offset the shape 
	tmpVector.set(0.0f,-0.5f, 0.0f);
	tmpTrans.set(tmpVector);
	tmpTG.setTransform(tmpTrans);
	tmpCyl = new Cylinder(0.2f, 1.0f, appearance); 
	tmpTG.addChild(tmpCyl);

	// add the shape to the r_shoulder
	Human_r_elbow.addChild(tmpTG);

	// add the elbow to the shoulder group
	Human_r_shoulder.addChild(Human_r_elbow);

	// create the l_shoulder TransformGroup
	Human_l_shoulder = new TransformGroup();
	Human_l_shoulder.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
	Human_l_shoulder.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
	tmpVector.set( 0.95f, 2.9f,-0.2f);
	tmpTrans.set(tmpVector);
	Human_l_shoulder.setTransform(tmpTrans);

	// place the sphere for the l_shoulder
	tmpSphere = new Sphere(0.22f, appearance); 
	Human_l_shoulder.addChild(tmpSphere);

	// offset and place the cylinder for the l_shoulder
	tmpTG = new TransformGroup();
	// offset the shape 
	tmpVector.set(0.0f,-0.5f, 0.0f);
	tmpTrans.set(tmpVector);
	tmpTG.setTransform(tmpTrans);
	tmpCyl = new Cylinder(0.2f, 1.0f, appearance); 
	tmpTG.addChild(tmpCyl);

	// add the shape to the l_shoulder
	Human_l_shoulder.addChild(tmpTG);

	// add the shoulder to the body group
	Human_body.addChild(Human_l_shoulder);

	// create the r_elbow TransformGroup
	Human_l_elbow = new TransformGroup();
	Human_l_elbow.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
	Human_l_elbow.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
	tmpVector.set(0.0f, -1.054f, 0.0f);
	tmpTrans.set(tmpVector);
	Human_l_elbow.setTransform(tmpTrans);

	// place the sphere for the l_elbow
	tmpSphere = new Sphere(0.22f, appearance); 
	Human_l_elbow.addChild(tmpSphere);

	// offset and place the cylinder for the l_elbow
	tmpTG = new TransformGroup();
	// offset the shape 
	tmpVector.set(0.0f,-0.5f, 0.0f);
	tmpTrans.set(tmpVector);
	tmpTG.setTransform(tmpTrans);
	tmpCyl = new Cylinder(0.2f, 1.0f, appearance); 
	tmpTG.addChild(tmpCyl);

	// add the shape to the l_elbow
	Human_l_elbow.addChild(tmpTG);

	// add the shoulder to the body group
	Human_l_shoulder.addChild(Human_l_elbow);

	// create the skullbase TransformGroup
        
	Human_skullbase = new TransformGroup();
	tmpVector.set( 0.0f, 3.632f, 0.0f);
	tmpTrans.set(tmpVector);
	Human_skullbase.setTransform(tmpTrans);

	// offset and place the sphere for the skull
	tmpSphere = new Sphere(0.5f, appearance);

	// add the shape to the l_shoulder
	Human_skullbase.addChild(tmpSphere);

	// add the shoulder to the body group
	Human_body.addChild(Human_skullbase);

    }


    public void actionPerformed(ActionEvent e) 
    {
	String action = e.getActionCommand();
	Object source = e.getSource();

	// nop	
    }

    public void setRShoulderRot( int rotation ) 
    {
	rShoulderRot = rotation;
	rShoulderAA.angle = (float) Math.toRadians( rShoulderRot );
	Human_r_shoulder.getTransform(tmpTrans);
	tmpTrans.setRotation(rShoulderAA);
	Human_r_shoulder.setTransform(tmpTrans);
    }

    public void setRElbowRot(int rotation) 
    {
	float angle = (float) Math.toRadians( rotation );
	rElbowRot = rotation;
	rElbowAA.angle = (float) Math.toRadians( rElbowRot );
	Human_r_elbow.getTransform(tmpTrans);
	tmpTrans.setRotation(rElbowAA);
	Human_r_elbow.setTransform(tmpTrans);
    }

    public void setLShoulderRot(int rotation) 
    {
	lShoulderRot = rotation;
	lShoulderAA.angle = (float) Math.toRadians(lShoulderRot);
	Human_l_shoulder.getTransform(tmpTrans);
	tmpTrans.setRotation(lShoulderAA);
	Human_l_shoulder.setTransform(tmpTrans);
    }

    public void setLElbowRot(int rotation) 
    {
	float angle = (float) Math.toRadians(rotation);
	lElbowRot = rotation;
	lElbowAA.angle = (float) Math.toRadians(lElbowRot);
	Human_l_elbow.getTransform(tmpTrans);
	tmpTrans.setRotation(lElbowAA);
	Human_l_elbow.setTransform(tmpTrans);
    }


    public void stateChanged( ChangeEvent e ) 
    {
       String indent = "   ";
  
        JSlider source = (JSlider) e.getSource();
	int value = source.getValue();
        
        if ( source == rShoulderSlider ) {
	    setRShoulderRot(value);
	    rShoulderSliderLabel.setText( indent + Integer.toString(value) );
        } else if ( source == rElbowSlider ) {
	    setRElbowRot(value);
	    rElbowSliderLabel.setText( indent +  Integer.toString( value));
        } else if (source == lShoulderSlider ) {
	    setLShoulderRot(value);
	    lShoulderSliderLabel.setText( indent +  Integer.toString( value ));
        } else if ( source == lElbowSlider ) {
	    setLElbowRot(value);
	    lElbowSliderLabel.setText( indent +  Integer.toString( value ));
	}
    }

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

	// Create a TransformGroup to scale the scene down by 3.5x
	// TODO: move view platform instead of scene using orbit behavior
        
	TransformGroup  objScale   = new TransformGroup();
        Transform3D     scaleTrans = new Transform3D();
        
        float scaleFactor = 1 / 2.0f;   // was 1 / 3.5f
	scaleTrans.set( scaleFactor ); // scale down 
        
	objScale.setTransform( scaleTrans );
	objRoot.addChild( objScale );

	// Create a TransformGroup and initialize it to the
	// identity.  Enable the TRANSFORM_WRITE capability so that
	// the mouse behaviors code can modify it at runtime.  Add it to the
	// root of the subgraph.
	TransformGroup objTrans = new TransformGroup();
	objTrans.setCapability( TransformGroup.ALLOW_TRANSFORM_WRITE );
	objTrans.setCapability( TransformGroup.ALLOW_TRANSFORM_READ  );
	objScale.addChild( objTrans );

	// Add the primitives to the scene
        
	createHuman( ); 				// the human
	objTrans.addChild(Human_body);

	BoundingSphere bounds = new BoundingSphere(new Point3d(), 100.0);

	Background bg = new Background(new Color3f(1.0f, 1.0f, 1.0f));
	bg.setApplicationBounds(bounds);
	objTrans.addChild(bg);

							// set up the mouse rotation behavior 
	MouseRotate mr = new MouseRotate();
	mr.setTransformGroup(objTrans);
	mr.setSchedulingBounds(bounds);
	mr.setFactor(0.007);
	objTrans.addChild(mr);

        // Set up the ambient light
        Color3f ambientColor = new Color3f(0.1f, 0.1f, 0.1f);
        AmbientLight ambientLightNode = new AmbientLight(ambientColor);
        ambientLightNode.setInfluencingBounds(bounds);
        objRoot.addChild(ambientLightNode);

        // Set up the directional lights
        Color3f light1Color = new Color3f(1.0f, 1.0f, 1.0f);
        Vector3f light1Direction  = new Vector3f(0.0f, -0.2f, -1.0f);

        DirectionalLight light1
            = new DirectionalLight(light1Color, light1Direction);
        light1.setInfluencingBounds(bounds);
        objRoot.addChild(light1);

	return objRoot;
    }


    public Human( ) 	// constructor
    {

    }
    

    
    public void init() 
    {

	setLayout( new GridLayout( 1, 2 ) );

	
//    GraphicsConfiguration config = SimpleUniverse.getPreferredConfiguration( );

    GraphicsConfiguration config =
          GraphicsEnvironment.getLocalGraphicsEnvironment( 
                    ).getDefaultScreenDevice( ).getDefaultConfiguration( );            

	canvas = new Canvas3D( config );

	add(  canvas );

	u = new SimpleUniverse( canvas );

	// Create a simple scene and attach it to the virtual universe
	BranchGroup scene = createSceneGraph();
	
        // move the ViewPlatform back a bit so the objects in the scene can be viewed.

        u.getViewingPlatform().setNominalViewingTransform();
	u.addBranchGraph(scene);

	view = u.getViewer().getView();

	add(         guiPanel() );
    }

    // create a panel with a tabbed pane holding each of the edit panels
    
    
    JPanel guiPanel() 
    { 
	JPanel panel = new JPanel( );
        
	panel.setLayout( new GridLayout( 0, 1 ) );
        
        panel.resize( 120, 200 );   // added by paul
                
        String jointLabels [ ] = {  "  Right Shoulder", 
                                    "  Right Elbow",
                                    "  Left Sholder",
                                    "  Left Elbow"
                                 };
                                 
                                 
        panel.add( new JLabel( "  "              ) );
        panel.add( new JLabel( "Joint Rotations" ) );
        panel.add( new JLabel( "  "              ) );
        panel.add( new JLabel( jointLabels[0]    ) );
        
        rShoulderSlider = new JSlider( JSlider.HORIZONTAL, 0, 180, rShoulderRot );
        rShoulderSlider.addChangeListener(this);
        rShoulderSliderLabel = new JLabel( Integer.toString(rShoulderRot));
        panel.add( rShoulderSlider );
        panel.add( rShoulderSliderLabel  );

	// Human_r_elbow rotation 
        panel.add(new JLabel( jointLabels[1] ) );
        rElbowSlider = new JSlider( JSlider.HORIZONTAL, 0, 180, rElbowRot);
        rElbowSlider.addChangeListener(this);
        rElbowSliderLabel = new JLabel(    Integer.toString( rElbowRot));
        panel.add( rElbowSlider );
        panel.add( rElbowSliderLabel );

	// Human_l_shoulder rotation 
        panel.add( new JLabel( jointLabels[2] ) );
        lShoulderSlider =  new JSlider( JSlider.HORIZONTAL, 0, 180, lShoulderRot);
        lShoulderSlider.addChangeListener(this);
        panel.add(  lShoulderSlider );
        panel.add( lShoulderSliderLabel = new JLabel( Integer.toString( lShoulderRot ) ) );
 

	// Human_l_elbow rotation 
        panel.add( new JLabel(  jointLabels[3] ) );
        lElbowSlider = new JSlider( JSlider.HORIZONTAL, 0, 180,  lElbowRot );
        lElbowSlider.addChangeListener(this);
        lElbowSliderLabel = new JLabel(   Integer.toString( lElbowRot));
        panel.add(lElbowSlider);
        panel.add(  lElbowSliderLabel  );   // had error was rElbowSliderLabel !
        

	return panel;
    }

    
    public void destroy( ) 
    {
	 //   u.removeAllLocales();     // gave error
    }

   
    
    public static void main( String [ ] args ) 
    {
	
        MainFrame   window = new MainFrame( new Human(  ),	260, 200 );
        String 							windowFrameTitleString = "Java J.S. Demo: Pseudo H-Anim";
                    window.setTitle( 	windowFrameTitleString );  	  		// was:	950, 600 );
    }
    
}

/* 
      %Z%%M% %I% %E% %U%

***************************************************************
"Copyright (c) 2001 Sun Microsystems, Inc. All Rights Reserved.

Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:

-Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.

-Redistribution in binary form must reproduce the above copyright notice, this
list of conditions and the following disclaimer in the documentation and/or
other materials provided with the distribution.

Neither the name of Sun Microsystems, Inc. or the names of contributors may be
used to endorse or promote products derived from this software without
specific prior written permission.

This software is provided "AS IS," without a warranty of any kind. ALL
EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

You acknowledge that Software is not designed,licensed or intended for use in
the design, construction, operation or maintenance of any nuclear facility."

****************************************************************************
*/

 /*
  *  Modifications by and Copyright (c) 2002 by Paul Flavin and 
  *  as with the original copyright: you may copy, modify & use
  *  but all copies and derivatives must contain this statement.
  */
