import point3d;
import vector3d;
import defines;

// The 3D view matrix class
class matrix3d
{
	protected double[][] Matrix = new double[4][4];
	protected double[][] RMatrix = new double[4][4];
	protected int Xr, Yr, Zr;
	protected double XTrans, YTrans, ZTrans;
	protected defines def = new defines();
	
	public matrix3d()
	{
		def.InitMath();
		Xr = Yr = Zr = 0;
		XTrans = YTrans = ZTrans = 0;

	}// matrix3d()

	//-------------------------------------------------------------

	protected void InitMat(double Mat[][])
	{
		// Initializes a specific matrix to the identity matrix:
		Mat[0][0] = 1; Mat[0][1] = 0; Mat[0][2] = 0; Mat[0][3] = 0;
		Mat[1][0] = 0; Mat[1][1] = 1; Mat[1][2] = 0; Mat[1][3] = 0;
		Mat[2][0] = 0; Mat[2][1] = 0; Mat[2][2] = 1; Mat[2][3] = 0;
		Mat[3][0] = 0; Mat[3][1] = 0; Mat[3][2] = 0; Mat[3][3] = 1;
	}// InitMat()

	//-------------------------------------------------------------

	protected void MergeMatrix(double NewMatrix[][])
	{
		// Multiply NewMatrix by Matrix; store result in TempMatrix
		double[][] TempMatrix = new double[4][4];
		for(int i = 0; i<4; i++)
			for(int j = 0; j<4; j++)
				TempMatrix[i][j] = (Matrix[i][0] * NewMatrix[0][j])
								 + (Matrix[i][1] * NewMatrix[1][j])
								 + (Matrix[i][2] * NewMatrix[2][j])
								 + (Matrix[i][3] * NewMatrix[3][j]);
		// Copy TempMatrix to Matrix
		for(int i=0;i<4;i++)
			for(int j=0;j<4;j++)
				Matrix[i][j] = TempMatrix[i][j];
		
	}// MergeMatrix()

	//-------------------------------------------------------------

	protected void MergeMatrices(double Dest[][], double Source[][])
	{

		// Multiply Source by Dest; store result in Temp
		double[][] Temp = new double[4][4];
		for(int i = 0; i<4; i++)
			for(int j = 0; j<4; j++)
			{
				Temp[i][j] = (Source[i][0] * Dest[0][j])
					       + (Source[i][1] * Dest[1][j])
						   + (Source[i][2] * Dest[2][j])
						   + (Source[i][3] * Dest[3][j]);
			}
		
		// copy Temp to Dest
		for(int i = 0; i<4; i++)
			for(int j=0;j<4; j++)
				Dest[i][j] = Temp[i][j];

	}// MergeMatrices()

	//-------------------------------------------------------------

	public void Rotate(int Xa, int Ya, int Za)
	{
		// Generate 3D rotation matrix
		Xr = Xa; Yr = Ya; Zr = Za;
		double[][] Rmat = new double[4][4];
		InitMat(RMatrix);

		//Initialize Z rotatin matrix -
		// Note: we perform Z rotation first to align the 3D z axis with the 2D z axis

		Rmat[0][0] = def.COS(Za); Rmat[0][1] = def.SIN(Za);
		Rmat[0][2] = 0; Rmat[0][3] = 0;

		Rmat[1][0] = -def.SIN(Za); Rmat[1][1] = def.COS(Za);
		Rmat[1][2] = 0; Rmat[1][3] = 0;

		Rmat[2][0] = 0; Rmat[2][1] = 0; Rmat[2][2] = 1; Rmat[2][3] = 0;
		Rmat[3][0] = 0; Rmat[3][1] = 0; Rmat[3][2] = 0; Rmat[3][3] = 1;

		// Merge matrix with master matrix:
		MergeMatrices(RMatrix, Rmat);

		// Initialize X rotation matrix:
		Rmat[0][0]=1; Rmat[0][1]=0;            Rmat[0][2]=0;           Rmat[0][3]=0;
		Rmat[1][0]=0; Rmat[1][1]=def.COS(Xa);  Rmat[1][2]=def.SIN(Xa); Rmat[1][3]=0;
		Rmat[2][0]=0; Rmat[2][1]=-def.SIN(Xa); Rmat[2][2]=def.COS(Xa); Rmat[2][3]=0;
		Rmat[3][0]=0; Rmat[3][1]=0;            Rmat[3][2]=0;           Rmat[3][3]=1;

		//Merge matrix with master matrix:
		MergeMatrices(RMatrix,Rmat);

		//Initialize Y rotation matrix:
		Rmat[0][0]=def.COS(Ya); Rmat[0][1]=0; Rmat[0][2]=-def.SIN(Ya); Rmat[0][3]=0;
		Rmat[1][0]=0;           Rmat[1][1]=1; Rmat[1][2]=0;            Rmat[1][3]=0;
		Rmat[2][0]=def.SIN(Ya); Rmat[2][1]=0; Rmat[2][2]=def.COS(Ya);  Rmat[2][3]=0;
		Rmat[3][0]=0;           Rmat[3][1]=0; Rmat[3][2]=0;            Rmat[3][3]=1;

		//Merge matrix with master matrix:
		MergeMatrices(RMatrix, Rmat);

		MergeMatrix(RMatrix);

	}// Rotate()

	//-------------------------------------------------------------

