import	java.awt.*;
import  java.awt.event.*;
import  java.awt.image.*;
import	javax.vecmath.*;
import	javax.media.j3d.*;

class LightingDemo extends Frame implements ItemListener
{
	boolean ambientOn        	= true;
	boolean brightAmbientOn    	= false;
	boolean redDirectionalOn    	= false;
	boolean yellowDirectionalOn 	= false;
	boolean orangePointOn       	= true;

	CheckboxMenuItem ambientMenu;
	CheckboxMenuItem brightAmbientMenu;
	CheckboxMenuItem redDirectionalMenu;
	CheckboxMenuItem yellowDirectionalMenu;
	CheckboxMenuItem orangePointMenu;

	AmbientLight ambient = new AmbientLight();
	AmbientLight brightAmbient = new AmbientLight();
	DirectionalLight redDirectional = new DirectionalLight();
	DirectionalLight yellowDirectional = new DirectionalLight();
	PointLight orangePoint = new PointLight();

	int width1=128;
	int height1=128;
	MyImageComponent2D myImage1 = new MyImageComponent2D("Fire_128x128.jpg",width1,height1,
						BufferedImage.TYPE_INT_RGB,ImageComponent.FORMAT_RGB8);
	int width2=128;
	int height2=128;
	MyImageComponent2D myImage2 = new MyImageComponent2D("Stone_128x128.jpg",width2,height2,
						BufferedImage.TYPE_INT_RGB,ImageComponent.FORMAT_RGB8);



	public static void main(String[] args)
	{
		new LightingDemo();
	}

	public LightingDemo()
	{
		setTitle("LightingDemo");		

		setLayout(new BorderLayout());
		Canvas3D c = new Canvas3D(null);
		add("Center", c);
		MenuBar menuBar = new MenuBar();

		Menu menu = new Menu("Lights");
		
		ambientMenu = new CheckboxMenuItem("Gyenge ambientLight", ambientOn );
		ambientMenu.addItemListener( this );
		menu.add( ambientMenu );

		brightAmbientMenu = new CheckboxMenuItem("Eros ambient light", brightAmbientOn );
		brightAmbientMenu.addItemListener( this );
		menu.add( brightAmbientMenu );

		redDirectionalMenu = new CheckboxMenuItem("Piros directionalLight", redDirectionalOn );
		redDirectionalMenu.addItemListener( this );
		menu.add( redDirectionalMenu );

		yellowDirectionalMenu = new CheckboxMenuItem("Sárga directionalLight", yellowDirectionalOn );
		yellowDirectionalMenu.addItemListener( this );
		menu.add( yellowDirectionalMenu );

		orangePointMenu = new CheckboxMenuItem("Narancs pointLight", orangePointOn );
		orangePointMenu.addItemListener( this );
		menu.add( orangePointMenu );

		menuBar.add(menu);
		setMenuBar(menuBar);

		UniverseBuilder u = new UniverseBuilder(c);
		BranchGroup scene = createSceneGraph();
		u.addBranchGraph(scene);

		setSize(300,270);
		show();
	}

