/*
* 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.core;

import net.dzzd.access.*;
import java.io.Serializable;

public final class Face3D implements IFace3D,Serializable
{	
	public static final long serialVersionUID = 0x00000001;
	Mesh3D object;				//Face parent object (owner of this face)
	
	int id;						//Face id relative to parent object
	
	Vertex3D p0,p1,p2;			//Face vertices  
	
	Point3D center;
	
	int smoothGroupMask;		//Face smoothing group mask
	
	float pa,pb,pc,pd; 			//Face plane equation in object space pa,pb,pc=face normal pd=nearest distance of the face from 0,0
	
	float p0nx,p0ny,p0nz;		//Face normal for vertex p0
	float p1nx,p1ny,p1nz;		//Face normal for vertex p1
	float p2nx,p2ny,p2nz;		//Face normal for vertex p2

	float u0,u1,u2;				//U Mapping coordinate Original mapping coordinate
	float v0,v1,v2;				//V Mapping coordinate Original mapping coordinate
	
	Material material;			//Face material
	
	float sphereBox;			//Face spherebox related to center
	
	
	//TEMPORARY VARIABLES USED BY SOFTWARE RENDERER - UPDATED FOR EACH NEW FRAME
	//TODO: this should be removed, Mesh3D must handle this in a FaceList
	transient Face3D nextAlphaFace;	

	public Face3D()
	{
		this.object=null;
		this.p0=null;
		this.p1=null;
		this.p2=null;
		this.center=new Point3D();
		this.smoothGroupMask=0;
		this.material=null;
		this.u0=0.0f;
		this.u1=1.0f;
		this.u2=1.0f;
		this.v0=0.0f;
		this.v1=0.0f;
		this.v2=1.0f;		
	}
	
	public Face3D(IVertex3D p0,IVertex3D p1,IVertex3D p2)
	{
		this();
		this.p0=(Vertex3D)p0;
		this.p1=(Vertex3D)p1;
		this.p2=(Vertex3D)p2;
	}
	
	
	void setNormal()
	{
		//Compute normal
		/*
		Point3D normal=new Point3D();
		Point3D centre=new Point3D();
		centre.copy(p1);		
		normal.copy(p2);
		centre.sub(p0);
		normal.sub(p0);		
		centre.cross(normal);
		centre.normalize();	
			
		normal.copy(centre);*/
		
		double x0=p0.x;
		double y0=p0.y;
		double z0=p0.z;

		double x1=p1.x;
		double y1=p1.y;
		double z1=p1.z;
		
		double x2=p2.x;
		double y2=p2.y;
		double z2=p2.z;
		
		double x10=x1-x0;
		double y10=y1-y0;
		double z10=z1-z0;

		double x20=x2-x0;
		double y20=y2-y0;
		double z20=z2-z0;
		
		double nx=y10*z20-z10*y20;
		double ny=z10*x20-x10*z20;
		double nz=x10*y20-y10*x20;
		
		double n=1.0/Math.sqrt(nx*nx+ny*ny+nz*nz);
		nx*=n;
		ny*=n;
		nz*=n;
		
		this.pa=(float)nx;
		this.pb=(float)ny;
		this.pc=(float)nz;
		this.pd=(float)-(nx*x0+ny*y0+nz*z0);

		this.p0nx=(float)nx;
		this.p0ny=(float)ny;
		this.p0nz=(float)nz;
		
		this.p1nx=(float)nx;
		this.p1ny=(float)ny;
		this.p1nz=(float)nz;
		
		this.p2nx=(float)nx;
		this.p2ny=(float)ny;
		this.p2nz=(float)nz;
				
			
	}
	
	public void initSphereBox()
	{
		this.center.copy(this.p0);
		this.center.add(this.p1);
		this.center.add(this.p2);
		this.center.div(3);
		
		double d0=this.center.distance2(this.p0);
		double d1=this.center.distance2(this.p1);
		double d2=this.center.distance2(this.p2);
		
		double d=d0;
		if(d1>d) d=d1;
		if(d2>d) d=d2;
		
		this.sphereBox=(float)Math.sqrt(d);
		
		/*	
		this.sphereBox=(float)this.p2.dist(this.p0);
		double distance21=this.p2.dist(this.p1);
		if(distance21>this.sphereBox)
			this.sphereBox=(float)distance21;
		*/
	}
	
	/*
	 *INTERFACE IFace3D
	 */

	public void flipNormal()
	{
		Vertex3D tmpP0=this.p0;
		this.p0=this.p2;
		this.p2=tmpP0;
		
		float tmpU0=this.u0;
		this.u0=this.u2;
		this.u2=tmpU0;
		
		float tmpV0=this.v0;
		this.v0=this.v2;
		this.v2=tmpV0;
	}

	public double getSphereBox()
	{
		return this.sphereBox;
	}

	public void setMaterial(IMaterial m)
	{
		this.material=(Material)m;
	}
	 
	public IMaterial getMaterial()
	 {
	 	return this.material;
	 }

	public IVertex3D getVertex3D0()
	{
		return this.p0;
	}	
	public IVertex3D getVertex3D1()
	{
		return this.p1;
	}	
	public IVertex3D getVertex3D2()
	{
		return this.p2;
	}	

	public IMesh3D getMesh3D()
	{
		return this.object;
	}
	
	public double getPA()
	{
		return this.pa;
	}

	public double getPB()
	{
		return this.pb;
	}

	public double getPC()
	{
		return this.pc;
	}

	public double getPD()
	{
		return this.pd;
	}
	
	public float getMappingU(int numVertex)
	{
		switch(numVertex)
		{
			case 0:
				return this.u0;
			case 1:
				return this.u1;
			case 2:
				return this.u2;	
			default:
				return 0f;
		}
	}	

	public float getMappingV(int numVertex)
	{
		switch(numVertex)
		{
			case 0:
				return this.v0;
			case 1:
				return this.v1;
			case 2:
				return this.v2;	
			default:
				return 0f;
		}
	}		
	
	public void setMappingU(int numVertex,float val)		
	{
		switch(numVertex)
		{
			case 0:
				this.u0=val;
			break;
			case 1:
				this.u1=val;
			break;
			case 2:
				this.u2=val;
			break;
			default:
				
		}
	}	
	
	public void setMappingUV(float u0,float v0,float u1,float v1,float u2,float v2)		
	{
		this.u0=u0;
		this.v0=v0;
		this.u1=u1;
		this.v1=v1;
		this.u2=u2;
		this.v2=v2;
	}	
		
	public void setMappingV(int numVertex,float val)
	{
		switch(numVertex)
		{
			case 0:
				this.v0=val;
			break;
			case 1:
				this.v1=val;
			break;
			case 2:
				this.v2=val;
			break;
			default:
				
		}
	}
	
	public int getId()
	{
		return this.id;
	}
	
	public float getVertex3D0Nx()
	{
		return this.p0nx;
	}		
	
	public float getVertex3D0Ny()
	{
		return this.p0ny;
	}		
	
	public float getVertex3D0Nz()
	{
		return this.p0nz;
	}	
	
	public float getVertex3D1Nx()
	{
		return this.p1nx;
	}		
	
	public float getVertex3D1Ny()
	{
		return this.p1ny;
	}		
	
	public float getVertex3D1Nz()
	{
		return this.p1nz;
	}
	
	public float getVertex3D2Nx()
	{
		return this.p2nx;
	}		
	
	public float getVertex3D2Ny()
	{
		return this.p2ny;
	}		
	
	public float getVertex3D2Nz()
	{
		return this.p2nz;
	}	
	
	public IPoint3D getCenter()
	{
		return this.center;
	}
	
	public void setSmoothGroup(int smooth)
	{
		this.smoothGroupMask=smooth;
	}
}