package glmodel; import java.nio.FloatBuffer; /** * Define a 4x4 matrix, and provide functions to create common * matrices for 3D operations, such as rotate, scale and translate. */ public class GL_Matrix { // vars hold a 4x4 matrix, defaults to identity matrix. public float m00=1, m01=0, m02=0, m03=0; public float m10=0, m11=1, m12=0, m13=0; public float m20=0, m21=0, m22=1, m23=0; public float m30=0, m31=0, m32=0, m33=1; /** * Default to the identity matrix */ public GL_Matrix() { } /** * Create a matrix with the three given axes */ public GL_Matrix(GL_Vector right, GL_Vector up, GL_Vector forward) { m00 = right.x; m10 = right.y; m20 = right.z; m01 = up.x; m11 = up.y; m21 = up.z; m02 = forward.x; m12 = forward.y; m22 = forward.z; } /** * copy a two dimensional float array into this Matrix */ public void importFromArray(float[][] data) { // insure that the array is 4x4 if (data.length<4) return; for (int i=0;i<4;i++) if (data[i].length<4) return; m00=data[0][0]; m01=data[0][1]; m02=data[0][2]; m03=data[0][3]; m10=data[1][0]; m11=data[1][1]; m12=data[1][2]; m13=data[1][3]; m20=data[2][0]; m21=data[2][1]; m22=data[2][2]; m23=data[2][3]; m30=data[3][0]; m31=data[3][1]; m32=data[3][2]; m33=data[3][3]; } /** * return a two dimensional float array containing this Matrix */ public float[][] exportToArray() { float data[][] = new float[4][4]; data[0][0]=m00; data[0][1]=m01; data[0][2]=m02; data[0][3]=m03; data[1][0]=m10; data[1][1]=m11; data[1][2]=m12; data[1][3]=m13; data[2][0]=m20; data[2][1]=m21; data[2][2]=m22; data[2][3]=m23; data[3][0]=m30; data[3][1]=m31; data[3][2]=m32; data[3][3]=m33; return data; } /////////////////////////////////////////////////////////// // Factory Methods /////////////////////////////////////////////////////////// /** * create a Matrix shifted by the given amounts */ public static GL_Matrix translateMatrix(float dx, float dy, float dz) { GL_Matrix m = new GL_Matrix(); m.m03=dx; m.m13=dy; m.m23=dz; return m; } /** * create a Matrix to change scale */ public static GL_Matrix scaleMatrix(float dx, float dy, float dz) { GL_Matrix m=new GL_Matrix(); m.m00=dx; m.m11=dy; m.m22=dz; return m; } /** * create a Matrix to scale all axes equally */ public static GL_Matrix scaleMatrix(float d) { return GL_Matrix.scaleMatrix(d,d,d); } /** * create a rotation matrix */ public static GL_Matrix rotateMatrix(float dx, float dy, float dz) { GL_Matrix out=new GL_Matrix(); float SIN; float COS; if (dx!=0) { GL_Matrix m =new GL_Matrix(); SIN = (float)Math.sin(dx); COS = (float)Math.cos(dx); m.m11=COS; m.m12=SIN; m.m21=-SIN; m.m22=COS; out.transform(m); } if (dy!=0) { GL_Matrix m =new GL_Matrix(); SIN = (float)Math.sin(dy); COS = (float)Math.cos(dy); m.m00=COS; m.m02=SIN; m.m20=-SIN; m.m22=COS; out.transform(m); } if (dz!=0) { GL_Matrix m =new GL_Matrix(); SIN = (float)Math.sin(dz); COS = (float)Math.cos(dz); m.m00=COS; m.m01=SIN; m.m10=-SIN; m.m11=COS; out.transform(m); } return out; } /////////////////////////////////////////////////////////// // Public Methods /////////////////////////////////////////////////////////// public void translate(float dx, float dy, float dz) { transform(translateMatrix(dx,dy,dz)); } public void scale(float dx, float dy, float dz) { transform(scaleMatrix(dx,dy,dz)); } public void scale(float d) { transform(scaleMatrix(d)); } public void rotate(float dx, float dy, float dz) { transform(rotateMatrix(dx,dy,dz)); } public void scaleSelf(float dx, float dy, float dz) { preTransform(scaleMatrix(dx,dy,dz)); } public void scaleSelf(float d) { preTransform(scaleMatrix(d)); } public void rotateSelf(float dx, float dy, float dz) { preTransform(rotateMatrix(dx,dy,dz)); } /** * reset to the identity matrix */ public void reset() { m00=1; m01=0; m02=0; m03=0; m10=0; m11=1; m12=0; m13=0; m20=0; m21=0; m22=1; m23=0; m30=0; m31=0; m32=0; m33=1; } /** * Transform the given vector using this matrix. Return the * transformed vector (the original vector is not modified). * * @param v GL_Vector to be transformed * @return the transformed GL_Vector */ public GL_Vector transform(GL_Vector v) { if (v != null) { float newx, newy, newz; newx = v.x*m00 + v.y*m01 + v.z*m02+ m03; newy = v.x*m10 + v.y*m11 + v.z*m12+ m13; newz = v.x*m20 + v.y*m21 + v.z*m22+ m23; return new GL_Vector(newx,newy,newz); } return null; } /** * transforms this matrix by matrix n from left (this=n x this) */ public void transform(GL_Matrix n) { GL_Matrix m = this.getClone(); m00 = n.m00*m.m00 + n.m01*m.m10 + n.m02*m.m20; m01 = n.m00*m.m01 + n.m01*m.m11 + n.m02*m.m21; m02 = n.m00*m.m02 + n.m01*m.m12 + n.m02*m.m22; m03 = n.m00*m.m03 + n.m01*m.m13 + n.m02*m.m23 + n.m03; m10 = n.m10*m.m00 + n.m11*m.m10 + n.m12*m.m20; m11 = n.m10*m.m01 + n.m11*m.m11 + n.m12*m.m21; m12 = n.m10*m.m02 + n.m11*m.m12 + n.m12*m.m22; m13 = n.m10*m.m03 + n.m11*m.m13 + n.m12*m.m23 + n.m13; m20 = n.m20*m.m00 + n.m21*m.m10 + n.m22*m.m20; m21 = n.m20*m.m01 + n.m21*m.m11 + n.m22*m.m21; m22 = n.m20*m.m02 + n.m21*m.m12 + n.m22*m.m22; m23 = n.m20*m.m03 + n.m21*m.m13 + n.m22*m.m23 + n.m23; } /** * transforms this matrix by matrix n from right (this=this x n) */ public void preTransform(GL_Matrix n) { GL_Matrix m=this.getClone(); m00 = m.m00*n.m00 + m.m01*n.m10 + m.m02*n.m20; m01 = m.m00*n.m01 + m.m01*n.m11 + m.m02*n.m21; m02 = m.m00*n.m02 + m.m01*n.m12 + m.m02*n.m22; m03 = m.m00*n.m03 + m.m01*n.m13 + m.m02*n.m23 + m.m03; m10 = m.m10*n.m00 + m.m11*n.m10 + m.m12*n.m20; m11 = m.m10*n.m01 + m.m11*n.m11 + m.m12*n.m21; m12 = m.m10*n.m02 + m.m11*n.m12 + m.m12*n.m22; m13 = m.m10*n.m03 + m.m11*n.m13 + m.m12*n.m23 + m.m13; m20 = m.m20*n.m00 + m.m21*n.m10 + m.m22*n.m20; m21 = m.m20*n.m01 + m.m21*n.m11 + m.m22*n.m21; m22 = m.m20*n.m02 + m.m21*n.m12 + m.m22*n.m22; m23 = m.m20*n.m03 + m.m21*n.m13 + m.m22*n.m23 + m.m23; } /** * Multiply the two matrices. Return m1 x m2 */ public static GL_Matrix multiply(GL_Matrix m1, GL_Matrix m2) { GL_Matrix m = new GL_Matrix(); m.m00 = m1.m00*m2.m00 + m1.m01*m2.m10 + m1.m02*m2.m20; m.m01 = m1.m00*m2.m01 + m1.m01*m2.m11 + m1.m02*m2.m21; m.m02 = m1.m00*m2.m02 + m1.m01*m2.m12 + m1.m02*m2.m22; m.m03 = m1.m00*m2.m03 + m1.m01*m2.m13 + m1.m02*m2.m23 + m1.m03; m.m10 = m1.m10*m2.m00 + m1.m11*m2.m10 + m1.m12*m2.m20; m.m11 = m1.m10*m2.m01 + m1.m11*m2.m11 + m1.m12*m2.m21; m.m12 = m1.m10*m2.m02 + m1.m11*m2.m12 + m1.m12*m2.m22; m.m13 = m1.m10*m2.m03 + m1.m11*m2.m13 + m1.m12*m2.m23 + m1.m13; m.m20 = m1.m20*m2.m00 + m1.m21*m2.m10 + m1.m22*m2.m20; m.m21 = m1.m20*m2.m01 + m1.m21*m2.m11 + m1.m22*m2.m21; m.m22 = m1.m20*m2.m02 + m1.m21*m2.m12 + m1.m22*m2.m22; m.m23 = m1.m20*m2.m03 + m1.m21*m2.m13 + m1.m22*m2.m23 + m1.m23; return m; } /** * return a string representation of this matrix */ public String toString() { StringBuffer out=new StringBuffer("\r\n"); return out.toString(); } /** * return a copy of this matrix */ public GL_Matrix getClone() { GL_Matrix m=new GL_Matrix(); m.m00=m00; m.m01=m01; m.m02=m02; m.m03=m03; m.m10=m10; m.m11=m11; m.m12=m12; m.m13=m13; m.m20=m20; m.m21=m21; m.m22=m22; m.m23=m23; m.m30=m30; m.m31=m31; m.m32=m32; m.m33=m33; return m; } /** * return the inverse of this matrix */ public GL_Matrix inverse() { GL_Matrix m = new GL_Matrix(); float q1 = m12; float q6 = m10*m01; float q7 = m10*m21; float q8 = m02; float q13 = m20*m01; float q14 = m20*m11; float q21 = m02*m21; float q22 = m03*m21; float q25 = m01*m12; float q26 = m01*m13; float q27 = m02*m11; float q28 = m03*m11; float q29 = m10*m22; float q30 = m10*m23; float q31 = m20*m12; float q32 = m20*m13; float q35 = m00*m22; float q36 = m00*m23; float q37 = m20*m02; float q38 = m20*m03; float q41 = m00*m12; float q42 = m00*m13; float q43 = m10*m02; float q44 = m10*m03; float q45 = m00*m11; float q48 = m00*m21; float q49 = q45*m22-q48*q1-q6*m22+q7*q8; float q50 = q13*q1-q14*q8; float q51 = 1/(q49+q50); m.m00 = (m11*m22*m33-m11*m23*m32-m21*m12*m33+m21*m13*m32+m31*m12*m23-m31*m13*m22)*q51; m.m01 = -(m01*m22*m33-m01*m23*m32-q21*m33+q22*m32)*q51; m.m02 = (q25*m33-q26*m32-q27*m33+q28*m32)*q51; m.m03 = -(q25*m23-q26*m22-q27*m23+q28*m22+q21*m13-q22*m12)*q51; m.m10 = -(q29*m33-q30*m32-q31*m33+q32*m32)*q51; m.m11 = (q35*m33-q36*m32-q37*m33+q38*m32)*q51; m.m12 = -(q41*m33-q42*m32-q43*m33+q44*m32)*q51; m.m13 = (q41*m23-q42*m22-q43*m23+q44*m22+q37*m13-q38*m12)*q51; m.m20 = (q7*m33-q30*m31-q14*m33+q32*m31)*q51; m.m21 = -(q48*m33-q36*m31-q13*m33+q38*m31)*q51; m.m22 = (q45*m33-q42*m31-q6*m33+q44*m31)*q51; m.m23 = -(q45*m23-q42*m21-q6*m23+q44*m21+q13*m13-q38*m11)*q51; return m; } /** * vCreate the billboard matrix: a rotation matrix created from an arbitrary set * of axis. Store those axis values in the first 3 columns of the matrix. Col * 1 is the X axis, col 2 is the Y axis, and col 3 is the Z axis. We are * rotating right into X, up into Y, and look into Z. The rotation matrix * created from the rows will translate the arbitrary axis set to the global * vaxis set. Lastly, OpenGl stores the matrices by columns, so enter the data * into the array columns first. * * pos: position of billboard * right, up, look: orientation of billboard x,y,z axes */ public static void createBillboardMatrix(FloatBuffer matrix, GL_Vector right, GL_Vector up, GL_Vector look, GL_Vector pos) { matrix.put(0, right.x); matrix.put(1, right.y); matrix.put(2, right.z); matrix.put(3, 0); matrix.put(4, up.x); matrix.put(5, up.y); matrix.put(6, up.z); matrix.put(7, 0); matrix.put(8, look.x); matrix.put(9, look.y); matrix.put(10, look.z); matrix.put(11, 0); // Add the translation in as well. matrix.put(12, pos.x); matrix.put(13, pos.y); matrix.put(14, pos.z); matrix.put(15, 1); } }