/** * Copyright 2012 Jason Sorensen (sorensenj@smert.net) * * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on * an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the * specific language governing permissions and limitations under the License. */ package net.smert.frameworkgl.math; import java.nio.FloatBuffer; /** * * @author Jason Sorensen <sorensenj@smert.net> */ public class Matrix4f { /** * Layout of the matrix as follows: * * Column 1 | Column 2 | Column 3 | Column 4 * * d0 | d4 | d8 | d12 * * d1 | d5 | d9 | d13 * * d2 | d6 | d10 | d14 * * d3 | d7 | d11 | d15 */ float d0; float d1; float d2; float d3; float d4; float d5; float d6; float d7; float d8; float d9; float d10; float d11; float d12; float d13; float d14; float d15; // Constructors public Matrix4f() { identity(); } public Matrix4f(Matrix4f matrix) { set(matrix); } // Conversion Operations public void extractPlanes( Vector4f nearPlane, Vector4f farPlane, Vector4f leftPlane, Vector4f rightPlane, Vector4f bottomPlane, Vector4f topPlane) { // Near Plane (row 2 + row 3) nearPlane.x = d2 + d3; nearPlane.y = d6 + d7; nearPlane.z = d10 + d11; nearPlane.w = d14 + d15; // Far Plane (row 3 - row 2) farPlane.x = d3 - d2; farPlane.y = d7 - d6; farPlane.z = d11 - d10; farPlane.w = d15 - d14; // Left Plane (row 0 + row 3) leftPlane.x = d0 + d3; leftPlane.y = d4 + d7; leftPlane.z = d8 + d11; leftPlane.w = d12 + d15; // Right Plane (row 3 - row 0) rightPlane.x = d3 - d0; rightPlane.y = d7 - d4; rightPlane.z = d11 - d8; rightPlane.w = d15 - d12; // Bottom Plane (row 1 + row 3) bottomPlane.x = d1 + d3; bottomPlane.y = d5 + d7; bottomPlane.z = d9 + d11; bottomPlane.w = d13 + d15; // Top Plane (row 3 - row 1) topPlane.x = d3 - d1; topPlane.y = d7 - d5; topPlane.z = d11 - d9; topPlane.w = d15 - d13; nearPlane.normalize(); farPlane.normalize(); leftPlane.normalize(); rightPlane.normalize(); bottomPlane.normalize(); topPlane.normalize(); } public void extractPlanes(ClipPlanes clipPlanes) { // Near Plane (row 2 + row 3) clipPlanes.npX = d2 + d3; clipPlanes.npY = d6 + d7; clipPlanes.npZ = d10 + d11; clipPlanes.npW = d14 + d15; // Far Plane (row 3 - row 2) clipPlanes.fpX = d3 - d2; clipPlanes.fpY = d7 - d6; clipPlanes.fpZ = d11 - d10; clipPlanes.fpW = d15 - d14; // Left Plane (row 0 + row 3) clipPlanes.lpX = d0 + d3; clipPlanes.lpY = d4 + d7; clipPlanes.lpZ = d8 + d11; clipPlanes.lpW = d12 + d15; // Right Plane (row 3 - row 0) clipPlanes.rpX = d3 - d0; clipPlanes.rpY = d7 - d4; clipPlanes.rpZ = d11 - d8; clipPlanes.rpW = d15 - d12; // Bottom Plane (row 1 + row 3) clipPlanes.bpX = d1 + d3; clipPlanes.bpY = d5 + d7; clipPlanes.bpZ = d9 + d11; clipPlanes.bpW = d13 + d15; // Top Plane (row 3 - row 1) clipPlanes.tpX = d3 - d1; clipPlanes.tpY = d7 - d5; clipPlanes.tpZ = d11 - d9; clipPlanes.tpW = d15 - d13; clipPlanes.normalize(); } public void fromColumnArray(float[] in) { d0 = in[0]; d1 = in[1]; d2 = in[2]; d3 = in[3]; d4 = in[4]; d5 = in[5]; d6 = in[6]; d7 = in[7]; d8 = in[8]; d9 = in[9]; d10 = in[10]; d11 = in[11]; d12 = in[12]; d13 = in[13]; d14 = in[14]; d15 = in[15]; } public void fromColumnFloatBuffer(FloatBuffer fbIn) { d0 = fbIn.get(); d1 = fbIn.get(); d2 = fbIn.get(); d3 = fbIn.get(); d4 = fbIn.get(); d5 = fbIn.get(); d6 = fbIn.get(); d7 = fbIn.get(); d8 = fbIn.get(); d9 = fbIn.get(); d10 = fbIn.get(); d11 = fbIn.get(); d12 = fbIn.get(); d13 = fbIn.get(); d14 = fbIn.get(); d15 = fbIn.get(); } public void fromRowArray(float[] in) { d0 = in[0]; d4 = in[1]; d8 = in[2]; d12 = in[3]; d1 = in[4]; d5 = in[5]; d9 = in[6]; d13 = in[7]; d2 = in[8]; d6 = in[9]; d10 = in[10]; d14 = in[11]; d3 = in[12]; d7 = in[13]; d11 = in[14]; d15 = in[15]; } public void toFloatBuffer(FloatBuffer fbOut) { fbOut.put(d0); fbOut.put(d1); fbOut.put(d2); fbOut.put(d3); fbOut.put(d4); fbOut.put(d5); fbOut.put(d6); fbOut.put(d7); fbOut.put(d8); fbOut.put(d9); fbOut.put(d10); fbOut.put(d11); fbOut.put(d12); fbOut.put(d13); fbOut.put(d14); fbOut.put(d15); } public void toMatrix3f(Matrix3f out) { out.xAxis.x = d0; out.xAxis.y = d1; out.xAxis.z = d2; out.yAxis.x = d4; out.yAxis.y = d5; out.yAxis.z = d6; out.zAxis.x = d8; out.zAxis.y = d9; out.zAxis.z = d10; } public void toColumnArray(float[] out) { out[0] = d0; out[1] = d1; out[2] = d2; out[3] = d3; out[4] = d4; out[5] = d5; out[6] = d6; out[7] = d7; out[8] = d8; out[9] = d9; out[10] = d10; out[11] = d11; out[12] = d12; out[13] = d13; out[14] = d14; out[15] = d15; } public void toRowArray(float[] out) { out[0] = d0; out[1] = d4; out[2] = d8; out[3] = d12; out[4] = d1; out[5] = d5; out[6] = d9; out[7] = d13; out[8] = d2; out[9] = d6; out[10] = d10; out[11] = d14; out[12] = d3; out[13] = d7; out[14] = d11; out[15] = d15; } // Scalar Operations public float dotColumn3(int row, Vector3f vector) { switch (row) { case 0: return d0 * vector.x + d1 * vector.y + d2 * vector.z; case 1: return d4 * vector.x + d5 * vector.y + d6 * vector.z; case 2: return d8 * vector.x + d9 * vector.y + d10 * vector.z; } throw new IllegalArgumentException("Invalid row: " + row); } public float dotRow(int row, float c0, float c1, float c2, float c3) { switch (row) { case 0: return d0 * c0 + d4 * c1 + d8 * c2 + d12 * c3; case 1: return d1 * c0 + d5 * c1 + d9 * c2 + d13 * c3; case 2: return d2 * c0 + d6 * c1 + d10 * c2 + d14 * c3; case 3: return d3 * c0 + d7 * c1 + d11 * c2 + d15 * c3; } throw new IllegalArgumentException("Invalid row: " + row); } public float dotRow3(int row, Vector3f vector) { switch (row) { case 0: return d0 * vector.x + d4 * vector.y + d8 * vector.z; case 1: return d1 * vector.x + d5 * vector.y + d9 * vector.z; case 2: return d2 * vector.x + d6 * vector.y + d10 * vector.z; } throw new IllegalArgumentException("Invalid row: " + row); } public float getDeterminant() { float a1b1 = d10 * d15 - d14 * d11; float a2c1 = d6 * d15 - d14 * d7; float a3d1 = d6 * d11 - d10 * d7; float b2c2 = d2 * d15 - d14 * d3; float b3d2 = d2 * d11 - d10 * d3; float c3d3 = d2 * d7 - d6 * d3; return d0 * (d5 * a1b1 - d9 * a2c1 + d13 * a3d1) - d4 * (d1 * a1b1 - d9 * b2c2 + d13 * b3d2) + d8 * (d1 * a2c1 - d5 * b2c2 + d13 * c3d3) - d12 * (d1 * a3d1 - d5 * b3d2 + d9 * c3d3); } public float getPositionX() { return d12; } public float getPositionY() { return d13; } public float getPositionZ() { return d14; } // Matrix Operations public Matrix4f biasMultiplyProjectionOut(Matrix4f matrix, Matrix4f out) { assert (this != matrix); assert (this != out); // Bias Project = Result // x 0 0 px } d0 0 d8 d12 = (x d0) (0) (x d8 + px d11) (x d12 + px d15) // 0 y 0 py | 0 d5 d9 d13 = (0) (y d5) (y d9 + py d11) (y d13 + py d15) // 0 0 z pz | 0 0 d10 d14 = (0) (0) (z d10 + pz d11) (z d14 + pz d15) // 0 0 0 1 | 0 0 d11 d15 = (0) (0) (d11) (d15) out.d0 = d0 * matrix.d0; out.d4 = 0f; out.d8 = d0 * matrix.d8 + d12 * matrix.d11; out.d12 = d0 * matrix.d12 + d12 * matrix.d15; out.d1 = 0f; out.d5 = d5 * matrix.d5; out.d9 = d5 * matrix.d9 + d13 * matrix.d11; out.d13 = d5 * matrix.d13 + d13 * matrix.d15; out.d2 = 0f; out.d6 = 0f; out.d10 = d10 * matrix.d10 + d14 * matrix.d11; out.d14 = d10 * matrix.d14 + d14 * matrix.d15; out.d3 = 0f; out.d7 = 0f; out.d11 = matrix.d11; out.d15 = matrix.d15; return this; } public Matrix4f fromAxisAngle(Vector3f vector, float degrees) { float radians = MathHelper.ToRadians(degrees); float c = MathHelper.Cos(radians); float s = MathHelper.Sin(radians); float t = (1f - c); d0 = t * (vector.x * vector.x) + c; d1 = t * (vector.x * vector.y) + (vector.z * s); d2 = t * (vector.x * vector.z) - (vector.y * s); d3 = 0f; d4 = t * (vector.y * vector.x) - (vector.z * s); d5 = t * (vector.y * vector.y) + c; d6 = t * (vector.y * vector.z) + (vector.x * s); d7 = 0f; d8 = t * (vector.z * vector.x) + (vector.y * s); d9 = t * (vector.z * vector.y) - (vector.x * s); d10 = t * (vector.z * vector.z) + c; d11 = 0f; return this; } public final Matrix4f identity() { d0 = 1f; d1 = 0f; d2 = 0f; d3 = 0f; d4 = 0f; d5 = 1f; d6 = 0f; d7 = 0f; d8 = 0f; d9 = 0f; d10 = 1f; d11 = 0f; d12 = 0f; d13 = 0f; d14 = 0f; d15 = 1f; return this; } public Matrix4f multiply(float value) { d0 *= value; d1 *= value; d2 *= value; d3 *= value; d4 *= value; d5 *= value; d6 *= value; d7 *= value; d8 *= value; d9 *= value; d10 *= value; d11 *= value; d12 *= value; d13 *= value; d14 *= value; d15 *= value; return this; } public Matrix4f multiply(Matrix4f matrix) { float t1, t2, t3, t4; t1 = dotRow(0, matrix.d0, matrix.d1, matrix.d2, matrix.d3); t2 = dotRow(0, matrix.d4, matrix.d5, matrix.d6, matrix.d7); t3 = dotRow(0, matrix.d8, matrix.d9, matrix.d10, matrix.d11); t4 = dotRow(0, matrix.d12, matrix.d13, matrix.d14, matrix.d15); d0 = t1; d4 = t2; d8 = t3; d12 = t4; t1 = dotRow(1, matrix.d0, matrix.d1, matrix.d2, matrix.d3); t2 = dotRow(1, matrix.d4, matrix.d5, matrix.d6, matrix.d7); t3 = dotRow(1, matrix.d8, matrix.d9, matrix.d10, matrix.d11); t4 = dotRow(1, matrix.d12, matrix.d13, matrix.d14, matrix.d15); d1 = t1; d5 = t2; d9 = t3; d13 = t4; t1 = dotRow(2, matrix.d0, matrix.d1, matrix.d2, matrix.d3); t2 = dotRow(2, matrix.d4, matrix.d5, matrix.d6, matrix.d7); t3 = dotRow(2, matrix.d8, matrix.d9, matrix.d10, matrix.d11); t4 = dotRow(2, matrix.d12, matrix.d13, matrix.d14, matrix.d15); d2 = t1; d6 = t2; d10 = t3; d14 = t4; t1 = dotRow(3, matrix.d0, matrix.d1, matrix.d2, matrix.d3); t2 = dotRow(3, matrix.d4, matrix.d5, matrix.d6, matrix.d7); t3 = dotRow(3, matrix.d8, matrix.d9, matrix.d10, matrix.d11); t4 = dotRow(3, matrix.d12, matrix.d13, matrix.d14, matrix.d15); d3 = t1; d7 = t2; d11 = t3; d15 = t4; return this; } public Matrix4f multiply(Vector3f vector) { d12 += d0 * vector.x + d4 * vector.y + d8 * vector.z; d13 += d1 * vector.x + d5 * vector.y + d9 * vector.z; d14 += d2 * vector.x + d6 * vector.y + d10 * vector.z; d15 += d3 * vector.x + d7 * vector.y + d11 * vector.z; return this; } public Matrix4f multiplyOut(Matrix4f matrix, Matrix4f out) { assert (this != matrix); assert (this != out); out.d0 = dotRow(0, matrix.d0, matrix.d1, matrix.d2, matrix.d3); out.d4 = dotRow(0, matrix.d4, matrix.d5, matrix.d6, matrix.d7); out.d8 = dotRow(0, matrix.d8, matrix.d9, matrix.d10, matrix.d11); out.d12 = dotRow(0, matrix.d12, matrix.d13, matrix.d14, matrix.d15); out.d1 = dotRow(1, matrix.d0, matrix.d1, matrix.d2, matrix.d3); out.d5 = dotRow(1, matrix.d4, matrix.d5, matrix.d6, matrix.d7); out.d9 = dotRow(1, matrix.d8, matrix.d9, matrix.d10, matrix.d11); out.d13 = dotRow(1, matrix.d12, matrix.d13, matrix.d14, matrix.d15); out.d2 = dotRow(2, matrix.d0, matrix.d1, matrix.d2, matrix.d3); out.d6 = dotRow(2, matrix.d4, matrix.d5, matrix.d6, matrix.d7); out.d10 = dotRow(2, matrix.d8, matrix.d9, matrix.d10, matrix.d11); out.d14 = dotRow(2, matrix.d12, matrix.d13, matrix.d14, matrix.d15); out.d3 = dotRow(3, matrix.d0, matrix.d1, matrix.d2, matrix.d3); out.d7 = dotRow(3, matrix.d4, matrix.d5, matrix.d6, matrix.d7); out.d11 = dotRow(3, matrix.d8, matrix.d9, matrix.d10, matrix.d11); out.d15 = dotRow(3, matrix.d12, matrix.d13, matrix.d14, matrix.d15); return this; } public Matrix4f projectionMultiplyViewOut(Matrix4f matrix, Matrix4f out) { assert (this != matrix); assert (this != out); // http://www.songho.ca/opengl/gl_projectionmatrix.html // Project | View = Result // d0 0 d8 d12 | xx yx zx px = (d0 xx + d8 xz) (d0 yx + d8 yz) (d0 zx + d8 zz) (d0 px + d8 pz) + d12 // 0 d5 d9 d13 | xy yy zy py = (d5 xy + d9 xz) (d5 yy + d9 yz) (d5 zy + d9 zz) (d5 py + d9 pz) + d13 // 0 0 d10 d14 | xz yz zz pz = (d10 xz) (d10 yz) (d10 zz) (d10 pz) + d14 // 0 0 d11 d15 | 0 0 0 1 = (d11 xz) (d11 yz) (d11 zz) (d11 pz) + d15 out.d0 = d0 * matrix.d0 + d8 * matrix.d2; out.d4 = d0 * matrix.d4 + d8 * matrix.d6; out.d8 = d0 * matrix.d8 + d8 * matrix.d10; out.d12 = d0 * matrix.d12 + d8 * matrix.d14 + d12; out.d1 = d5 * matrix.d1 + d9 * matrix.d2; out.d5 = d5 * matrix.d5 + d9 * matrix.d6; out.d9 = d5 * matrix.d9 + d9 * matrix.d10; out.d13 = d5 * matrix.d13 + d9 * matrix.d14 + d13; out.d2 = d10 * matrix.d2; out.d6 = d10 * matrix.d6; out.d10 = d10 * matrix.d10; out.d14 = d10 * matrix.d14 + d14; out.d3 = d11 * matrix.d2; out.d7 = d11 * matrix.d6; out.d11 = d11 * matrix.d10; out.d15 = d11 * matrix.d14 + d15; return this; } public Matrix4f projectionSymmetricalMultiplyViewOut(Matrix4f matrix, Matrix4f out) { assert (this != matrix); assert (this != out); // http://www.songho.ca/opengl/gl_projectionmatrix.html // Project | View = Result // d0 0 0 0 | xx yx zx px = (d0 xx) (d0 yx) (d0 zx) (d0 px) // 0 d5 0 0 | xy yy zy py = (d5 xy) (d5 yy) (d5 zy) (d5 py) // 0 0 d10 d14 | xz yz zz pz = (d10 xz) (d10 yz) (d10 zz) (d10 pz) + d14 // 0 0 d11 d15 | 0 0 0 1 = (d11 xz) (d11 yz) (d11 zz) (d11 pz) + d15 out.d0 = d0 * matrix.d0; out.d4 = d0 * matrix.d4; out.d8 = d0 * matrix.d8; out.d12 = d0 * matrix.d12; out.d1 = d5 * matrix.d1; out.d5 = d5 * matrix.d5; out.d9 = d5 * matrix.d9; out.d13 = d5 * matrix.d13; out.d2 = d10 * matrix.d2; out.d6 = d10 * matrix.d6; out.d10 = d10 * matrix.d10; out.d14 = d10 * matrix.d14 + d14; out.d3 = d11 * matrix.d2; out.d7 = d11 * matrix.d6; out.d11 = d11 * matrix.d10; out.d15 = d11 * matrix.d14 + d15; return this; } public final Matrix4f set(Matrix4f matrix) { d0 = matrix.d0; d1 = matrix.d1; d2 = matrix.d2; d3 = matrix.d3; d4 = matrix.d4; d5 = matrix.d5; d6 = matrix.d6; d7 = matrix.d7; d8 = matrix.d8; d9 = matrix.d9; d10 = matrix.d10; d11 = matrix.d11; d12 = matrix.d12; d13 = matrix.d13; d14 = matrix.d14; d15 = matrix.d15; return this; } public Matrix4f set(Transform4f transform) { d0 = transform.rotation.xAxis.x; d1 = transform.rotation.xAxis.y; d2 = transform.rotation.xAxis.z; d3 = 0f; d4 = transform.rotation.yAxis.x; d5 = transform.rotation.yAxis.y; d6 = transform.rotation.yAxis.z; d7 = 0f; d8 = transform.rotation.zAxis.x; d9 = transform.rotation.zAxis.y; d10 = transform.rotation.zAxis.z; d11 = 0f; d12 = transform.position.x; d13 = transform.position.y; d14 = transform.position.z; d15 = 1f; return this; } public Matrix4f setDiagonal(float radius) { d0 = radius; d5 = radius; d10 = radius; return this; } public Matrix4f setDiagonal(float x, float y, float z) { d0 = x; d5 = y; d10 = z; return this; } public Matrix4f setFrustum(float left, float right, float bottom, float top, float zNear, float zFar) { float invDeltaX = 1f / (right - left); float invDeltaY = 1f / (top - bottom); float invDeltaZ = 1f / (zFar - zNear); float h = 2f * zNear * invDeltaY; setRow(0, 2f * zNear * invDeltaX, 0f, (right + left) * invDeltaX, 0f); setRow(1, 0f, h, (top + bottom) * invDeltaY, 0f); setRow(2, 0f, 0f, -(zFar + zNear) * invDeltaZ, -2f * zFar * zNear * invDeltaZ); setRow(3, 0f, 0f, -1f, 0f); return this; } public Matrix4f setInverse(Matrix3f rotation, Vector3f position) { d0 = rotation.xAxis.x; d1 = rotation.yAxis.x; d2 = rotation.zAxis.x; d3 = 0f; d4 = rotation.xAxis.y; d5 = rotation.yAxis.y; d6 = rotation.zAxis.y; d7 = 0f; d8 = rotation.xAxis.z; d9 = rotation.yAxis.z; d10 = rotation.zAxis.z; d11 = 0f; d12 = -rotation.xAxis.dot(position); d13 = -rotation.yAxis.dot(position); d14 = -rotation.zAxis.dot(position); d15 = 1f; return this; } public Matrix4f setInverse(Matrix4f matrix) { assert (this != matrix); float a1b1 = matrix.d10 * matrix.d15 - matrix.d14 * matrix.d11; float a2c1 = matrix.d6 * matrix.d15 - matrix.d14 * matrix.d7; float a3d1 = matrix.d6 * matrix.d11 - matrix.d10 * matrix.d7; float b2c2 = matrix.d2 * matrix.d15 - matrix.d14 * matrix.d3; float b3d2 = matrix.d2 * matrix.d11 - matrix.d10 * matrix.d3; float c3d3 = matrix.d2 * matrix.d7 - matrix.d6 * matrix.d3; float t0 = matrix.d5 * a1b1 - matrix.d9 * a2c1 + matrix.d13 * a3d1; float t4 = matrix.d1 * a1b1 - matrix.d9 * b2c2 + matrix.d13 * b3d2; float t8 = matrix.d1 * a2c1 - matrix.d5 * b2c2 + matrix.d13 * c3d3; float t12 = matrix.d1 * a3d1 - matrix.d5 * b3d2 + matrix.d9 * c3d3; float determinant = matrix.d0 * t0 - matrix.d4 * t4 + matrix.d8 * t8 - matrix.d12 * t12; if ((determinant < MathHelper.ZERO_EPSILON) && (determinant > -MathHelper.ZERO_EPSILON)) { throw new RuntimeException("Unable to invert matrix"); } // Row 1 d0 = t0; d4 = -t4; d8 = t8; d12 = -t12; // Row 2 a1b1 = matrix.d10 * matrix.d15 - matrix.d14 * matrix.d11; a2c1 = matrix.d6 * matrix.d15 - matrix.d14 * matrix.d7; a3d1 = matrix.d6 * matrix.d11 - matrix.d10 * matrix.d7; b2c2 = matrix.d2 * matrix.d15 - matrix.d14 * matrix.d3; b3d2 = matrix.d2 * matrix.d11 - matrix.d10 * matrix.d3; c3d3 = matrix.d2 * matrix.d7 - matrix.d6 * matrix.d3; d1 = -(matrix.d4 * a1b1 - matrix.d8 * a2c1 + matrix.d12 * a3d1); d5 = matrix.d0 * a1b1 - matrix.d8 * b2c2 + matrix.d12 * b3d2; d9 = -(matrix.d0 * a2c1 - matrix.d4 * b2c2 + matrix.d12 * c3d3); d13 = matrix.d0 * a3d1 - matrix.d4 * b3d2 + matrix.d8 * c3d3; // Row 3 a1b1 = matrix.d9 * matrix.d15 - matrix.d13 * matrix.d11; a2c1 = matrix.d5 * matrix.d15 - matrix.d13 * matrix.d7; a3d1 = matrix.d5 * matrix.d11 - matrix.d9 * matrix.d7; b2c2 = matrix.d1 * matrix.d15 - matrix.d13 * matrix.d3; b3d2 = matrix.d1 * matrix.d11 - matrix.d9 * matrix.d3; c3d3 = matrix.d1 * matrix.d7 - matrix.d5 * matrix.d3; d2 = matrix.d4 * a1b1 - matrix.d8 * a2c1 + matrix.d12 * a3d1; d6 = -(matrix.d0 * a1b1 - matrix.d8 * b2c2 + matrix.d12 * b3d2); d10 = matrix.d0 * a2c1 - matrix.d4 * b2c2 + matrix.d12 * c3d3; d14 = -(matrix.d0 * a3d1 - matrix.d4 * b3d2 + matrix.d8 * c3d3); // Row 4 a1b1 = matrix.d9 * matrix.d14 - matrix.d13 * matrix.d10; a2c1 = matrix.d5 * matrix.d14 - matrix.d13 * matrix.d6; a3d1 = matrix.d5 * matrix.d10 - matrix.d9 * matrix.d6; b2c2 = matrix.d1 * matrix.d14 - matrix.d13 * matrix.d2; b3d2 = matrix.d1 * matrix.d10 - matrix.d9 * matrix.d2; c3d3 = matrix.d1 * matrix.d6 - matrix.d5 * matrix.d2; d3 = -(matrix.d4 * a1b1 - matrix.d8 * a2c1 + matrix.d12 * a3d1); d7 = matrix.d0 * a1b1 - matrix.d8 * b2c2 + matrix.d12 * b3d2; d11 = -(matrix.d0 * a2c1 - matrix.d4 * b2c2 + matrix.d12 * c3d3); d15 = matrix.d0 * a3d1 - matrix.d4 * b3d2 + matrix.d8 * c3d3; return multiply(1f / determinant); } public Matrix4f setOrthogonal(float left, float right, float bottom, float top, float zNear, float zFar) { float invDeltaX = 1f / (right - left); float invDeltaY = 1f / (top - bottom); float invDeltaZ = 1f / (zFar - zNear); float h = 2f * invDeltaY; setRow(0, 2f * invDeltaX, 0f, 0f, -(right + left) * invDeltaX); setRow(1, 0f, h, 0f, -(top + bottom) * invDeltaY); setRow(2, 0f, 0f, -2f * invDeltaZ, -(zFar + zNear) * invDeltaZ); setRow(3, 0f, 0f, 0f, 1f); return this; } public Matrix4f setPerspective(float fieldOfViewY, float aspectRatio, float zNear, float zFar) { float coTangent = 1f / MathHelper.Tan(fieldOfViewY * MathHelper.PI_OVER_360); float invDeltaZ = 1f / (zFar - zNear); setRow(0, coTangent / aspectRatio, 0f, 0f, 0f); setRow(1, 0f, coTangent, 0f, 0f); setRow(2, 0f, 0f, -(zFar + zNear) * invDeltaZ, -2f * zNear * zFar * invDeltaZ); setRow(3, 0f, 0f, -1f, 0f); return this; } public Matrix4f setPosition(float x, float y, float z) { d12 = x; d13 = y; d14 = z; return this; } public Matrix4f setPosition(Vector3f position) { d12 = position.x; d13 = position.y; d14 = position.z; return this; } public Matrix4f setRow(int row, float c0, float c1, float c2, float c3) { switch (row) { case 0: d0 = c0; d4 = c1; d8 = c2; d12 = c3; break; case 1: d1 = c0; d5 = c1; d9 = c2; d13 = c3; break; case 2: d2 = c0; d6 = c1; d10 = c2; d14 = c3; break; case 3: d3 = c0; d7 = c1; d11 = c2; d15 = c3; break; default: throw new IllegalArgumentException("Invalid row: " + row); } return this; } public void viewMultiplyModelOut(Matrix4f matrix, Matrix4f out) { assert (this != matrix); assert (this != out); // View | Model = Result // vxx vyx vzx vpx | mxx myx mzx mpx = o1 // vxy vyy vzy vpy | mxy myy mzy mpy = o2 // vxz vyz vzz vpz | mxz myz mzz mpz = o3 // 0 0 0 1 | 0 0 0 1 = o4 // o1 = (vxx mxx + vyx mxy + vzx mxz) (vxx myx + vyx myy + vzx myz) (vxx mzx + vyx mzy + vzx mzz) (vxx mpx + vyx mpy + vzx mpz) + vpx // o2 = (vxy mxx + vyy mxy + vzy mxz) (vxy myx + vyy myy + vzy myz) (vxy mzx + vyy mzy + vzy mzz) (vxy mpx + vyy mpy + vzy mpz) + vpy // o3 = (vxz mxx + vyz mxy + vzz mxz) (vxz myx + vyz myy + vzz myz) (vxz mzx + vyz mzy + vzz mzz) (vxz mpx + vyz mpy + vzz mpz) + vpz // o4 = 0 0 0 1 out.d0 = d0 * matrix.d0 + d4 * matrix.d1 + d8 * matrix.d2; out.d4 = d0 * matrix.d4 + d4 * matrix.d5 + d8 * matrix.d6; out.d8 = d0 * matrix.d8 + d4 * matrix.d9 + d8 * matrix.d10; out.d12 = d0 * matrix.d12 + d4 * matrix.d13 + d8 * matrix.d14 + d12; out.d1 = d1 * matrix.d0 + d5 * matrix.d1 + d9 * matrix.d2; out.d5 = d1 * matrix.d4 + d5 * matrix.d5 + d9 * matrix.d6; out.d9 = d1 * matrix.d8 + d5 * matrix.d9 + d9 * matrix.d10; out.d13 = d1 * matrix.d12 + d5 * matrix.d13 + d9 * matrix.d14 + d13; out.d2 = d2 * matrix.d0 + d6 * matrix.d1 + d10 * matrix.d2; out.d6 = d2 * matrix.d4 + d6 * matrix.d5 + d10 * matrix.d6; out.d10 = d2 * matrix.d8 + d6 * matrix.d9 + d10 * matrix.d10; out.d14 = d2 * matrix.d12 + d6 * matrix.d13 + d10 * matrix.d14 + d14; out.d3 = 0f; out.d7 = 0f; out.d11 = 0f; out.d15 = 1f; } // Vector Operations public Vector3f multiplyOut(Vector3f vector, Vector3f out) { out.set( dotRow3(0, vector), dotRow3(1, vector), dotRow3(2, vector)); out.add(d12, d13, d14); return out; } public Vector3f multiplyDirectionOut(Vector3f vector, Vector3f out) { out.set( dotRow3(0, vector), dotRow3(1, vector), dotRow3(2, vector)); return out; } public Vector3f multiplyProjectionOut(Vector3f vector, Vector3f out) { float w = 1f / (vector.x * d12 + vector.y * d13 + vector.z * d14 + d15); out.set( dotColumn3(0, vector), dotColumn3(1, vector), dotColumn3(2, vector)); out.add(d3, d7, d11); out.multiply(w); return out; } @Override public int hashCode() { int hash = 7; hash = 47 * hash + Float.floatToIntBits(this.d0); hash = 47 * hash + Float.floatToIntBits(this.d1); hash = 47 * hash + Float.floatToIntBits(this.d2); hash = 47 * hash + Float.floatToIntBits(this.d3); hash = 47 * hash + Float.floatToIntBits(this.d4); hash = 47 * hash + Float.floatToIntBits(this.d5); hash = 47 * hash + Float.floatToIntBits(this.d6); hash = 47 * hash + Float.floatToIntBits(this.d7); hash = 47 * hash + Float.floatToIntBits(this.d8); hash = 47 * hash + Float.floatToIntBits(this.d9); hash = 47 * hash + Float.floatToIntBits(this.d10); hash = 47 * hash + Float.floatToIntBits(this.d11); hash = 47 * hash + Float.floatToIntBits(this.d12); hash = 47 * hash + Float.floatToIntBits(this.d13); hash = 47 * hash + Float.floatToIntBits(this.d14); hash = 47 * hash + Float.floatToIntBits(this.d15); return hash; } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (getClass() != obj.getClass()) { return false; } final Matrix4f other = (Matrix4f) obj; if (Float.floatToIntBits(this.d0) != Float.floatToIntBits(other.d0)) { return false; } if (Float.floatToIntBits(this.d1) != Float.floatToIntBits(other.d1)) { return false; } if (Float.floatToIntBits(this.d2) != Float.floatToIntBits(other.d2)) { return false; } if (Float.floatToIntBits(this.d3) != Float.floatToIntBits(other.d3)) { return false; } if (Float.floatToIntBits(this.d4) != Float.floatToIntBits(other.d4)) { return false; } if (Float.floatToIntBits(this.d5) != Float.floatToIntBits(other.d5)) { return false; } if (Float.floatToIntBits(this.d6) != Float.floatToIntBits(other.d6)) { return false; } if (Float.floatToIntBits(this.d7) != Float.floatToIntBits(other.d7)) { return false; } if (Float.floatToIntBits(this.d8) != Float.floatToIntBits(other.d8)) { return false; } if (Float.floatToIntBits(this.d9) != Float.floatToIntBits(other.d9)) { return false; } if (Float.floatToIntBits(this.d10) != Float.floatToIntBits(other.d10)) { return false; } if (Float.floatToIntBits(this.d11) != Float.floatToIntBits(other.d11)) { return false; } if (Float.floatToIntBits(this.d12) != Float.floatToIntBits(other.d12)) { return false; } if (Float.floatToIntBits(this.d13) != Float.floatToIntBits(other.d13)) { return false; } if (Float.floatToIntBits(this.d14) != Float.floatToIntBits(other.d14)) { return false; } return Float.floatToIntBits(this.d15) == Float.floatToIntBits(other.d15); } @Override public String toString() { return "(d0: " + d0 + " d4: " + d4 + " d8: " + d8 + " d12: " + d12 + ")\n" + "(d1: " + d1 + " d5: " + d5 + " d9: " + d9 + " d13: " + d13 + ")\n" + "(d2: " + d2 + " d6: " + d6 + " d10: " + d10 + " d14: " + d14 + ")\n" + "(d3: " + d3 + " d7: " + d7 + " d11: " + d11 + " d15: " + d15 + ")"; } }