	public void Translate(double Xt, double Yt, double Zt)
	{
		// Create 3D translation matrix:

		// Declare translation matrix:
		double[][] Tmat = new double[4][4];

		// Save translation values
		XTrans = Xt; YTrans = Yt; ZTrans = Zt;

		// Initialize translation matrix:
		Tmat[0][0]=1;  Tmat[0][1]=0;  Tmat[0][2]=0;  Tmat[0][3]=0;
		Tmat[1][0]=0;  Tmat[1][1]=1;  Tmat[1][2]=0;  Tmat[1][3]=0;
		Tmat[2][0]=0;  Tmat[2][1]=0;  Tmat[2][2]=1;  Tmat[2][3]=0;
		Tmat[3][0]=Xt; Tmat[3][1]=Yt; Tmat[3][2]=Zt; Tmat[3][3]=1;

		// Merge matrix with master matrix:
		MergeMatrix(Tmat);

	}// Translate()

	//-------------------------------------------------------------

	public void Scale(double Xs, double Ys, double Zs)
	{
		// Merge scaling matrix with master matrix:

		// Create 3d scaling matrix

		double[][] Smat = new double[4][4];

		// Initialize scaling matrix:
		Smat[0][0]=Xs; Smat[0][1]=0;  Smat[0][2]=0;  Smat[0][3]=0;
		Smat[1][0]=0;  Smat[1][1]=Ys; Smat[1][2]=0;  Smat[1][3]=0;
		Smat[2][0]=0;  Smat[2][1]=0;  Smat[2][2]=Zs; Smat[2][3]=0;
		Smat[3][0]=0;  Smat[3][1]=0;  Smat[3][2]=0;  Smat[3][3]=1;

		//Merge matrix with master matrix:
		MergeMatrix(Smat);

	}// Scale()

	//-------------------------------------------------------------

	public void Shear(double Xs, double Ys)
	{

		// Create 3D shearing matrix:

		double[][] Smat = new double[4][4];

		//Initialize shearing matrix:
		Smat[0][0]=1;  Smat[0][1]=0;  Smat[0][2]=Xs; Smat[0][3]=0;
		Smat[1][0]=0;  Smat[1][1]=1;  Smat[1][2]=Ys; Smat[1][3]=0;
		Smat[2][0]=0;  Smat[2][1]=0;  Smat[2][2]=1;  Smat[2][3]=0;
		Smat[3][0]=0;  Smat[3][1]=0;  Smat[3][2]=0;  Smat[3][3]=1;

		// Merge matrix with master matrix:
		MergeMatrix(Smat);
	}// Shear()

	//-------------------------------------------------------------

	public void Initialize()
	{
		Matrix[0][0]=1;  Matrix[0][1]=0;  Matrix[0][2]=0;  Matrix[0][3]=0;
		Matrix[1][0]=0;  Matrix[1][1]=1;  Matrix[1][2]=0;  Matrix[1][3]=0;
		Matrix[2][0]=0;  Matrix[2][1]=0;  Matrix[2][2]=1;  Matrix[2][3]=0;
		Matrix[3][0]=0;  Matrix[3][1]=0;  Matrix[3][2]=0;  Matrix[3][3]=1;
	}// Initialize()

	//-------------------------------------------------------------

	public point3d Transform(point3d V)
	{
		// Function designed to transform a vertex using the master
		
		// Initialize temporary variables:
		double Lx = V.Lx;
		double Ly = V.Ly;
		double Lz = V.Lz;

		// Transform vertex by master matrix:

		V.Wx = ((Lx * Matrix[0][0]))
			 + ((Ly * Matrix[1][0]))
			 + ((Lz * Matrix[2][0]))
			 +        Matrix[3][0];

		V.Wy = ((Lx * Matrix[0][1]))
			 + ((Ly * Matrix[1][1]))
			 + ((Lz * Matrix[2][1]))
			 +        Matrix[3][1];

		V.Wz = ((Lx * Matrix[0][2]))
			 + ((Ly * Matrix[1][2]))
			 + ((Lz * Matrix[2][2]))
			 +        Matrix[3][2];
		
		return V;
	}// Transform(point3d)

	//-------------------------------------------------------------------

	public Vector Transform(Vector v)
	{
		// Function designed to transform a vector using the master matrix

		// Initialize temporary vvariables:

		double OldX = v.x;
		double OldY = v.y;
		double OldZ = v.z;

		// Transform vertex by master matris:

		v.Tx = (( OldX * Matrix[0][0]))
			+  (( OldY * Matrix[1][0]))
			+  (( OldZ * Matrix[2][0]))
			+            Matrix[3][0];

  		v.Ty = (( OldX * Matrix[0][1]))
			+  (( OldY * Matrix[1][1]))
			+  (( OldZ * Matrix[2][1]))
			+            Matrix[3][1];

		v.Tz = (( OldX * Matrix[0][2]))
			+  (( OldY * Matrix[1][2]))
			+  (( OldZ * Matrix[2][2]))
			+            Matrix[3][2];

		return v;

	}// Transform(vector)

	//---------------------------------------------------------

	public double GetXt()
	{
		return XTrans;
	}// GetXt()

	//---------------------------------------------------------

	public double GetYt()
	{
		return YTrans;
	}// GetYt()

	//---------------------------------------------------------

	public double GetZt()
	{
		return ZTrans;
	}// GetZt()

};
