/*
* This file is part of 3DzzD http://dzzd.net/.
*
* Released under LGPL
*
* 3DzzD is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* 3DzzD is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with 3DzzD.  If not, see <http://www.gnu.org/licenses/>.
*
* Copyright 2005 - 2009 Bruno Augier
*/
package net.dzzd.test;
 
import java.awt.*;
import java.applet.*;

import net.dzzd.access.*;
import net.dzzd.*;
import net.dzzd.utils.*;



/**
 * CreateMesh
 * 
 * This sample show how to create a Mesh3D by hand :
 */
public class Sea extends DzzDApplet implements Runnable
{
	public static final long serialVersionUID = 0x00000001;
	
	private IRender3D render;
	private IScene3D scene;
	private boolean run=false;
	private Grid3D grid;
	private IMappingUV mappingUV;
	

	public void start()
	{
		//Ask 3DzzD factory for a fresh Scene3D
		this.scene=DzzD.newScene3D();	
		
		//Ask 3DzzD factory for a software 3D Render
		this.render=DzzD.newRender3D("SOFT",null);
		
		//Add the Render3D canvas to the Applet Panel
		this.setLayout(null);
		this.add(this.render.getCanvas());
		
		//Set the Render3D size
		this.render.setSize(this.getSize().width,this.getSize().height,1);
		
		//Set Camera Aspect ratio to 1:1
		this.scene.getCurrentCamera3D().setZoomY(((double)this.render.getWidth())/((double)this.render.getHeight()));	
		this.scene.getCurrentCamera3D().setFOV(70);
		
		//Tell the Render3D wich camera it should use to render
		this.render.setCamera3D(this.scene.getCurrentCamera3D());
		
		//Set light position
		this.scene.getLight3DById(0).getRotation().setX(-0.4*Math.PI);
		
		//Set background color
		this.scene.setBackgroundColor(0x000055);
			
		//Create a main Thread
		Thread mainThread=new Thread(this);
		this.run=true;
		mainThread.start();
	}
	
	
	/**
	 * Tell the main thread that it can stop running when Applet is destroyed
	 */
	public void destroy()
	{
		this.run=false;
	}
	
	
	private void createScene3D()
	{
		IScene3DLoader s1=DzzD.newScene3DLoader();
		s1.loadScene3D(this.getBaseURL()+"./","SKY.3DS");
		this.scene.setScene3DLoader(s1);
	
		do
		{
			
			this.scene.updateMonitoredSceneObjects();
			DzzD.sleep(200);
			Thread.yield();
			
		}
		while(this.scene.getNbMonitoredSceneObject()!=0);
	
		IMesh3D sky=this.scene.getMesh3DByName("SKY");
		if(sky!=null)
		{
			sky.zoom(10000,10000,10000);
			sky.getRender3DMode().disableRender3DMode(DzzD.RM_LIGHT);
			sky.setSolid(false);
		}
	
		IMaterial material=DzzD.newMaterial();
		material.setName("SeaMaterial");
		material.setDiffuseColor(0xffffff);
		material.setSpecularColor(0x000055);
		material.setSpecularPower(45);
		material.setSpecularLevel(100);
		material.setSelfIlluminationLevel(0);
		
		
		IURLTexture urlTexture=DzzD.newURLTexture();
		urlTexture.setBaseURL(this.getCodeBase().toString()+"./");
		urlTexture.setSourceFile("WATER.JPG");
		
		
		material.setDiffuseTexture(urlTexture);
		
		mappingUV=DzzD.newMappingUV();
		mappingUV.setVZoom(0.2f);
		mappingUV.setUZoom(0.2f);
		mappingUV.setUOffset(3.5f);
		mappingUV.setVOffset(3.5f);
		material.setMappingUV(mappingUV);
		
		this.scene.addMaterial(material);
		this.scene.addTexture(urlTexture);
	
		this.grid=new Grid3D(36,25,material);
		IMesh3D mesh=this.grid.getMesh3D();
		mesh.getPosition().set(0,0,0);
		mesh.getPivot().set(18,0,0);
		mesh.setOctreeEnabled(false);
		mesh.setName("Sea");
		this.scene.addMesh3D(mesh);
	
	}
	
	long start=System.currentTimeMillis();
	int t=0;
	int nb=0;
	private void updateWorld()
	{
		double h=seaHeight(0,0);
		
		this.scene.getCurrentCamera3D().getRotation().setX((-0.05-h*0.1)*Math.PI);
		
		this.scene.getCurrentCamera3D().getPosition().setY(h+1.5);
		
		IMesh3D sky=this.scene.getMesh3DByName("SKY");
		if(sky!=null)
		{
			sky.getRotation().set(0,0,0);
			sky.getPosition().copy(this.scene.getCurrentCamera3D().getPosition());
		}
		
		IVertex3D vertices[]=this.grid.getMesh3D().getVertex3D();
		for(int n=0;n<vertices.length;n++)
		{
			IVertex3D v=vertices[n];
			v.setY(this.seaHeight(v.getX(),v.getZ()));
		
		}
		t=(int)(System.currentTimeMillis()-start)>>2;
		//if(nb<100)
		{
		this.grid.getMesh3D().buildSphereBoxAndCenter();
		this.grid.getMesh3D().buildFacesNormals();
		}
		
		//this.grid.getMesh3D().build();
		mappingUV.setUOffset(3.5f+t*0.0001f);
		mappingUV.setVOffset(3.5f+t*0.0001f);
		nb++;
		if(nb%100==0)
		{
			int fps=(int)((1000*nb)/(System.currentTimeMillis()-start));
			Log.log("fps"+fps);
		}
	}
	
	private double seaHeight(double x,double z)
	{
		double h=0.0;
		h+=0.2*MathX.cos(t*0.01+(x+z)*1.0);
		h+=0.15*MathX.cos(t*0.005+x*0.5);
		h*=1.3;
		 
		return h;
	
	}
	
	/**
	 * Here is the mainThread run method
	 * called by mainThread.start(); (inded this method is started in a different Thread)
	 */
	public void run()
	{
		this.createScene3D();
		while(this.run)
		{
			//Update world
			this.updateWorld();
			
			//Render a single frame
			this.renderSingleFrame();
			Thread.yield();	
		}
		
	}
	
	
	
	public void renderSingleFrame()
	{
		//Set the scene to world space
		this.scene.setScene3DObjectToWorld();
		
		//Set the scene to active camera space
		this.scene.setScene3DObjectToCamera();
		
		//Tell the 3D render to compute & draw the frame
		this.render.renderScene3D(this.scene);
	}
}