	public BranchGroup createSceneGraph()
	{		
		BranchGroup branchGroup = new BranchGroup();

		BoundingSphere bounds = new BoundingSphere(new Point3d(0.0,0.0,0.0), 1000.0);		


		ambient.setEnable( ambientOn );
		ambient.setColor( new Color3f( 0.6f, 0.6f, 0.6f ) );
		ambient.setCapability( AmbientLight.ALLOW_STATE_WRITE );
		ambient.setInfluencingBounds( bounds );
		branchGroup.addChild( ambient );

		brightAmbient.setEnable( brightAmbientOn );
		brightAmbient.setColor( new Color3f( 1.0f, 1.0f, 1.0f ) );
		brightAmbient.setCapability( AmbientLight.ALLOW_STATE_WRITE );
		brightAmbient.setInfluencingBounds( bounds );
		branchGroup.addChild( brightAmbient );
	
		redDirectional.setEnable( redDirectionalOn );
		redDirectional.setColor( new Color3f( 1.0f, 0.0f, 0.0f ) );
		redDirectional.setDirection( new Vector3f( 1.0f, -0.5f, -0.5f ) );
		redDirectional.setCapability( AmbientLight.ALLOW_STATE_WRITE );
		redDirectional.setInfluencingBounds( bounds );
		branchGroup.addChild( redDirectional );

		yellowDirectional.setEnable( yellowDirectionalOn );
		yellowDirectional.setColor( new Color3f( 1.0f, 0.8f, 0.0f ) );
		yellowDirectional.setDirection( new Vector3f( -1.0f, 0.5f, 1.0f ) );
		yellowDirectional.setCapability( AmbientLight.ALLOW_STATE_WRITE );
		yellowDirectional.setInfluencingBounds( bounds );
		branchGroup.addChild( yellowDirectional );

		orangePoint.setEnable( orangePointOn );
		orangePoint.setColor( new Color3f( 1.0f, 0.5f, 0.0f ) );
		orangePoint.setPosition( new Point3f( 0.0f, 1.1f, 0.0f ) );
		orangePoint.setCapability( AmbientLight.ALLOW_STATE_WRITE );
		orangePoint.setInfluencingBounds( bounds );
		branchGroup.addChild( orangePoint );


// a center kocka			
		Appearance appearance1 = new Appearance();
		Material m1 = new Material();
		appearance1.setMaterial(m1);		
		Texture2D texture2D1 = new Texture2D(Texture.BASE_LEVEL,Texture.RGB,width1,height1);
		texture2D1.setImage(0,myImage1.getImageComponent2D());
		appearance1.setTexture(texture2D1);
		TextureAttributes textureAttributes1 = new TextureAttributes();
		appearance1.setTextureAttributes(textureAttributes1);
		

		Transform3D transform3D1 = new Transform3D();
		transform3D1.setScale(new Vector3d(0.7,0.7,0.7));
		transform3D1.setTranslation(new Vector3f(0.0f,1.0f,0.0f));
		TransformGroup transformGroup1 = new TransformGroup(transform3D1);

		transformGroup1.addChild(new ColorCube(appearance1).getShape());
		branchGroup.addChild(transformGroup1);
// a hosszu oldal kocka

		Appearance appearance2 = new Appearance();
		Material m2 = new Material();
		appearance2.setMaterial(m2);		
		Texture2D texture2D2 = new Texture2D(Texture.BASE_LEVEL,Texture.RGB,width2,height2);
		texture2D2.setImage(0,myImage2.getImageComponent2D());
		appearance2.setTexture(texture2D2);

		Transform3D textureTransform3D2 = new Transform3D();
		textureTransform3D2.setScale(new Vector3d(1.0,4.0,1.0));
		TextureAttributes textureAttributes2 = new TextureAttributes();
		textureAttributes2.setTextureMode( TextureAttributes.MODULATE );
		textureAttributes2.setPerspectiveCorrectionMode(TextureAttributes.NICEST );
		textureAttributes2.setTextureTransform( textureTransform3D2 );
		appearance2.setTextureAttributes(textureAttributes2);
		
		SharedGroup sharedGroup = new SharedGroup();
		sharedGroup.addChild(new ColorCube(appearance2).getShape());
		sharedGroup.compile();
				
		
//		Ez ekvivalens az elozo transzformacio megadassal.
//		Azert szerepel itt, hogy lassuk hogyan kell csinalni.
//		double trans[] = {
//					0.3,0.0,0.0,-2.0,
//					0.0,4.0,0.0,4.0,
//					0.0,0.0,0.3,0.0,
//					0.0,0.0,0.0,1.0,
//				};

// most egyesevel beszurjuk a hosszu kocka peldanyait a grafba
		Link link1 = new Link(sharedGroup);
		Transform3D transform3D2 = new Transform3D();
		transform3D2.setScale(new Vector3d(0.3,4.0,0.3));
		transform3D2.setTranslation(new Vector3f(2.0f,4.0f,0.0f));
		TransformGroup transformGroup2 = new TransformGroup(transform3D2);
		transformGroup2.addChild(link1);
		branchGroup.addChild(transformGroup2);


		Link link2 = new Link(sharedGroup);
		Transform3D transform3D3 = new Transform3D();
		transform3D3.setScale(new Vector3d(0.3,4.0,0.3));
		transform3D3.setTranslation(new Vector3f(-2.0f,4.0f,0.0f));
		TransformGroup transformGroup3 = new TransformGroup(transform3D3);
		transformGroup3.addChild(link2);
		branchGroup.addChild(transformGroup3);


		Link link3 = new Link(sharedGroup);
		Transform3D transform3D4 = new Transform3D();
		transform3D4.setScale(new Vector3d(0.3,4.0,0.3));
		transform3D4.setTranslation(new Vector3f(0.0f,4.0f,2.0f));
		TransformGroup transformGroup4 = new TransformGroup(transform3D4);
		transformGroup4.addChild(link3);
		branchGroup.addChild(transformGroup4);


		Link link4 = new Link(sharedGroup);
		Transform3D transform3D5 = new Transform3D();
		transform3D5.setScale(new Vector3d(0.3,4.0,0.3));
		transform3D5.setTranslation(new Vector3f(0.0f,4.0f,-2.0f));
		TransformGroup transformGroup5 = new TransformGroup(transform3D5);
		transformGroup5.addChild(link4);
		branchGroup.addChild(transformGroup5);


		return branchGroup;
	}



