You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1220 lines
29 KiB
1220 lines
29 KiB
// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ . |
|
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌· |
|
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀ |
|
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌ |
|
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀ |
|
// Magicbane Emulator Project © 2013 - 2022 |
|
// www.magicbane.com |
|
|
|
package engine.math; |
|
|
|
import org.pmw.tinylog.Logger; |
|
|
|
import java.nio.FloatBuffer; |
|
|
|
|
|
/** |
|
* <code>Matrix3f</code> defines a 3x3 matrix. Matrix data is maintained |
|
* internally and is accessible via the get and set methods. Convenience methods |
|
* are used for matrix operations as well as generating a matrix from a given |
|
* set of values. |
|
* |
|
*/ |
|
public class Matrix3f { |
|
public float m00, m01, m02; |
|
public float m10, m11, m12; |
|
public float m20, m21, m22; |
|
|
|
/** |
|
* Constructor instantiates a new <code>Matrix3f</code> object. The initial |
|
* values for the matrix is that of the identity matrix. |
|
* |
|
*/ |
|
public Matrix3f() { |
|
loadIdentity(); |
|
} |
|
|
|
/** |
|
* constructs a matrix with the given values. |
|
* |
|
* @param m00 |
|
* 0x0 in the matrix. |
|
* @param m01 |
|
* 0x1 in the matrix. |
|
* @param m02 |
|
* 0x2 in the matrix. |
|
* @param m10 |
|
* 1x0 in the matrix. |
|
* @param m11 |
|
* 1x1 in the matrix. |
|
* @param m12 |
|
* 1x2 in the matrix. |
|
* @param m20 |
|
* 2x0 in the matrix. |
|
* @param m21 |
|
* 2x1 in the matrix. |
|
* @param m22 |
|
* 2x2 in the matrix. |
|
*/ |
|
public Matrix3f(float m00, float m01, float m02, float m10, float m11, |
|
float m12, float m20, float m21, float m22) { |
|
|
|
this.m00 = m00; |
|
this.m01 = m01; |
|
this.m02 = m02; |
|
this.m10 = m10; |
|
this.m11 = m11; |
|
this.m12 = m12; |
|
this.m20 = m20; |
|
this.m21 = m21; |
|
this.m22 = m22; |
|
} |
|
|
|
/** |
|
* Copy constructor that creates a new <code>Matrix3f</code> object that is |
|
* the same as the provided matrix. |
|
* |
|
* @param mat |
|
* the matrix to copy. |
|
*/ |
|
public Matrix3f(Matrix3f mat) { |
|
copy(mat); |
|
} |
|
|
|
/** |
|
* <code>copy</code> transfers the contents of a given matrix to this |
|
* matrix. If a null matrix is supplied, this matrix is set to the identity |
|
* matrix. |
|
* |
|
* @param matrix |
|
* the matrix to copy. |
|
*/ |
|
public void copy(Matrix3f matrix) { |
|
if (null == matrix) { |
|
loadIdentity(); |
|
} else { |
|
m00 = matrix.m00; |
|
m01 = matrix.m01; |
|
m02 = matrix.m02; |
|
m10 = matrix.m10; |
|
m11 = matrix.m11; |
|
m12 = matrix.m12; |
|
m20 = matrix.m20; |
|
m21 = matrix.m21; |
|
m22 = matrix.m22; |
|
} |
|
} |
|
|
|
/** |
|
* <code>get</code> retrieves a value from the matrix at the given position. |
|
* If the position is invalid a <code>Exception</code> is thrown. |
|
* |
|
* @param i |
|
* the row index. |
|
* @param j |
|
* the column index. |
|
* @return the value at (i, j). |
|
* @throws Exception |
|
*/ |
|
public float get(int i, int j) throws Exception { |
|
switch (i) { |
|
case 0: |
|
switch (j) { |
|
case 0: |
|
return m00; |
|
case 1: |
|
return m01; |
|
case 2: |
|
return m02; |
|
} |
|
case 1: |
|
switch (j) { |
|
case 0: |
|
return m10; |
|
case 1: |
|
return m11; |
|
case 2: |
|
return m12; |
|
} |
|
case 2: |
|
switch (j) { |
|
case 0: |
|
return m20; |
|
case 1: |
|
return m21; |
|
case 2: |
|
return m22; |
|
} |
|
} |
|
throw new Exception("Invalid indices into matrix."); |
|
} |
|
|
|
/** |
|
* <code>get(float[])</code> returns the matrix in row-major or column-major |
|
* order. |
|
* |
|
* @param data |
|
* The array to return the data into. This array can be 9 or 16 |
|
* floats in size. Only the upper 3x3 are assigned to in the case |
|
* of a 16 element array. |
|
* @param rowMajor |
|
* True for row major storage in the array (translation in |
|
* elements 3, 7, 11 for a 4x4), false for column major |
|
* (translation in elements 12, 13, 14 for a 4x4). |
|
* @throws Exception |
|
*/ |
|
public void get(float[] data, boolean rowMajor) throws Exception { |
|
if (data.length == 9) { |
|
if (rowMajor) { |
|
data[0] = m00; |
|
data[1] = m01; |
|
data[2] = m02; |
|
data[3] = m10; |
|
data[4] = m11; |
|
data[5] = m12; |
|
data[6] = m20; |
|
data[7] = m21; |
|
data[8] = m22; |
|
} else { |
|
data[0] = m00; |
|
data[1] = m10; |
|
data[2] = m20; |
|
data[3] = m01; |
|
data[4] = m11; |
|
data[5] = m21; |
|
data[6] = m02; |
|
data[7] = m12; |
|
data[8] = m22; |
|
} |
|
} else if (data.length == 16) { |
|
if (rowMajor) { |
|
data[0] = m00; |
|
data[1] = m01; |
|
data[2] = m02; |
|
data[4] = m10; |
|
data[5] = m11; |
|
data[6] = m12; |
|
data[8] = m20; |
|
data[9] = m21; |
|
data[10] = m22; |
|
} else { |
|
data[0] = m00; |
|
data[1] = m10; |
|
data[2] = m20; |
|
data[4] = m01; |
|
data[5] = m11; |
|
data[6] = m21; |
|
data[8] = m02; |
|
data[9] = m12; |
|
data[10] = m22; |
|
} |
|
} else { |
|
throw new Exception("Array size must be 9 or 16 in Matrix3f.get()."); |
|
} |
|
} |
|
|
|
/** |
|
* <code>getColumn</code> returns one of three columns specified by the |
|
* parameter. This column is returned as a <code>Vector3f</code> object. |
|
* |
|
* @param i |
|
* the column to retrieve. Must be between 0 and 2. |
|
* @return the column specified by the index. |
|
* @throws Exception |
|
*/ |
|
public Vector3f getColumn(int i) throws Exception { |
|
return getColumn(i, null); |
|
} |
|
|
|
/** |
|
* <code>getColumn</code> returns one of three columns specified by the |
|
* parameter. This column is returned as a <code>Vector3f</code> object. |
|
* |
|
* @param i |
|
* the column to retrieve. Must be between 0 and 2. |
|
* @param store |
|
* the vector object to store the result in. if null, a new one |
|
* is created. |
|
* @return the column specified by the index. |
|
* @throws Exception |
|
*/ |
|
public Vector3f getColumn(int i, Vector3f store) throws Exception { |
|
if (store == null) |
|
store = new Vector3f(); |
|
switch (i) { |
|
case 0: |
|
store.x = m00; |
|
store.y = m10; |
|
store.z = m20; |
|
break; |
|
case 1: |
|
store.x = m01; |
|
store.y = m11; |
|
store.z = m21; |
|
break; |
|
case 2: |
|
store.x = m02; |
|
store.y = m12; |
|
store.z = m22; |
|
break; |
|
default: |
|
throw new Exception("Invalid column index. " + i); |
|
} |
|
return store; |
|
} |
|
|
|
/** |
|
* <code>getColumn</code> returns one of three rows as specified by the |
|
* parameter. This row is returned as a <code>Vector3f</code> object. |
|
* |
|
* @param i |
|
* the row to retrieve. Must be between 0 and 2. |
|
* @return the row specified by the index. |
|
* @throws Exception |
|
*/ |
|
public Vector3f getRow(int i) throws Exception { |
|
return getRow(i, null); |
|
} |
|
|
|
/** |
|
* <code>getRow</code> returns one of three rows as specified by the |
|
* parameter. This row is returned as a <code>Vector3f</code> object. |
|
* |
|
* @param i |
|
* the row to retrieve. Must be between 0 and 2. |
|
* @param store |
|
* the vector object to store the result in. if null, a new one |
|
* is created. |
|
* @return the row specified by the index. |
|
* @throws Exception |
|
*/ |
|
public Vector3f getRow(int i, Vector3f store) throws Exception { |
|
if (store == null) |
|
store = new Vector3f(); |
|
switch (i) { |
|
case 0: |
|
store.x = m00; |
|
store.y = m01; |
|
store.z = m02; |
|
break; |
|
case 1: |
|
store.x = m10; |
|
store.y = m11; |
|
store.z = m12; |
|
break; |
|
case 2: |
|
store.x = m20; |
|
store.y = m21; |
|
store.z = m22; |
|
break; |
|
default: |
|
throw new Exception("Invalid row index. " + i); |
|
} |
|
return store; |
|
} |
|
|
|
/** |
|
* <code>fillFloatBuffer</code> fills a FloatBuffer object with the matrix |
|
* data. |
|
* |
|
* @param fb |
|
* the buffer to fill, starting at current position. Must have |
|
* room for 9 more floats. |
|
* @return matrix data as a FloatBuffer. (position is advanced by 9 and any |
|
* limit set is not changed). |
|
*/ |
|
public FloatBuffer fillFloatBuffer(FloatBuffer fb) { |
|
fb.put(m00).put(m01).put(m02); |
|
fb.put(m10).put(m11).put(m12); |
|
fb.put(m20).put(m21).put(m22); |
|
return fb; |
|
} |
|
|
|
/** |
|
* |
|
* <code>setColumn</code> sets a particular column of this matrix to that |
|
* represented by the provided vector. |
|
* |
|
* @param i |
|
* the column to set. |
|
* @param column |
|
* the data to set. |
|
* @throws Exception |
|
*/ |
|
public void setColumn(int i, Vector3f column) throws Exception { |
|
|
|
if (column == null) { |
|
return; |
|
} |
|
switch (i) { |
|
case 0: |
|
m00 = column.x; |
|
m10 = column.y; |
|
m20 = column.z; |
|
break; |
|
case 1: |
|
m01 = column.x; |
|
m11 = column.y; |
|
m21 = column.z; |
|
break; |
|
case 2: |
|
m02 = column.x; |
|
m12 = column.y; |
|
m22 = column.z; |
|
break; |
|
default: |
|
throw new Exception("Invalid column index. " + i); |
|
} |
|
} |
|
|
|
/** |
|
* |
|
* <code>setRow</code> sets a particular row of this matrix to that |
|
* represented by the provided vector. |
|
* |
|
* @param i |
|
* the row to set. |
|
* @param row |
|
* the data to set. |
|
* @throws Exception |
|
*/ |
|
public void setRow(int i, Vector3f row) throws Exception { |
|
|
|
if (row == null) { |
|
return; |
|
} |
|
switch (i) { |
|
case 0: |
|
m00 = row.x; |
|
m01 = row.y; |
|
m02 = row.z; |
|
break; |
|
case 1: |
|
m10 = row.x; |
|
m11 = row.y; |
|
m12 = row.z; |
|
break; |
|
case 2: |
|
m20 = row.x; |
|
m21 = row.y; |
|
m22 = row.z; |
|
break; |
|
default: |
|
throw new Exception("Invalid row index. " + i); |
|
} |
|
} |
|
|
|
/** |
|
* <code>set</code> places a given value into the matrix at the given |
|
* position. If the position is invalid a <code>Exception</code> is thrown. |
|
* |
|
* @param i |
|
* the row index. |
|
* @param j |
|
* the column index. |
|
* @param value |
|
* the value for (i, j). |
|
* @throws Exception |
|
*/ |
|
public void set(int i, int j, float value) throws Exception { |
|
switch (i) { |
|
case 0: |
|
switch (j) { |
|
case 0: |
|
m00 = value; |
|
return; |
|
case 1: |
|
m01 = value; |
|
return; |
|
case 2: |
|
m02 = value; |
|
return; |
|
} |
|
case 1: |
|
switch (j) { |
|
case 0: |
|
m10 = value; |
|
return; |
|
case 1: |
|
m11 = value; |
|
return; |
|
case 2: |
|
m12 = value; |
|
return; |
|
} |
|
case 2: |
|
switch (j) { |
|
case 0: |
|
m20 = value; |
|
return; |
|
case 1: |
|
m21 = value; |
|
return; |
|
case 2: |
|
m22 = value; |
|
return; |
|
} |
|
} |
|
throw new Exception("Invalid indices into matrix."); |
|
} |
|
|
|
/** |
|
* |
|
* <code>set</code> sets the values of the matrix to those supplied by the |
|
* 3x3 two dimenion array. |
|
* |
|
* @param matrix |
|
* the new values of the matrix. |
|
* @throws Exception |
|
* if the array is not of size 9. |
|
*/ |
|
public void set(float[][] matrix) throws Exception { |
|
if (matrix.length != 3 || matrix[0].length != 3) { |
|
throw new Exception("Array must be of size 9."); |
|
} |
|
|
|
m00 = matrix[0][0]; |
|
m01 = matrix[0][1]; |
|
m02 = matrix[0][2]; |
|
m10 = matrix[1][0]; |
|
m11 = matrix[1][1]; |
|
m12 = matrix[1][2]; |
|
m20 = matrix[2][0]; |
|
m21 = matrix[2][1]; |
|
m22 = matrix[2][2]; |
|
} |
|
|
|
/** |
|
* Recreate Matrix using the provided axis. |
|
* |
|
* @param uAxis |
|
* Vector3f |
|
* @param vAxis |
|
* Vector3f |
|
* @param wAxis |
|
* Vector3f |
|
*/ |
|
public void fromAxes(Vector3f uAxis, Vector3f vAxis, Vector3f wAxis) { |
|
m00 = uAxis.x; |
|
m10 = uAxis.y; |
|
m20 = uAxis.z; |
|
|
|
m01 = vAxis.x; |
|
m11 = vAxis.y; |
|
m21 = vAxis.z; |
|
|
|
m02 = wAxis.x; |
|
m12 = wAxis.y; |
|
m22 = wAxis.z; |
|
} |
|
|
|
/** |
|
* <code>set</code> sets the values of this matrix from an array of values |
|
* assuming that the data is rowMajor order; |
|
* |
|
* @param matrix |
|
* the matrix to set the value to. |
|
* @throws Exception |
|
*/ |
|
public void set(float[] matrix) throws Exception { |
|
set(matrix, true); |
|
} |
|
|
|
/** |
|
* <code>set</code> sets the values of this matrix from an array of values; |
|
* |
|
* @param matrix |
|
* the matrix to set the value to. |
|
* @param rowMajor |
|
* whether the incoming data is in row or column major order. |
|
*/ |
|
public void set(float[] matrix, boolean rowMajor) throws Exception { |
|
if (matrix.length != 9) |
|
throw new Exception("Array must be of size 9."); |
|
|
|
if (rowMajor) { |
|
m00 = matrix[0]; |
|
m01 = matrix[1]; |
|
m02 = matrix[2]; |
|
m10 = matrix[3]; |
|
m11 = matrix[4]; |
|
m12 = matrix[5]; |
|
m20 = matrix[6]; |
|
m21 = matrix[7]; |
|
m22 = matrix[8]; |
|
} else { |
|
m00 = matrix[0]; |
|
m01 = matrix[3]; |
|
m02 = matrix[6]; |
|
m10 = matrix[1]; |
|
m11 = matrix[4]; |
|
m12 = matrix[7]; |
|
m20 = matrix[2]; |
|
m21 = matrix[5]; |
|
m22 = matrix[8]; |
|
} |
|
} |
|
|
|
/** |
|
* |
|
* <code>set</code> defines the values of the matrix based on a supplied |
|
* <code>Quaternion</code>. It should be noted that all previous values will |
|
* be overridden. |
|
* |
|
* @param quaternion |
|
* the quaternion to create a rotational matrix from. |
|
*/ |
|
public void set(Quaternion quaternion) { |
|
quaternion.toRotationMatrix(this); |
|
} |
|
|
|
/** |
|
* <code>loadIdentity</code> sets this matrix to the identity matrix. Where |
|
* all values are zero except those along the diagonal which are one. |
|
* |
|
*/ |
|
public void loadIdentity() { |
|
m01 = m02 = m10 = m12 = m20 = m21 = 0; |
|
m00 = m11 = m22 = 1; |
|
} |
|
|
|
/** |
|
* @return true if this matrix is identity |
|
*/ |
|
public boolean isIdentity() { |
|
return (m00 == 1 && m01 == 0 && m02 == 0) |
|
&& (m10 == 0 && m11 == 1 && m12 == 0) |
|
&& (m20 == 0 && m21 == 0 && m22 == 1); |
|
} |
|
|
|
/** |
|
* <code>fromAngleAxis</code> sets this matrix4f to the values specified by |
|
* an angle and an axis of rotation. This method creates an object, so use |
|
* fromAngleNormalAxis if your axis is already normalized. |
|
* |
|
* @param angle |
|
* the angle to rotate (in radians). |
|
* @param axis |
|
* the axis of rotation. |
|
*/ |
|
public void fromAngleAxis(float angle, Vector3f axis) { |
|
Vector3f normAxis = axis.normalize(); |
|
fromAngleNormalAxis(angle, normAxis); |
|
} |
|
|
|
/** |
|
* <code>fromAngleNormalAxis</code> sets this matrix4f to the values |
|
* specified by an angle and a normalized axis of rotation. |
|
* |
|
* @param angle |
|
* the angle to rotate (in radians). |
|
* @param axis |
|
* the axis of rotation (already normalized). |
|
*/ |
|
public void fromAngleNormalAxis(float angle, Vector3f axis) { |
|
float fCos = FastMath.cos(angle); |
|
float fSin = FastMath.sin(angle); |
|
float fOneMinusCos = ((float) 1.0) - fCos; |
|
float fX2 = axis.x * axis.x; |
|
float fY2 = axis.y * axis.y; |
|
float fZ2 = axis.z * axis.z; |
|
float fXYM = axis.x * axis.y * fOneMinusCos; |
|
float fXZM = axis.x * axis.z * fOneMinusCos; |
|
float fYZM = axis.y * axis.z * fOneMinusCos; |
|
float fXSin = axis.x * fSin; |
|
float fYSin = axis.y * fSin; |
|
float fZSin = axis.z * fSin; |
|
|
|
m00 = fX2 * fOneMinusCos + fCos; |
|
m01 = fXYM - fZSin; |
|
m02 = fXZM + fYSin; |
|
m10 = fXYM + fZSin; |
|
m11 = fY2 * fOneMinusCos + fCos; |
|
m12 = fYZM - fXSin; |
|
m20 = fXZM - fYSin; |
|
m21 = fYZM + fXSin; |
|
m22 = fZ2 * fOneMinusCos + fCos; |
|
} |
|
|
|
/** |
|
* <code>mult</code> multiplies this matrix by a given matrix. The result |
|
* matrix is returned as a new object. If the given matrix is null, a null |
|
* matrix is returned. |
|
* |
|
* @param mat |
|
* the matrix to multiply this matrix by. |
|
* @return the result matrix. |
|
*/ |
|
public Matrix3f mult(Matrix3f mat) { |
|
return mult(mat, null); |
|
} |
|
|
|
/** |
|
* <code>mult</code> multiplies this matrix by a given matrix. The result |
|
* matrix is returned as a new object. |
|
* |
|
* @param mat |
|
* the matrix to multiply this matrix by. |
|
* @param product |
|
* the matrix to store the result in. if null, a new matrix3f is |
|
* created. It is safe for mat and product to be the same object. |
|
* @return a matrix3f object containing the result of this operation |
|
*/ |
|
public Matrix3f mult(Matrix3f mat, Matrix3f product) { |
|
|
|
float temp00, temp01, temp02; |
|
float temp10, temp11, temp12; |
|
float temp20, temp21, temp22; |
|
|
|
if (product == null) |
|
product = new Matrix3f(); |
|
temp00 = m00 * mat.m00 + m01 * mat.m10 + m02 * mat.m20; |
|
temp01 = m00 * mat.m01 + m01 * mat.m11 + m02 * mat.m21; |
|
temp02 = m00 * mat.m02 + m01 * mat.m12 + m02 * mat.m22; |
|
temp10 = m10 * mat.m00 + m11 * mat.m10 + m12 * mat.m20; |
|
temp11 = m10 * mat.m01 + m11 * mat.m11 + m12 * mat.m21; |
|
temp12 = m10 * mat.m02 + m11 * mat.m12 + m12 * mat.m22; |
|
temp20 = m20 * mat.m00 + m21 * mat.m10 + m22 * mat.m20; |
|
temp21 = m20 * mat.m01 + m21 * mat.m11 + m22 * mat.m21; |
|
temp22 = m20 * mat.m02 + m21 * mat.m12 + m22 * mat.m22; |
|
|
|
product.m00 = temp00; |
|
product.m01 = temp01; |
|
product.m02 = temp02; |
|
product.m10 = temp10; |
|
product.m11 = temp11; |
|
product.m12 = temp12; |
|
product.m20 = temp20; |
|
product.m21 = temp21; |
|
product.m22 = temp22; |
|
|
|
return product; |
|
} |
|
|
|
/** |
|
* <code>mult</code> multiplies this matrix by a given <code>Vector3f</code> |
|
* object. The result vector is returned. If the given vector is null, null |
|
* will be returned. |
|
* |
|
* @param vec |
|
* the vector to multiply this matrix by. |
|
* @return the result vector. |
|
*/ |
|
public Vector3f mult(Vector3f vec) { |
|
return mult(vec, null); |
|
} |
|
|
|
/** |
|
* Multiplies this 3x3 matrix by the 1x3 Vector vec and stores the result in |
|
* product. |
|
* |
|
* @param vec |
|
* The Vector3f to multiply. |
|
* @param product |
|
* The Vector3f to store the result, it is safe for this to be |
|
* the same as vec. |
|
* @return The given product vector. |
|
*/ |
|
public Vector3f mult(Vector3f vec, Vector3f product) { |
|
|
|
if (null == product) { |
|
product = new Vector3f(); |
|
} |
|
|
|
float x = vec.x; |
|
float y = vec.y; |
|
float z = vec.z; |
|
|
|
product.x = m00 * x + m01 * y + m02 * z; |
|
product.y = m10 * x + m11 * y + m12 * z; |
|
product.z = m20 * x + m21 * y + m22 * z; |
|
return product; |
|
} |
|
|
|
/** |
|
* <code>multLocal</code> multiplies this matrix internally by a given float |
|
* scale factor. |
|
* |
|
* @param scale |
|
* the value to scale by. |
|
* @return this Matrix3f |
|
*/ |
|
public Matrix3f multLocal(float scale) { |
|
m00 *= scale; |
|
m01 *= scale; |
|
m02 *= scale; |
|
m10 *= scale; |
|
m11 *= scale; |
|
m12 *= scale; |
|
m20 *= scale; |
|
m21 *= scale; |
|
m22 *= scale; |
|
return this; |
|
} |
|
|
|
/** |
|
* <code>multLocal</code> multiplies this matrix by a given |
|
* <code>Vector3f</code> object. The result vector is stored inside the |
|
* passed vector, then returned . If the given vector is null, null will be |
|
* returned. |
|
* |
|
* @param vec |
|
* the vector to multiply this matrix by. |
|
* @return The passed vector after multiplication |
|
*/ |
|
public Vector3f multLocal(Vector3f vec) { |
|
if (vec == null) |
|
return null; |
|
float x = vec.x; |
|
float y = vec.y; |
|
vec.x = m00 * x + m01 * y + m02 * vec.z; |
|
vec.y = m10 * x + m11 * y + m12 * vec.z; |
|
vec.z = m20 * x + m21 * y + m22 * vec.z; |
|
return vec; |
|
} |
|
|
|
/** |
|
* <code>mult</code> multiplies this matrix by a given matrix. The result |
|
* matrix is saved in the current matrix. If the given matrix is null, |
|
* nothing happens. The current matrix is returned. This is equivalent to |
|
* this*=mat |
|
* |
|
* @param mat |
|
* the matrix to multiply this matrix by. |
|
* @return This matrix, after the multiplication |
|
*/ |
|
public Matrix3f multLocal(Matrix3f mat) { |
|
|
|
return mult(mat, this); |
|
} |
|
|
|
/** |
|
* Transposes this matrix in place. Returns this matrix for chaining |
|
* |
|
* @return This matrix after transpose |
|
* @throws Exception |
|
*/ |
|
public Matrix3f transposeLocal() throws Exception { |
|
float[] tmp = new float[9]; |
|
get(tmp, false); |
|
set(tmp, true); |
|
return this; |
|
} |
|
|
|
/** |
|
* Inverts this matrix as a new Matrix3f. |
|
* |
|
* @return The new inverse matrix |
|
*/ |
|
public Matrix3f invert() { |
|
return invert(null); |
|
} |
|
|
|
/** |
|
* Inverts this matrix and stores it in the given store. |
|
* |
|
* @return The store |
|
*/ |
|
public Matrix3f invert(Matrix3f store) { |
|
if (store == null) |
|
store = new Matrix3f(); |
|
|
|
float det = determinant(); |
|
if (FastMath.abs(det) <= 0) |
|
return store.zero(); |
|
|
|
store.m00 = m11 * m22 - m12 * m21; |
|
store.m01 = m02 * m21 - m01 * m22; |
|
store.m02 = m01 * m12 - m02 * m11; |
|
store.m10 = m12 * m20 - m10 * m22; |
|
store.m11 = m00 * m22 - m02 * m20; |
|
store.m12 = m02 * m10 - m00 * m12; |
|
store.m20 = m10 * m21 - m11 * m20; |
|
store.m21 = m01 * m20 - m00 * m21; |
|
store.m22 = m00 * m11 - m01 * m10; |
|
|
|
store.multLocal(1f / det); |
|
return store; |
|
} |
|
|
|
/** |
|
* Inverts this matrix locally. |
|
* |
|
* @return this |
|
*/ |
|
public Matrix3f invertLocal() { |
|
float det = determinant(); |
|
if (FastMath.abs(det) <= FastMath.FLT_EPSILON) |
|
return zero(); |
|
|
|
float f00 = m11 * m22 - m12 * m21; |
|
float f01 = m02 * m21 - m01 * m22; |
|
float f02 = m01 * m12 - m02 * m11; |
|
float f10 = m12 * m20 - m10 * m22; |
|
float f11 = m00 * m22 - m02 * m20; |
|
float f12 = m02 * m10 - m00 * m12; |
|
float f20 = m10 * m21 - m11 * m20; |
|
float f21 = m01 * m20 - m00 * m21; |
|
float f22 = m00 * m11 - m01 * m10; |
|
|
|
m00 = f00; |
|
m01 = f01; |
|
m02 = f02; |
|
m10 = f10; |
|
m11 = f11; |
|
m12 = f12; |
|
m20 = f20; |
|
m21 = f21; |
|
m22 = f22; |
|
|
|
multLocal(1f / det); |
|
return this; |
|
} |
|
|
|
/** |
|
* Returns a new matrix representing the adjoint of this matrix. |
|
* |
|
* @return The adjoint matrix |
|
*/ |
|
public Matrix3f adjoint() { |
|
return adjoint(null); |
|
} |
|
|
|
/** |
|
* Places the adjoint of this matrix in store (creates store if null.) |
|
* |
|
* @param store |
|
* The matrix to store the result in. If null, a new matrix is |
|
* created. |
|
* @return store |
|
*/ |
|
public Matrix3f adjoint(Matrix3f store) { |
|
if (store == null) |
|
store = new Matrix3f(); |
|
|
|
store.m00 = m11 * m22 - m12 * m21; |
|
store.m01 = m02 * m21 - m01 * m22; |
|
store.m02 = m01 * m12 - m02 * m11; |
|
store.m10 = m12 * m20 - m10 * m22; |
|
store.m11 = m00 * m22 - m02 * m20; |
|
store.m12 = m02 * m10 - m00 * m12; |
|
store.m20 = m10 * m21 - m11 * m20; |
|
store.m21 = m01 * m20 - m00 * m21; |
|
store.m22 = m00 * m11 - m01 * m10; |
|
|
|
return store; |
|
} |
|
|
|
/** |
|
* <code>determinant</code> generates the determinate of this matrix. |
|
* |
|
* @return the determinate |
|
*/ |
|
public float determinant() { |
|
float fCo00 = m11 * m22 - m12 * m21; |
|
float fCo10 = m12 * m20 - m10 * m22; |
|
float fCo20 = m10 * m21 - m11 * m20; |
|
return m00 * fCo00 + m01 * fCo10 + m02 * fCo20; |
|
} |
|
|
|
/** |
|
* Sets all of the values in this matrix to zero. |
|
* |
|
* @return this matrix |
|
*/ |
|
public Matrix3f zero() { |
|
m00 = m01 = m02 = m10 = m11 = m12 = m20 = m21 = m22 = 0.0f; |
|
return this; |
|
} |
|
|
|
/** |
|
* <code>add</code> adds the values of a parameter matrix to this matrix. |
|
* |
|
* @param mat |
|
* the matrix to add to this. |
|
*/ |
|
public void add(Matrix3f mat) { |
|
m00 += mat.m00; |
|
m01 += mat.m01; |
|
m02 += mat.m02; |
|
m10 += mat.m10; |
|
m11 += mat.m11; |
|
m12 += mat.m12; |
|
m20 += mat.m20; |
|
m21 += mat.m21; |
|
m22 += mat.m22; |
|
} |
|
|
|
/** |
|
* <code>transpose</code> <b>locally</b> transposes this Matrix. This is |
|
* inconsistent with general value vs local semantics, but is preserved for |
|
* backwards compatibility. Use transposeNew() to transpose to a new object |
|
* (value). |
|
* |
|
* @return this object for chaining. |
|
* @throws Exception |
|
*/ |
|
public Matrix3f transpose() throws Exception { |
|
return transposeLocal(); |
|
} |
|
|
|
/** |
|
* <code>transposeNew</code> returns a transposed version of this matrix. |
|
* |
|
* @return The new Matrix3f object. |
|
*/ |
|
public Matrix3f transposeNew() { |
|
return new Matrix3f(m00, m10, m20, m01, m11, m21, m02, m12, m22); |
|
} |
|
|
|
/** |
|
* <code>toString</code> returns the string representation of this object. |
|
* It is in a format of a 3x3 matrix. For example, an identity matrix would |
|
* be represented by the following string. com.jme.math.Matrix3f <br> |
|
* [<br> |
|
* 1.0 0.0 0.0 <br> |
|
* 0.0 1.0 0.0 <br> |
|
* 0.0 0.0 1.0 <br> |
|
* ]<br> |
|
* |
|
* @return the string representation of this object. |
|
*/ |
|
@Override |
|
public String toString() { |
|
StringBuffer result = new StringBuffer("com.jme.math.Matrix3f\n[\n"); |
|
result.append(' '); |
|
result.append(m00); |
|
result.append(" "); |
|
result.append(m01); |
|
result.append(" "); |
|
result.append(m02); |
|
result.append(" \n"); |
|
result.append(' '); |
|
result.append(m10); |
|
result.append(" "); |
|
result.append(m11); |
|
result.append(" "); |
|
result.append(m12); |
|
result.append(" \n"); |
|
result.append(' '); |
|
result.append(m20); |
|
result.append(" "); |
|
result.append(m21); |
|
result.append(" "); |
|
result.append(m22); |
|
result.append(" \n]"); |
|
return result.toString(); |
|
} |
|
|
|
/** |
|
* |
|
* <code>hashCode</code> returns the hash code value as an integer and is |
|
* supported for the benefit of hashing based collection classes such as |
|
* Hashtable, HashMap, HashSet etc. |
|
* |
|
* @return the hashcode for this instance of Matrix4f. |
|
* @see java.lang.Object#hashCode() |
|
*/ |
|
@Override |
|
public int hashCode() { |
|
int hash = 37; |
|
hash = 37 * hash + Float.floatToIntBits(m00); |
|
hash = 37 * hash + Float.floatToIntBits(m01); |
|
hash = 37 * hash + Float.floatToIntBits(m02); |
|
|
|
hash = 37 * hash + Float.floatToIntBits(m10); |
|
hash = 37 * hash + Float.floatToIntBits(m11); |
|
hash = 37 * hash + Float.floatToIntBits(m12); |
|
|
|
hash = 37 * hash + Float.floatToIntBits(m20); |
|
hash = 37 * hash + Float.floatToIntBits(m21); |
|
hash = 37 * hash + Float.floatToIntBits(m22); |
|
|
|
return hash; |
|
} |
|
|
|
/** |
|
* are these two matrices the same? they are is they both have the same mXX |
|
* values. |
|
* |
|
* @param o |
|
* the object to compare for equality |
|
* @return true if they are equal |
|
*/ |
|
@Override |
|
public boolean equals(Object o) { |
|
if (!(o instanceof Matrix3f) || o == null) { |
|
return false; |
|
} |
|
|
|
if (this == o) { |
|
return true; |
|
} |
|
|
|
Matrix3f comp = (Matrix3f) o; |
|
if (Float.compare(m00, comp.m00) != 0) |
|
return false; |
|
if (Float.compare(m01, comp.m01) != 0) |
|
return false; |
|
if (Float.compare(m02, comp.m02) != 0) |
|
return false; |
|
|
|
if (Float.compare(m10, comp.m10) != 0) |
|
return false; |
|
if (Float.compare(m11, comp.m11) != 0) |
|
return false; |
|
if (Float.compare(m12, comp.m12) != 0) |
|
return false; |
|
|
|
if (Float.compare(m20, comp.m20) != 0) |
|
return false; |
|
if (Float.compare(m21, comp.m21) != 0) |
|
return false; |
|
return Float.compare(m22, comp.m22) == 0; |
|
} |
|
|
|
/** |
|
* A function for creating a rotation matrix that rotates a vector called |
|
* "start" into another vector called "end". |
|
* |
|
* @param start |
|
* normalized non-zero starting vector |
|
* @param end |
|
* normalized non-zero ending vector |
|
* @throws Exception |
|
* @see "Tomas Miller, John Hughes \"Efficiently Building a Matrix to Rotate |
|
* \ One Vector to Another\" Journal of Graphics Tools, 4(4):1-4, 1999" |
|
*/ |
|
public void fromStartEndVectors(Vector3f start, Vector3f end) |
|
throws Exception { |
|
Vector3f v = new Vector3f(); |
|
float e, h, f; |
|
|
|
start.cross(end, v); |
|
e = start.dot(end); |
|
f = (e < 0) ? -e : e; |
|
|
|
// if "from" and "to" vectors are nearly parallel |
|
if (f > 1.0f - FastMath.ZERO_TOLERANCE) { |
|
Vector3f u = new Vector3f(); |
|
Vector3f x = new Vector3f(); |
|
float c1, c2, c3; /* coefficients for later use */ |
|
int i, j; |
|
|
|
x.x = (start.x > 0.0) ? start.x : -start.x; |
|
x.y = (start.y > 0.0) ? start.y : -start.y; |
|
x.z = (start.z > 0.0) ? start.z : -start.z; |
|
|
|
if (x.x < x.y) { |
|
if (x.x < x.z) { |
|
x.x = 1.0f; |
|
x.y = x.z = 0.0f; |
|
} else { |
|
x.z = 1.0f; |
|
x.x = x.y = 0.0f; |
|
} |
|
} else { |
|
if (x.y < x.z) { |
|
x.y = 1.0f; |
|
x.x = x.z = 0.0f; |
|
} else { |
|
x.z = 1.0f; |
|
x.x = x.y = 0.0f; |
|
} |
|
} |
|
|
|
u.x = x.x - start.x; |
|
u.y = x.y - start.y; |
|
u.z = x.z - start.z; |
|
v.x = x.x - end.x; |
|
v.y = x.y - end.y; |
|
v.z = x.z - end.z; |
|
|
|
c1 = 2.0f / u.dot(u); |
|
c2 = 2.0f / v.dot(v); |
|
c3 = c1 * c2 * u.dot(v); |
|
|
|
for (i = 0; i < 3; i++) { |
|
for (j = 0; j < 3; j++) { |
|
float val = -c1 * u.get(i) * u.get(j) - c2 * v.get(i) |
|
* v.get(j) + c3 * v.get(i) * u.get(j); |
|
set(i, j, val); |
|
} |
|
float val = get(i, i); |
|
set(i, i, val + 1.0f); |
|
} |
|
} else { |
|
// the most common case, unless "start"="end", or "start"=-"end" |
|
float hvx, hvz, hvxy, hvxz, hvyz; |
|
h = 1.0f / (1.0f + e); |
|
hvx = h * v.x; |
|
hvz = h * v.z; |
|
hvxy = hvx * v.y; |
|
hvxz = hvx * v.z; |
|
hvyz = hvz * v.y; |
|
set(0, 0, e + hvx * v.x); |
|
set(0, 1, hvxy - v.z); |
|
set(0, 2, hvxz + v.y); |
|
|
|
set(1, 0, hvxy + v.z); |
|
set(1, 1, e + h * v.y * v.y); |
|
set(1, 2, hvyz - v.x); |
|
|
|
set(2, 0, hvxz - v.y); |
|
set(2, 1, hvyz + v.x); |
|
set(2, 2, e + hvz * v.z); |
|
} |
|
} |
|
|
|
/** |
|
* <code>scale</code> scales the operation performed by this matrix on a |
|
* per-component basis. |
|
* |
|
* @param scale |
|
* The scale applied to each of the X, Y and Z output values. |
|
*/ |
|
public void scale(Vector3f scale) { |
|
m00 *= scale.x; |
|
m10 *= scale.x; |
|
m20 *= scale.x; |
|
m01 *= scale.y; |
|
m11 *= scale.y; |
|
m21 *= scale.y; |
|
m02 *= scale.z; |
|
m12 *= scale.z; |
|
m22 *= scale.z; |
|
} |
|
|
|
static boolean equalIdentity(Matrix3f mat) { |
|
if (Math.abs(mat.m00 - 1) > 1e-4) |
|
return false; |
|
if (Math.abs(mat.m11 - 1) > 1e-4) |
|
return false; |
|
if (Math.abs(mat.m22 - 1) > 1e-4) |
|
return false; |
|
|
|
if (Math.abs(mat.m01) > 1e-4) |
|
return false; |
|
if (Math.abs(mat.m02) > 1e-4) |
|
return false; |
|
|
|
if (Math.abs(mat.m10) > 1e-4) |
|
return false; |
|
if (Math.abs(mat.m12) > 1e-4) |
|
return false; |
|
|
|
if (Math.abs(mat.m20) > 1e-4) |
|
return false; |
|
return !(Math.abs(mat.m21) > 1e-4); |
|
} |
|
|
|
@Override |
|
public Matrix3f clone() { |
|
try { |
|
return (Matrix3f) super.clone(); |
|
} catch (CloneNotSupportedException e) { |
|
Logger.error( e); |
|
throw new AssertionError(); // can not happen |
|
} |
|
} |
|
} |