package com.team.futurecraft;
import java.nio.FloatBuffer;
import org.lwjgl.BufferUtils;
/**
* This class represents a 4x4-Matrix. GLSL equivalent to mat4.
*
* @author Heiko Brumme
*/
public class Mat4f {
public float m00, m01, m02, m03;
public float m10, m11, m12, m13;
public float m20, m21, m22, m23;
public float m30, m31, m32, m33;
/**
* Creates a 4x4 identity matrix.
*/
public Mat4f() {
setIdentity();
}
/**
* Creates a 4x4 matrix with specified columns.
*
* @param col1 Vector with values of the first column
* @param col2 Vector with values of the second column
* @param col3 Vector with values of the third column
* @param col4 Vector with values of the fourth column
*/
public Mat4f(Vec4f col1, Vec4f col2, Vec4f col3, Vec4f col4) {
m00 = col1.x;
m10 = col1.y;
m20 = col1.z;
m30 = col1.w;
m01 = col2.x;
m11 = col2.y;
m21 = col2.z;
m31 = col2.w;
m02 = col3.x;
m12 = col3.y;
m22 = col3.z;
m32 = col3.w;
m03 = col4.x;
m13 = col4.y;
m23 = col4.z;
m33 = col4.w;
}
/**
* Sets this matrix to the identity matrix.
*/
public final void setIdentity() {
m00 = 1f;
m11 = 1f;
m22 = 1f;
m33 = 1f;
m01 = 0f;
m02 = 0f;
m03 = 0f;
m10 = 0f;
m12 = 0f;
m13 = 0f;
m20 = 0f;
m21 = 0f;
m23 = 0f;
m30 = 0f;
m31 = 0f;
m32 = 0f;
}
/**
* Adds this matrix to another matrix.
*
* @param other The other matrix
* @return Sum of this + other
*/
public Mat4f add(Mat4f other) {
Mat4f result = new Mat4f();
result.m00 = this.m00 + other.m00;
result.m10 = this.m10 + other.m10;
result.m20 = this.m20 + other.m20;
result.m30 = this.m30 + other.m30;
result.m01 = this.m01 + other.m01;
result.m11 = this.m11 + other.m11;
result.m21 = this.m21 + other.m21;
result.m31 = this.m31 + other.m31;
result.m02 = this.m02 + other.m02;
result.m12 = this.m12 + other.m12;
result.m22 = this.m22 + other.m22;
result.m32 = this.m32 + other.m32;
result.m03 = this.m03 + other.m03;
result.m13 = this.m13 + other.m13;
result.m23 = this.m23 + other.m23;
result.m33 = this.m33 + other.m33;
return result;
}
/**
* Negates this matrix.
*
* @return Negated matrix
*/
public Mat4f negate() {
return multiply(-1f);
}
/**
* Subtracts this matrix from another matrix.
*
* @param other The other matrix
* @return Difference of this - other
*/
public Mat4f subtract(Mat4f other) {
return this.add(other.negate());
}
/**
* Multiplies this matrix with a scalar.
*
* @param scalar The scalar
* @return Scalar product of this * scalar
*/
public Mat4f multiply(float scalar) {
Mat4f result = new Mat4f();
result.m00 = this.m00 * scalar;
result.m10 = this.m10 * scalar;
result.m20 = this.m20 * scalar;
result.m30 = this.m30 * scalar;
result.m01 = this.m01 * scalar;
result.m11 = this.m11 * scalar;
result.m21 = this.m21 * scalar;
result.m31 = this.m31 * scalar;
result.m02 = this.m02 * scalar;
result.m12 = this.m12 * scalar;
result.m22 = this.m22 * scalar;
result.m32 = this.m32 * scalar;
result.m03 = this.m03 * scalar;
result.m13 = this.m13 * scalar;
result.m23 = this.m23 * scalar;
result.m33 = this.m33 * scalar;
return result;
}
/**
* Multiplies this matrix to a vector.
*
* @param vector The vector
* @return Vector product of this * other
*/
public Vec4f multiply(Vec4f vector) {
float x = this.m00 * vector.x + this.m01 * vector.y + this.m02 * vector.z + this.m03 * vector.w;
float y = this.m10 * vector.x + this.m11 * vector.y + this.m12 * vector.z + this.m13 * vector.w;
float z = this.m20 * vector.x + this.m21 * vector.y + this.m22 * vector.z + this.m23 * vector.w;
float w = this.m30 * vector.x + this.m31 * vector.y + this.m32 * vector.z + this.m33 * vector.w;
return new Vec4f(x, y, z, w);
}
/**
* Multiplies this matrix to another matrix.
*
* @param other The other matrix
* @return Matrix product of this * other
*/
public Mat4f multiply(Mat4f other) {
Mat4f result = new Mat4f();
result.m00 = this.m00 * other.m00 + this.m01 * other.m10 + this.m02 * other.m20 + this.m03 * other.m30;
result.m10 = this.m10 * other.m00 + this.m11 * other.m10 + this.m12 * other.m20 + this.m13 * other.m30;
result.m20 = this.m20 * other.m00 + this.m21 * other.m10 + this.m22 * other.m20 + this.m23 * other.m30;
result.m30 = this.m30 * other.m00 + this.m31 * other.m10 + this.m32 * other.m20 + this.m33 * other.m30;
result.m01 = this.m00 * other.m01 + this.m01 * other.m11 + this.m02 * other.m21 + this.m03 * other.m31;
result.m11 = this.m10 * other.m01 + this.m11 * other.m11 + this.m12 * other.m21 + this.m13 * other.m31;
result.m21 = this.m20 * other.m01 + this.m21 * other.m11 + this.m22 * other.m21 + this.m23 * other.m31;
result.m31 = this.m30 * other.m01 + this.m31 * other.m11 + this.m32 * other.m21 + this.m33 * other.m31;
result.m02 = this.m00 * other.m02 + this.m01 * other.m12 + this.m02 * other.m22 + this.m03 * other.m32;
result.m12 = this.m10 * other.m02 + this.m11 * other.m12 + this.m12 * other.m22 + this.m13 * other.m32;
result.m22 = this.m20 * other.m02 + this.m21 * other.m12 + this.m22 * other.m22 + this.m23 * other.m32;
result.m32 = this.m30 * other.m02 + this.m31 * other.m12 + this.m32 * other.m22 + this.m33 * other.m32;
result.m03 = this.m00 * other.m03 + this.m01 * other.m13 + this.m02 * other.m23 + this.m03 * other.m33;
result.m13 = this.m10 * other.m03 + this.m11 * other.m13 + this.m12 * other.m23 + this.m13 * other.m33;
result.m23 = this.m20 * other.m03 + this.m21 * other.m13 + this.m22 * other.m23 + this.m23 * other.m33;
result.m33 = this.m30 * other.m03 + this.m31 * other.m13 + this.m32 * other.m23 + this.m33 * other.m33;
return result;
}
/**
* Transposes this matrix.
*
* @return Transposed matrix
*/
public Mat4f transpose() {
Mat4f result = new Mat4f();
result.m00 = this.m00;
result.m10 = this.m01;
result.m20 = this.m02;
result.m30 = this.m03;
result.m01 = this.m10;
result.m11 = this.m11;
result.m21 = this.m12;
result.m31 = this.m13;
result.m02 = this.m20;
result.m12 = this.m21;
result.m22 = this.m22;
result.m32 = this.m23;
result.m03 = this.m30;
result.m13 = this.m31;
result.m23 = this.m32;
result.m33 = this.m33;
return result;
}
public static Mat4f LookAt(Vec3f eye, Vec3f center, Vec3f up) {
Vec3f forward = new Vec3f(0, 0, -1);
Vec3f upVec = new Vec3f(0, 1, 0);
Vec3f side = new Vec3f(1, 0, 0);
forward.x = center.x - eye.x;
forward.y = center.y - eye.y;
forward.z = center.z - eye.z;
upVec.x = up.x;
upVec.y = up.y;
upVec.z = up.z;
forward = forward.normalize();
/* Side = forward x up */
side = forward.cross(upVec);
side = side.normalize();
/* Recompute up as: up = side x forward */
upVec = side.cross(forward);
Mat4f mat = new Mat4f();
mat.m00 = side.x;
mat.m01 = side.y;
mat.m02 = side.z;
mat.m10 = upVec.x;
mat.m11 = upVec.y;
mat.m12 = upVec.z;
mat.m20 = -forward.x;
mat.m21 = -forward.y;
mat.m22 = -forward.z;
return mat.multiply(Mat4f.translate(-eye.x, -eye.y, -eye.z));
}
/**
* Returns the Buffer representation of this vector.
*
* @return Vector as FloatBuffer
*/
public FloatBuffer getBuffer() {
FloatBuffer buffer = BufferUtils.createFloatBuffer(16);
buffer.put(m00).put(m10).put(m20).put(m30);
buffer.put(m01).put(m11).put(m21).put(m31);
buffer.put(m02).put(m12).put(m22).put(m32);
buffer.put(m03).put(m13).put(m23).put(m33);
buffer.flip();
return buffer;
}
/**
* Creates a orthographic projection matrix. Similar to
* <code>glOrtho(left, right, bottom, top, near, far)</code>.
*
* @param left Coordinate for the left vertical clipping pane
* @param right Coordinate for the right vertical clipping pane
* @param bottom Coordinate for the bottom horizontal clipping pane
* @param top Coordinate for the bottom horizontal clipping pane
* @param near Coordinate for the near depth clipping pane
* @param far Coordinate for the far depth clipping pane
* @return Orthographic matrix
*/
public static Mat4f orthographic(float left, float right, float bottom, float top, float near, float far) {
Mat4f ortho = new Mat4f();
float tx = -(right + left) / (right - left);
float ty = -(top + bottom) / (top - bottom);
float tz = -(far + near) / (far - near);
ortho.m00 = 2f / (right - left);
ortho.m11 = 2f / (top - bottom);
ortho.m22 = -2f / (far - near);
ortho.m03 = tx;
ortho.m13 = ty;
ortho.m23 = tz;
return ortho;
}
/**
* Creates a perspective projection matrix. Similar to
* <code>glFrustum(left, right, bottom, top, near, far)</code>.
*
* @param left Coordinate for the left vertical clipping pane
* @param right Coordinate for the right vertical clipping pane
* @param bottom Coordinate for the bottom horizontal clipping pane
* @param top Coordinate for the bottom horizontal clipping pane
* @param near Coordinate for the near depth clipping pane, must be positive
* @param far Coordinate for the far depth clipping pane, must be positive
* @return Perspective matrix
*/
public static Mat4f frustum(float left, float right, float bottom, float top, float near, float far) {
Mat4f frustum = new Mat4f();
float a = (right + left) / (right - left);
float b = (top + bottom) / (top - bottom);
float c = -(far + near) / (far - near);
float d = -(2f * far * near) / (far - near);
frustum.m00 = (2f * near) / (right - left);
frustum.m11 = (2f * near) / (top - bottom);
frustum.m02 = a;
frustum.m12 = b;
frustum.m22 = c;
frustum.m32 = -1f;
frustum.m23 = d;
frustum.m33 = 0f;
return frustum;
}
/**
* Creates a perspective projection matrix. Similar to
* <code>gluPerspective(fovy, aspec, zNear, zFar)</code>.
*
* @param fovy Field of view angle in degrees
* @param aspect The aspect ratio is the ratio of width to height
* @param near Distance from the viewer to the near clipping plane, must be
* positive
* @param far Distance from the viewer to the far clipping plane, must be
* positive
* @return Perspective matrix
*/
public static Mat4f perspective(float fovy, float aspect, float near, float far) {
Mat4f perspective = new Mat4f();
float f = (float) (1f / Math.tan(Math.toRadians(fovy) / 2f));
perspective.m00 = f / aspect;
perspective.m11 = f;
perspective.m22 = (far + near) / (near - far);
perspective.m32 = -1f;
perspective.m23 = (2f * far * near) / (near - far);
perspective.m33 = 0f;
return perspective;
}
/**
* Creates a translation matrix. Similar to
* <code>glTranslate(x, y, z)</code>.
*
* @param x x coordinate of translation vector
* @param y y coordinate of translation vector
* @param z z coordinate of translation vector
* @return Translation matrix
*/
public static Mat4f translate(float x, float y, float z) {
Mat4f translation = new Mat4f();
translation.m03 = x;
translation.m13 = y;
translation.m23 = z;
return translation;
}
/**
* Creates a rotation matrix. Similar to
* <code>glRotate(angle, x, y, z)</code>.
*
* @param angle Angle of rotation in degrees
* @param x x coordinate of the rotation vector
* @param y y coordinate of the rotation vector
* @param z z coordinate of the rotation vector
* @return Rotation matrix
*/
public static Mat4f rotate(float angle, float x, float y, float z) {
Mat4f rotation = new Mat4f();
float c = (float) Math.cos(Math.toRadians(angle));
float s = (float) Math.sin(Math.toRadians(angle));
Vec3f vec = new Vec3f(x, y, z);
if (vec.length() != 1f) {
vec = vec.normalize();
x = vec.x;
y = vec.y;
z = vec.z;
}
rotation.m00 = x * x * (1f - c) + c;
rotation.m10 = y * x * (1f - c) + z * s;
rotation.m20 = x * z * (1f - c) - y * s;
rotation.m01 = x * y * (1f - c) - z * s;
rotation.m11 = y * y * (1f - c) + c;
rotation.m21 = y * z * (1f - c) + x * s;
rotation.m02 = x * z * (1f - c) + y * s;
rotation.m12 = y * z * (1f - c) - x * s;
rotation.m22 = z * z * (1f - c) + c;
return rotation;
}
/**
* Creates a scaling matrix. Similar to <code>glScale(x, y, z)</code>.
*
* @param x Scale factor along the x coordinate
* @param y Scale factor along the y coordinate
* @param z Scale factor along the z coordinate
* @return Scaling matrix
*/
public static Mat4f scale(float x, float y, float z) {
Mat4f scaling = new Mat4f();
scaling.m00 = x;
scaling.m11 = y;
scaling.m22 = z;
return scaling;
}
private static float determinant3x3(float t00, float t01, float t02, float t10, float t11, float t12, float t20, float t21, float t22) {
return t00 * (t11 * t22 - t12 * t21) + t01 * (t12 * t20 - t10 * t22) + t02 * (t10 * t21 - t11 * t20);
}
public float determinant() {
float f =
m00
* ((m11 * m22 * m33 + m12 * m23 * m31 + m13 * m21 * m32)
- m13 * m22 * m31
- m11 * m23 * m32
- m12 * m21 * m33);
f -= m01
* ((m10 * m22 * m33 + m12 * m23 * m30 + m13 * m20 * m32)
- m13 * m22 * m30
- m10 * m23 * m32
- m12 * m20 * m33);
f += m02
* ((m10 * m21 * m33 + m11 * m23 * m30 + m13 * m20 * m31)
- m13 * m21 * m30
- m10 * m23 * m31
- m11 * m20 * m33);
f -= m03
* ((m10 * m21 * m32 + m11 * m22 * m30 + m12 * m20 * m31)
- m12 * m21 * m30
- m10 * m22 * m31
- m11 * m20 * m32);
return f;
}
public Mat4f inverse() {
Mat4f src = this;
Mat4f dest = new Mat4f();
float determinant = src.determinant();
if (determinant != 0) {
/*
* m00 m01 m02 m03
* m10 m11 m12 m13
* m20 m21 m22 m23
* m30 m31 m32 m33
*/
float determinant_inv = 1f/determinant;
// first row
float t00 = determinant3x3(src.m11, src.m12, src.m13, src.m21, src.m22, src.m23, src.m31, src.m32, src.m33);
float t01 = -determinant3x3(src.m10, src.m12, src.m13, src.m20, src.m22, src.m23, src.m30, src.m32, src.m33);
float t02 = determinant3x3(src.m10, src.m11, src.m13, src.m20, src.m21, src.m23, src.m30, src.m31, src.m33);
float t03 = -determinant3x3(src.m10, src.m11, src.m12, src.m20, src.m21, src.m22, src.m30, src.m31, src.m32);
// second row
float t10 = -determinant3x3(src.m01, src.m02, src.m03, src.m21, src.m22, src.m23, src.m31, src.m32, src.m33);
float t11 = determinant3x3(src.m00, src.m02, src.m03, src.m20, src.m22, src.m23, src.m30, src.m32, src.m33);
float t12 = -determinant3x3(src.m00, src.m01, src.m03, src.m20, src.m21, src.m23, src.m30, src.m31, src.m33);
float t13 = determinant3x3(src.m00, src.m01, src.m02, src.m20, src.m21, src.m22, src.m30, src.m31, src.m32);
// third row
float t20 = determinant3x3(src.m01, src.m02, src.m03, src.m11, src.m12, src.m13, src.m31, src.m32, src.m33);
float t21 = -determinant3x3(src.m00, src.m02, src.m03, src.m10, src.m12, src.m13, src.m30, src.m32, src.m33);
float t22 = determinant3x3(src.m00, src.m01, src.m03, src.m10, src.m11, src.m13, src.m30, src.m31, src.m33);
float t23 = -determinant3x3(src.m00, src.m01, src.m02, src.m10, src.m11, src.m12, src.m30, src.m31, src.m32);
// fourth row
float t30 = -determinant3x3(src.m01, src.m02, src.m03, src.m11, src.m12, src.m13, src.m21, src.m22, src.m23);
float t31 = determinant3x3(src.m00, src.m02, src.m03, src.m10, src.m12, src.m13, src.m20, src.m22, src.m23);
float t32 = -determinant3x3(src.m00, src.m01, src.m03, src.m10, src.m11, src.m13, src.m20, src.m21, src.m23);
float t33 = determinant3x3(src.m00, src.m01, src.m02, src.m10, src.m11, src.m12, src.m20, src.m21, src.m22);
// transpose and divide by the determinant
dest.m00 = t00*determinant_inv;
dest.m11 = t11*determinant_inv;
dest.m22 = t22*determinant_inv;
dest.m33 = t33*determinant_inv;
dest.m01 = t10*determinant_inv;
dest.m10 = t01*determinant_inv;
dest.m20 = t02*determinant_inv;
dest.m02 = t20*determinant_inv;
dest.m12 = t21*determinant_inv;
dest.m21 = t12*determinant_inv;
dest.m03 = t30*determinant_inv;
dest.m30 = t03*determinant_inv;
dest.m13 = t31*determinant_inv;
dest.m31 = t13*determinant_inv;
dest.m32 = t23*determinant_inv;
dest.m23 = t32*determinant_inv;
return dest;
} else
return null;
}
}