	public void itemStateChanged( ItemEvent event )
	{
		Object src = event.getSource( );

		if ( src == ambientMenu )
		{
			ambientOn = ambientMenu.getState( );
			ambient.setEnable( ambientOn );
			return;
		}
		if ( src == brightAmbientMenu )
		{
			brightAmbientOn = brightAmbientMenu.getState( );
			brightAmbient.setEnable( brightAmbientOn );
			return;
		}
		if ( src == redDirectionalMenu )
		{
			redDirectionalOn = redDirectionalMenu.getState( );
			redDirectional.setEnable( redDirectionalOn );
			return;
		}
		if ( src == yellowDirectionalMenu )
		{
			yellowDirectionalOn = yellowDirectionalMenu.getState( );
			yellowDirectional.setEnable( yellowDirectionalOn );
			return;
		}
		if ( src == orangePointMenu )
		{
			orangePointOn = orangePointMenu.getState( );
			orangePoint.setEnable( orangePointOn );
			return;
		}
		
	}



}

class UniverseBuilder extends Object
{
	Locale			locale;

	UniverseBuilder(Canvas3D c)
	{
		Transform3D t = new Transform3D();
		Transform3D t2 = new Transform3D();
		t2.setEuler( new Vector3d(-30.0*(Math.PI/180.0),45.0*(Math.PI/180.0),0.0));
		t.set(2.0,new Vector3d(3.6,3.7,4.2));
		t.mul(t,t2);

		VirtualUniverse	universe = new VirtualUniverse();
		locale = new Locale(universe);

		PhysicalBody body = new PhysicalBody();
		PhysicalEnvironment environment = new PhysicalEnvironment();
		BranchGroup viewPlatformBranchGroup = new BranchGroup();
		TransformGroup viewPlatformTransformGroup = new TransformGroup(t);
		ViewPlatform viewPlatform = new ViewPlatform();

		View view = new View();
		view.addCanvas3D(c);
		view.setPhysicalBody(body);
		view.setPhysicalEnvironment(environment);
		view.attachViewPlatform(viewPlatform);
		
		viewPlatformTransformGroup.addChild(viewPlatform);
		viewPlatformBranchGroup.addChild(viewPlatformTransformGroup);
		locale.addBranchGraph(viewPlatformBranchGroup);
	}

	void addBranchGraph(BranchGroup bg)
	{
		locale.addBranchGraph(bg);
	}
}

class ColorCube extends Object
{
	static double verts[] = {
		// elso lap
		1.0, -1.0,  1.0,	1.0,  1.0,  1.0,
		-1.0,  1.0,  1.0,	-1.0, -1.0,  1.0,
		// hatso lap
		-1.0, -1.0, -1.0,	-1.0,  1.0, -1.0,
		1.0,  1.0, -1.0,	1.0, -1.0, -1.0,
		// jobb lap
		1.0, -1.0, -1.0,	1.0,  1.0, -1.0,
		1.0,  1.0,  1.0,	1.0, -1.0,  1.0,
		// bal lap
		-1.0, -1.0,  1.0,	-1.0,  1.0,  1.0,
		-1.0,  1.0, -1.0,	-1.0, -1.0, -1.0,
		// fedo lap
		1.0,  1.0,  1.0,	1.0,  1.0, -1.0,
		-1.0,  1.0, -1.0,	-1.0,  1.0,  1.0,
		// alaplap
		-1.0, -1.0,  1.0,	-1.0, -1.0, -1.0,
		1.0, -1.0, -1.0,	1.0, -1.0,  1.0 
	};

	static float normals[] = {
		0.0f, 0.0f, 1.0f,
		0.0f, 0.0f, 1.0f,
		0.0f, 0.0f, 1.0f,
		0.0f, 0.0f, 1.0f,

		0.0f, 0.0f, -1.0f,
		0.0f, 0.0f, -1.0f,
		0.0f, 0.0f, -1.0f,
		0.0f, 0.0f, -1.0f,

		1.0f, 0.0f, 0.0f,
		1.0f, 0.0f, 0.0f,
		1.0f, 0.0f, 0.0f,
		1.0f, 0.0f, 0.0f,

		-1.0f, 0.0f, 0.0f,
		-1.0f, 0.0f, 0.0f,
		-1.0f, 0.0f, 0.0f,
		-1.0f, 0.0f, 0.0f,

		0.0f, 1.0f, 0.0f,
		0.0f, 1.0f, 0.0f,
		0.0f, 1.0f, 0.0f,
		0.0f, 1.0f, 0.0f,

		0.0f, -1.0f, 0.0f,
		0.0f, -1.0f, 0.0f,
		0.0f, -1.0f, 0.0f,
		0.0f, -1.0f, 0.0f,

	};

	static float textures[] = {
		1.0f, 0.0f,
		1.0f, 1.0f,
		0.0f, 1.0f,
		0.0f, 0.0f,

		1.0f, 0.0f,
		1.0f, 1.0f,
		0.0f, 1.0f,
		0.0f, 0.0f,

		1.0f, 0.0f,
		1.0f, 1.0f,
		0.0f, 1.0f,
		0.0f, 0.0f,
		
		1.0f, 0.0f,
		1.0f, 1.0f,
		0.0f, 1.0f,
		0.0f, 0.0f,

		1.0f, 0.0f,
		1.0f, 1.0f,
		0.0f, 1.0f,
		0.0f, 0.0f,

		1.0f, 0.0f,
		1.0f, 1.0f,
		0.0f, 1.0f,
		0.0f, 0.0f,

	};

	private Shape3D shape;

	public ColorCube(Appearance appearance)
	{
		QuadArray cube = new QuadArray(24, QuadArray.COORDINATES |QuadArray.NORMALS |QuadArray.TEXTURE_COORDINATE_2);

		cube.setCoordinates(0, verts);
		cube.setNormals(0,normals);
		cube.setTextureCoordinates(0,textures);

		shape = new Shape3D(cube, appearance);
	}

	public Shape3D getShape()
	{
		return shape;
	}
}

class MyImageComponent2D extends Object
{
	ImageComponent2D imageComponent2D = null;

	public MyImageComponent2D(String fname, int w, int h, int format1, int format2)
	{

		Toolkit toolkit = Toolkit.getDefaultToolkit();
		Image image = toolkit.getImage(fname);

   		BufferedImage bImage = new BufferedImage(w, h, format1);
	        int[] intPixels =((DataBufferInt)bImage.getRaster().getDataBuffer()).getData();
	
		PixelGrabber pg = new PixelGrabber(image, 0, 0, w, h, intPixels, 0, w);
		try { pg.grabPixels(); }
			catch (InterruptedException e) {;}
		imageComponent2D = new ImageComponent2D(format2, bImage);

		imageComponent2D.setCapability(ImageComponent.ALLOW_SIZE_READ);
		imageComponent2D.setCapability(ImageComponent.ALLOW_FORMAT_READ);
		imageComponent2D.setCapability(ImageComponent.ALLOW_IMAGE_READ);
	}

	public ImageComponent2D getImageComponent2D()
	{
		return imageComponent2D;
	}

}
