2 * Copyright (c) 2003-2009 jMonkeyEngine
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are
9 * * Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
12 * * Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
24 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 import java.io.IOException;
36 import java.io.Serializable;
37 import java.nio.FloatBuffer;
38 import java.util.logging.Logger;
40 import com.jme.system.JmeException;
41 import com.jme.util.export.InputCapsule;
42 import com.jme.util.export.JMEExporter;
43 import com.jme.util.export.JMEImporter;
44 import com.jme.util.export.OutputCapsule;
45 import com.jme.util.export.Savable;
46 import com.jme.util.geom.BufferUtils;
49 * <code>Matrix4f</code> defines and maintains a 4x4 matrix in row major order.
50 * This matrix is intended for use in a translation and rotational capacity.
51 * It provides convenience methods for creating the matrix from a multitude
54 * Matrices are stored assuming column vectors on the right, with the translation
55 * in the rightmost column. Element numbering is row,column, so m03 is the zeroth
56 * row, third column, which is the "x" translation part. This means that the implicit
57 * storage order is column major. However, the get() and set() functions on float
58 * arrays default to row major order!
61 * @author Joshua Slack
63 public class Matrix4f implements Serializable, Savable, Cloneable {
64 private static final Logger logger = Logger.getLogger(Matrix4f.class.getName());
66 private static final long serialVersionUID = 1L;
68 public float m00, m01, m02, m03;
70 public float m10, m11, m12, m13;
72 public float m20, m21, m22, m23;
74 public float m30, m31, m32, m33;
77 * Constructor instantiates a new <code>Matrix</code> that is set to the
86 * constructs a matrix with the given values.
88 public Matrix4f(float m00, float m01, float m02, float m03,
89 float m10, float m11, float m12, float m13,
90 float m20, float m21, float m22, float m23,
91 float m30, float m31, float m32, float m33) {
112 * Create a new Matrix4f, given data in column-major format.
115 * An array of 16 floats in column-major format (translation in elements 12, 13 and 14).
117 public Matrix4f(float[] array) {
122 * Constructor instantiates a new <code>Matrix</code> that is set to the
123 * provided matrix. This constructor copies a given Matrix. If the provided
124 * matrix is null, the constructor sets the matrix to the identity.
127 * the matrix to copy.
129 public Matrix4f(Matrix4f mat) {
134 * <code>copy</code> transfers the contents of a given matrix to this
135 * matrix. If a null matrix is supplied, this matrix is set to the identity
139 * the matrix to copy.
141 public void copy(Matrix4f matrix) {
142 if (null == matrix) {
165 * <code>get</code> retrieves the values of this object into
166 * a float array in row-major order.
169 * the matrix to set the values into.
171 public void get(float[] matrix) {
176 * <code>set</code> retrieves the values of this object into
180 * the matrix to set the values into.
182 * whether the outgoing data is in row or column major order.
184 public void get(float[] matrix, boolean rowMajor) {
185 if (matrix.length != 16) throw new JmeException(
186 "Array must be of size 16.");
226 * <code>get</code> retrieves a value from the matrix at the given
227 * position. If the position is invalid a <code>JmeException</code> is
234 * @return the value at (i, j).
236 public float get(int i, int j) {
268 logger.warning("Invalid matrix index.");
269 throw new JmeException("Invalid indices into matrix.");
273 * <code>getColumn</code> returns one of three columns specified by the
274 * parameter. This column is returned as a float array of length 4.
277 * the column to retrieve. Must be between 0 and 3.
278 * @return the column specified by the index.
280 public float[] getColumn(int i) {
281 return getColumn(i, null);
285 * <code>getColumn</code> returns one of three columns specified by the
286 * parameter. This column is returned as a float[4].
289 * the column to retrieve. Must be between 0 and 3.
291 * the float array to store the result in. if null, a new one
293 * @return the column specified by the index.
295 public float[] getColumn(int i, float[] store) {
296 if (store == null) store = new float[4];
323 logger.warning("Invalid column index.");
324 throw new JmeException("Invalid column index. " + i);
331 * <code>setColumn</code> sets a particular column of this matrix to that
332 * represented by the provided vector.
339 public void setColumn(int i, float[] column) {
341 if (column == null) {
342 logger.warning("Column is null. Ignoring.");
371 logger.warning("Invalid column index.");
372 throw new JmeException("Invalid column index. " + i);
376 * <code>set</code> places a given value into the matrix at the given
377 * position. If the position is invalid a <code>JmeException</code> is
385 * the value for (i, j).
387 public void set(int i, int j, float value) {
391 case 0: m00 = value; return;
392 case 1: m01 = value; return;
393 case 2: m02 = value; return;
394 case 3: m03 = value; return;
398 case 0: m10 = value; return;
399 case 1: m11 = value; return;
400 case 2: m12 = value; return;
401 case 3: m13 = value; return;
405 case 0: m20 = value; return;
406 case 1: m21 = value; return;
407 case 2: m22 = value; return;
408 case 3: m23 = value; return;
412 case 0: m30 = value; return;
413 case 1: m31 = value; return;
414 case 2: m32 = value; return;
415 case 3: m33 = value; return;
419 logger.warning("Invalid matrix index.");
420 throw new JmeException("Invalid indices into matrix.");
424 * <code>set</code> sets the values of this matrix from an array of
428 * the matrix to set the value to.
429 * @throws JmeException
430 * if the array is not of size 16.
432 public void set(float[][] matrix) {
433 if (matrix.length != 4 || matrix[0].length != 4) { throw new JmeException(
434 "Array must be of size 16."); }
455 * <code>set</code> sets the values of this matrix from another matrix.
458 * the matrix to read the value from.
460 public Matrix4f set(Matrix4f matrix) {
461 m00 = matrix.m00; m01 = matrix.m01; m02 = matrix.m02; m03 = matrix.m03;
462 m10 = matrix.m10; m11 = matrix.m11; m12 = matrix.m12; m13 = matrix.m13;
463 m20 = matrix.m20; m21 = matrix.m21; m22 = matrix.m22; m23 = matrix.m23;
464 m30 = matrix.m30; m31 = matrix.m31; m32 = matrix.m32; m33 = matrix.m33;
469 * <code>set</code> sets the values of this matrix from an array of
470 * values assuming that the data is rowMajor order;
473 * the matrix to set the value to.
475 public void set(float[] matrix) {
480 * <code>set</code> sets the values of this matrix from an array of
484 * the matrix to set the value to.
486 * whether the incoming data is in row or column major order.
488 public void set(float[] matrix, boolean rowMajor) {
489 if (matrix.length != 16) throw new JmeException(
490 "Array must be of size 16.");
529 public Matrix4f transpose() {
530 float[] tmp = new float[16];
532 Matrix4f mat = new Matrix4f(tmp);
537 * <code>transpose</code> locally transposes this Matrix.
539 * @return this object for chaining.
541 public Matrix4f transposeLocal() {
542 float[] tmp = new float[16];
550 * <code>toFloatBuffer</code> returns a FloatBuffer object that contains
553 * @return matrix data as a FloatBuffer.
555 public FloatBuffer toFloatBuffer() {
556 return toFloatBuffer(false);
560 * <code>toFloatBuffer</code> returns a FloatBuffer object that contains the
564 * if true, this buffer should be filled with column major data,
565 * otherwise it will be filled row major.
566 * @return matrix data as a FloatBuffer. The position is set to 0 for
569 public FloatBuffer toFloatBuffer(boolean columnMajor) {
570 FloatBuffer fb = BufferUtils.createFloatBuffer(16);
571 fillFloatBuffer(fb, columnMajor);
577 * <code>fillFloatBuffer</code> fills a FloatBuffer object with
579 * @param fb the buffer to fill, must be correct size
580 * @return matrix data as a FloatBuffer.
582 public FloatBuffer fillFloatBuffer(FloatBuffer fb) {
583 return fillFloatBuffer(fb, false);
587 * <code>fillFloatBuffer</code> fills a FloatBuffer object with the matrix
591 * the buffer to fill, starting at current position. Must have
592 * room for 16 more floats.
594 * if true, this buffer should be filled with column major data,
595 * otherwise it will be filled row major.
596 * @return matrix data as a FloatBuffer. (position is advanced by 16 and any
597 * limit set is not changed).
599 public FloatBuffer fillFloatBuffer(FloatBuffer fb, boolean columnMajor) {
601 fb.put(m00).put(m10).put(m20).put(m30);
602 fb.put(m01).put(m11).put(m21).put(m31);
603 fb.put(m02).put(m12).put(m22).put(m32);
604 fb.put(m03).put(m13).put(m23).put(m33);
606 fb.put(m00).put(m01).put(m02).put(m03);
607 fb.put(m10).put(m11).put(m12).put(m13);
608 fb.put(m20).put(m21).put(m22).put(m23);
609 fb.put(m30).put(m31).put(m32).put(m33);
615 * <code>readFloatBuffer</code> reads value for this matrix from a FloatBuffer.
616 * @param fb the buffer to read from, must be correct size
617 * @return this data as a FloatBuffer.
619 public Matrix4f readFloatBuffer(FloatBuffer fb) {
620 return readFloatBuffer(fb, false);
624 * <code>readFloatBuffer</code> reads value for this matrix from a FloatBuffer.
625 * @param fb the buffer to read from, must be correct size
626 * @param columnMajor if true, this buffer should be filled with column
627 * major data, otherwise it will be filled row major.
628 * @return this data as a FloatBuffer.
630 public Matrix4f readFloatBuffer(FloatBuffer fb, boolean columnMajor) {
633 m00 = fb.get(); m10 = fb.get(); m20 = fb.get(); m30 = fb.get();
634 m01 = fb.get(); m11 = fb.get(); m21 = fb.get(); m31 = fb.get();
635 m02 = fb.get(); m12 = fb.get(); m22 = fb.get(); m32 = fb.get();
636 m03 = fb.get(); m13 = fb.get(); m23 = fb.get(); m33 = fb.get();
638 m00 = fb.get(); m01 = fb.get(); m02 = fb.get(); m03 = fb.get();
639 m10 = fb.get(); m11 = fb.get(); m12 = fb.get(); m13 = fb.get();
640 m20 = fb.get(); m21 = fb.get(); m22 = fb.get(); m23 = fb.get();
641 m30 = fb.get(); m31 = fb.get(); m32 = fb.get(); m33 = fb.get();
647 * <code>loadIdentity</code> sets this matrix to the identity matrix,
648 * namely all zeros with ones along the diagonal.
651 public void loadIdentity() {
652 m01 = m02 = m03 = 0.0f;
653 m10 = m12 = m13 = 0.0f;
654 m20 = m21 = m23 = 0.0f;
655 m30 = m31 = m32 = 0.0f;
656 m00 = m11 = m22 = m33 = 1.0f;
660 * <code>fromAngleAxis</code> sets this matrix4f to the values specified
661 * by an angle and an axis of rotation. This method creates an object, so
662 * use fromAngleNormalAxis if your axis is already normalized.
665 * the angle to rotate (in radians).
667 * the axis of rotation.
669 public void fromAngleAxis(float angle, Vector3f axis) {
670 Vector3f normAxis = axis.normalize();
671 fromAngleNormalAxis(angle, normAxis);
675 * <code>fromAngleNormalAxis</code> sets this matrix4f to the values
676 * specified by an angle and a normalized axis of rotation.
679 * the angle to rotate (in radians).
681 * the axis of rotation (already normalized).
683 public void fromAngleNormalAxis(float angle, Vector3f axis) {
687 float fCos = FastMath.cos(angle);
688 float fSin = FastMath.sin(angle);
689 float fOneMinusCos = ((float)1.0)-fCos;
690 float fX2 = axis.x*axis.x;
691 float fY2 = axis.y*axis.y;
692 float fZ2 = axis.z*axis.z;
693 float fXYM = axis.x*axis.y*fOneMinusCos;
694 float fXZM = axis.x*axis.z*fOneMinusCos;
695 float fYZM = axis.y*axis.z*fOneMinusCos;
696 float fXSin = axis.x*fSin;
697 float fYSin = axis.y*fSin;
698 float fZSin = axis.z*fSin;
700 m00 = fX2*fOneMinusCos+fCos;
704 m11 = fY2*fOneMinusCos+fCos;
708 m22 = fZ2*fOneMinusCos+fCos;
712 * <code>mult</code> multiplies this matrix by a scalar.
715 * the scalar to multiply this matrix by.
717 public void multLocal(float scalar) {
736 public Matrix4f mult(float scalar) {
737 Matrix4f out = new Matrix4f();
739 out.multLocal(scalar);
743 public Matrix4f mult(float scalar, Matrix4f store) {
745 store.multLocal(scalar);
750 * <code>mult</code> multiplies this matrix with another matrix. The
751 * result matrix will then be returned. This matrix will be on the left hand
752 * side, while the parameter matrix will be on the right.
755 * the matrix to multiply this matrix by.
756 * @return the resultant matrix
758 public Matrix4f mult(Matrix4f in2) {
759 return mult(in2, null);
763 * <code>mult</code> multiplies this matrix with another matrix. The
764 * result matrix will then be returned. This matrix will be on the left hand
765 * side, while the parameter matrix will be on the right.
768 * the matrix to multiply this matrix by.
770 * where to store the result. It is safe for in2 and store to be
772 * @return the resultant matrix
774 public Matrix4f mult(Matrix4f in2, Matrix4f store) {
775 if (store == null) store = new Matrix4f();
777 float temp00, temp01, temp02, temp03;
778 float temp10, temp11, temp12, temp13;
779 float temp20, temp21, temp22, temp23;
780 float temp30, temp31, temp32, temp33;
782 temp00 = m00 * in2.m00 +
786 temp01 = m00 * in2.m01 +
790 temp02 = m00 * in2.m02 +
794 temp03 = m00 * in2.m03 +
799 temp10 = m10 * in2.m00 +
803 temp11 = m10 * in2.m01 +
807 temp12 = m10 * in2.m02 +
811 temp13 = m10 * in2.m03 +
816 temp20 = m20 * in2.m00 +
820 temp21 = m20 * in2.m01 +
824 temp22 = m20 * in2.m02 +
828 temp23 = m20 * in2.m03 +
833 temp30 = m30 * in2.m00 +
837 temp31 = m30 * in2.m01 +
841 temp32 = m30 * in2.m02 +
845 temp33 = m30 * in2.m03 +
850 store.m00 = temp00; store.m01 = temp01; store.m02 = temp02; store.m03 = temp03;
851 store.m10 = temp10; store.m11 = temp11; store.m12 = temp12; store.m13 = temp13;
852 store.m20 = temp20; store.m21 = temp21; store.m22 = temp22; store.m23 = temp23;
853 store.m30 = temp30; store.m31 = temp31; store.m32 = temp32; store.m33 = temp33;
859 * <code>mult</code> multiplies this matrix with another matrix. The
860 * results are stored internally and a handle to this matrix will
861 * then be returned. This matrix will be on the left hand
862 * side, while the parameter matrix will be on the right.
865 * the matrix to multiply this matrix by.
866 * @return the resultant matrix
868 public Matrix4f multLocal(Matrix4f in2) {
870 return mult(in2, this);
874 * <code>mult</code> multiplies a vector about a rotation matrix. The
875 * resulting vector is returned as a new Vector3f.
878 * vec to multiply against.
879 * @return the rotated vector.
881 public Vector3f mult(Vector3f vec) {
882 return mult(vec, null);
886 * <code>mult</code> multiplies a vector about a rotation matrix and adds
887 * translation. The resulting vector is returned.
890 * vec to multiply against.
892 * a vector to store the result in. Created if null is passed.
893 * @return the rotated vector.
895 public Vector3f mult(Vector3f vec, Vector3f store) {
896 if (store == null) store = new Vector3f();
898 float vx = vec.x, vy = vec.y, vz = vec.z;
899 store.x = m00 * vx + m01 * vy + m02 * vz + m03;
900 store.y = m10 * vx + m11 * vy + m12 * vz + m13;
901 store.z = m20 * vx + m21 * vy + m22 * vz + m23;
907 * <code>mult</code> multiplies a vector about a rotation matrix. The
908 * resulting vector is returned.
911 * vec to multiply against.
913 * a vector to store the result in. created if null is passed.
914 * @return the rotated vector.
916 public Vector3f multAcross(Vector3f vec, Vector3f store) {
918 logger.info("Source vector is null, null result returned.");
921 if (store == null) store = new Vector3f();
923 float vx = vec.x, vy = vec.y, vz = vec.z;
924 store.x = m00 * vx + m10 * vy + m20 * vz + m30 * 1;
925 store.y = m01 * vx + m11 * vy + m21 * vz + m31 * 1;
926 store.z = m02 * vx + m12 * vy + m22 * vz + m32 * 1;
932 * <code>mult</code> multiplies a quaternion about a matrix. The
933 * resulting vector is returned.
936 * vec to multiply against.
938 * a quaternion to store the result in. created if null is passed.
939 * @return store = this * vec
941 public Quaternion mult(Quaternion vec, Quaternion store) {
944 logger.warning("Source vector is null, null result returned.");
947 if (store == null) store = new Quaternion();
949 float x = m00 * vec.x + m10 * vec.y + m20 * vec.z + m30 * vec.w;
950 float y = m01 * vec.x + m11 * vec.y + m21 * vec.z + m31 * vec.w;
951 float z = m02 * vec.x + m12 * vec.y + m22 * vec.z + m32 * vec.w;
952 float w = m03 * vec.x + m13 * vec.y + m23 * vec.z + m33 * vec.w;
962 * <code>mult</code> multiplies an array of 4 floats against this rotation
963 * matrix. The results are stored directly in the array. (vec4f x mat4f)
966 * float array (size 4) to multiply against the matrix.
967 * @return the vec4f for chaining.
969 public float[] mult(float[] vec4f) {
970 if (null == vec4f || vec4f.length != 4) {
971 logger.warning("invalid array given, must be nonnull and length 4");
975 float x = vec4f[0], y = vec4f[1], z = vec4f[2], w = vec4f[3];
977 vec4f[0] = m00 * x + m01 * y + m02 * z + m03 * w;
978 vec4f[1] = m10 * x + m11 * y + m12 * z + m13 * w;
979 vec4f[2] = m20 * x + m21 * y + m22 * z + m23 * w;
980 vec4f[3] = m30 * x + m31 * y + m32 * z + m33 * w;
986 * <code>mult</code> multiplies an array of 4 floats against this rotation
987 * matrix. The results are stored directly in the array. (vec4f x mat4f)
990 * float array (size 4) to multiply against the matrix.
991 * @return the vec4f for chaining.
993 public float[] multAcross(float[] vec4f) {
994 if (null == vec4f || vec4f.length != 4) {
995 logger.warning("invalid array given, must be nonnull and length 4");
999 float x = vec4f[0], y = vec4f[1], z = vec4f[2], w = vec4f[3];
1001 vec4f[0] = m00 * x + m10 * y + m20 * z + m30 * w;
1002 vec4f[1] = m01 * x + m11 * y + m21 * z + m31 * w;
1003 vec4f[2] = m02 * x + m12 * y + m22 * z + m32 * w;
1004 vec4f[3] = m03 * x + m13 * y + m23 * z + m33 * w;
1010 * Inverts this matrix as a new Matrix4f.
1012 * @return The new inverse matrix
1014 public Matrix4f invert() {
1015 return invert(null);
1019 * Inverts this matrix and stores it in the given store.
1023 public Matrix4f invert(Matrix4f store) {
1024 if (store == null) store = new Matrix4f();
1026 float fA0 = m00*m11 - m01*m10;
1027 float fA1 = m00*m12 - m02*m10;
1028 float fA2 = m00*m13 - m03*m10;
1029 float fA3 = m01*m12 - m02*m11;
1030 float fA4 = m01*m13 - m03*m11;
1031 float fA5 = m02*m13 - m03*m12;
1032 float fB0 = m20*m31 - m21*m30;
1033 float fB1 = m20*m32 - m22*m30;
1034 float fB2 = m20*m33 - m23*m30;
1035 float fB3 = m21*m32 - m22*m31;
1036 float fB4 = m21*m33 - m23*m31;
1037 float fB5 = m22*m33 - m23*m32;
1038 float fDet = fA0*fB5-fA1*fB4+fA2*fB3+fA3*fB2-fA4*fB1+fA5*fB0;
1040 if ( FastMath.abs(fDet) <= FastMath.FLT_EPSILON )
1041 throw new ArithmeticException("This matrix cannot be inverted");
1043 store.m00 = + m11*fB5 - m12*fB4 + m13*fB3;
1044 store.m10 = - m10*fB5 + m12*fB2 - m13*fB1;
1045 store.m20 = + m10*fB4 - m11*fB2 + m13*fB0;
1046 store.m30 = - m10*fB3 + m11*fB1 - m12*fB0;
1047 store.m01 = - m01*fB5 + m02*fB4 - m03*fB3;
1048 store.m11 = + m00*fB5 - m02*fB2 + m03*fB1;
1049 store.m21 = - m00*fB4 + m01*fB2 - m03*fB0;
1050 store.m31 = + m00*fB3 - m01*fB1 + m02*fB0;
1051 store.m02 = + m31*fA5 - m32*fA4 + m33*fA3;
1052 store.m12 = - m30*fA5 + m32*fA2 - m33*fA1;
1053 store.m22 = + m30*fA4 - m31*fA2 + m33*fA0;
1054 store.m32 = - m30*fA3 + m31*fA1 - m32*fA0;
1055 store.m03 = - m21*fA5 + m22*fA4 - m23*fA3;
1056 store.m13 = + m20*fA5 - m22*fA2 + m23*fA1;
1057 store.m23 = - m20*fA4 + m21*fA2 - m23*fA0;
1058 store.m33 = + m20*fA3 - m21*fA1 + m22*fA0;
1060 float fInvDet = 1.0f/fDet;
1061 store.multLocal(fInvDet);
1067 * Inverts this matrix locally.
1071 public Matrix4f invertLocal() {
1073 float fA0 = m00*m11 - m01*m10;
1074 float fA1 = m00*m12 - m02*m10;
1075 float fA2 = m00*m13 - m03*m10;
1076 float fA3 = m01*m12 - m02*m11;
1077 float fA4 = m01*m13 - m03*m11;
1078 float fA5 = m02*m13 - m03*m12;
1079 float fB0 = m20*m31 - m21*m30;
1080 float fB1 = m20*m32 - m22*m30;
1081 float fB2 = m20*m33 - m23*m30;
1082 float fB3 = m21*m32 - m22*m31;
1083 float fB4 = m21*m33 - m23*m31;
1084 float fB5 = m22*m33 - m23*m32;
1085 float fDet = fA0*fB5-fA1*fB4+fA2*fB3+fA3*fB2-fA4*fB1+fA5*fB0;
1087 if ( FastMath.abs(fDet) <= FastMath.FLT_EPSILON )
1090 float f00 = + m11*fB5 - m12*fB4 + m13*fB3;
1091 float f10 = - m10*fB5 + m12*fB2 - m13*fB1;
1092 float f20 = + m10*fB4 - m11*fB2 + m13*fB0;
1093 float f30 = - m10*fB3 + m11*fB1 - m12*fB0;
1094 float f01 = - m01*fB5 + m02*fB4 - m03*fB3;
1095 float f11 = + m00*fB5 - m02*fB2 + m03*fB1;
1096 float f21 = - m00*fB4 + m01*fB2 - m03*fB0;
1097 float f31 = + m00*fB3 - m01*fB1 + m02*fB0;
1098 float f02 = + m31*fA5 - m32*fA4 + m33*fA3;
1099 float f12 = - m30*fA5 + m32*fA2 - m33*fA1;
1100 float f22 = + m30*fA4 - m31*fA2 + m33*fA0;
1101 float f32 = - m30*fA3 + m31*fA1 - m32*fA0;
1102 float f03 = - m21*fA5 + m22*fA4 - m23*fA3;
1103 float f13 = + m20*fA5 - m22*fA2 + m23*fA1;
1104 float f23 = - m20*fA4 + m21*fA2 - m23*fA0;
1105 float f33 = + m20*fA3 - m21*fA1 + m22*fA0;
1124 float fInvDet = 1.0f/fDet;
1131 * Returns a new matrix representing the adjoint of this matrix.
1133 * @return The adjoint matrix
1135 public Matrix4f adjoint() {
1136 return adjoint(null);
1141 * Places the adjoint of this matrix in store (creates store if null.)
1144 * The matrix to store the result in. If null, a new matrix is created.
1147 public Matrix4f adjoint(Matrix4f store) {
1148 if (store == null) store = new Matrix4f();
1150 float fA0 = m00*m11 - m01*m10;
1151 float fA1 = m00*m12 - m02*m10;
1152 float fA2 = m00*m13 - m03*m10;
1153 float fA3 = m01*m12 - m02*m11;
1154 float fA4 = m01*m13 - m03*m11;
1155 float fA5 = m02*m13 - m03*m12;
1156 float fB0 = m20*m31 - m21*m30;
1157 float fB1 = m20*m32 - m22*m30;
1158 float fB2 = m20*m33 - m23*m30;
1159 float fB3 = m21*m32 - m22*m31;
1160 float fB4 = m21*m33 - m23*m31;
1161 float fB5 = m22*m33 - m23*m32;
1163 store.m00 = + m11*fB5 - m12*fB4 + m13*fB3;
1164 store.m10 = - m10*fB5 + m12*fB2 - m13*fB1;
1165 store.m20 = + m10*fB4 - m11*fB2 + m13*fB0;
1166 store.m30 = - m10*fB3 + m11*fB1 - m12*fB0;
1167 store.m01 = - m01*fB5 + m02*fB4 - m03*fB3;
1168 store.m11 = + m00*fB5 - m02*fB2 + m03*fB1;
1169 store.m21 = - m00*fB4 + m01*fB2 - m03*fB0;
1170 store.m31 = + m00*fB3 - m01*fB1 + m02*fB0;
1171 store.m02 = + m31*fA5 - m32*fA4 + m33*fA3;
1172 store.m12 = - m30*fA5 + m32*fA2 - m33*fA1;
1173 store.m22 = + m30*fA4 - m31*fA2 + m33*fA0;
1174 store.m32 = - m30*fA3 + m31*fA1 - m32*fA0;
1175 store.m03 = - m21*fA5 + m22*fA4 - m23*fA3;
1176 store.m13 = + m20*fA5 - m22*fA2 + m23*fA1;
1177 store.m23 = - m20*fA4 + m21*fA2 - m23*fA0;
1178 store.m33 = + m20*fA3 - m21*fA1 + m22*fA0;
1184 * <code>determinant</code> generates the determinate of this matrix.
1186 * @return the determinate
1188 public float determinant() {
1189 float fA0 = m00*m11 - m01*m10;
1190 float fA1 = m00*m12 - m02*m10;
1191 float fA2 = m00*m13 - m03*m10;
1192 float fA3 = m01*m12 - m02*m11;
1193 float fA4 = m01*m13 - m03*m11;
1194 float fA5 = m02*m13 - m03*m12;
1195 float fB0 = m20*m31 - m21*m30;
1196 float fB1 = m20*m32 - m22*m30;
1197 float fB2 = m20*m33 - m23*m30;
1198 float fB3 = m21*m32 - m22*m31;
1199 float fB4 = m21*m33 - m23*m31;
1200 float fB5 = m22*m33 - m23*m32;
1201 float fDet = fA0*fB5-fA1*fB4+fA2*fB3+fA3*fB2-fA4*fB1+fA5*fB0;
1206 * Sets all of the values in this matrix to zero.
1208 * @return this matrix
1210 public Matrix4f zero() {
1211 m00 = m01 = m02 = m03 = 0.0f;
1212 m10 = m11 = m12 = m13 = 0.0f;
1213 m20 = m21 = m22 = m23 = 0.0f;
1214 m30 = m31 = m32 = m33 = 0.0f;
1218 public Matrix4f add(Matrix4f mat) {
1219 Matrix4f result = new Matrix4f();
1220 result.m00 = this.m00 + mat.m00;
1221 result.m01 = this.m01 + mat.m01;
1222 result.m02 = this.m02 + mat.m02;
1223 result.m03 = this.m03 + mat.m03;
1224 result.m10 = this.m10 + mat.m10;
1225 result.m11 = this.m11 + mat.m11;
1226 result.m12 = this.m12 + mat.m12;
1227 result.m13 = this.m13 + mat.m13;
1228 result.m20 = this.m20 + mat.m20;
1229 result.m21 = this.m21 + mat.m21;
1230 result.m22 = this.m22 + mat.m22;
1231 result.m23 = this.m23 + mat.m23;
1232 result.m30 = this.m30 + mat.m30;
1233 result.m31 = this.m31 + mat.m31;
1234 result.m32 = this.m32 + mat.m32;
1235 result.m33 = this.m33 + mat.m33;
1240 * <code>add</code> adds the values of a parameter matrix to this matrix.
1243 * the matrix to add to this.
1245 public void addLocal(Matrix4f mat) {
1264 public Vector3f toTranslationVector() {
1265 return new Vector3f(m03, m13, m23);
1268 public void toTranslationVector(Vector3f vector) {
1269 vector.set(m03, m13, m23);
1272 public Quaternion toRotationQuat() {
1273 Quaternion quat = new Quaternion();
1274 quat.fromRotationMatrix(toRotationMatrix());
1278 public void toRotationQuat(Quaternion q) {
1279 q.fromRotationMatrix(toRotationMatrix());
1282 public Matrix3f toRotationMatrix() {
1283 return new Matrix3f(m00, m01, m02, m10, m11, m12, m20, m21, m22);
1287 public void toRotationMatrix(Matrix3f mat) {
1301 * <code>setTranslation</code> will set the matrix's translation values.
1303 * @param translation
1304 * the new values for the translation.
1305 * @throws JmeException
1306 * if translation is not size 3.
1308 public void setTranslation(float[] translation) {
1309 if (translation.length != 3) { throw new JmeException(
1310 "Translation size must be 3."); }
1311 m03 = translation[0];
1312 m13 = translation[1];
1313 m23 = translation[2];
1317 * <code>setTranslation</code> will set the matrix's translation values.
1320 * value of the translation on the x axis
1322 * value of the translation on the y axis
1324 * value of the translation on the z axis
1326 public void setTranslation(float x, float y, float z) {
1333 * <code>setTranslation</code> will set the matrix's translation values.
1335 * @param translation
1336 * the new values for the translation.
1338 public void setTranslation(Vector3f translation) {
1339 m03 = translation.x;
1340 m13 = translation.y;
1341 m23 = translation.z;
1345 * <code>setInverseTranslation</code> will set the matrix's inverse
1346 * translation values.
1348 * @param translation
1349 * the new values for the inverse translation.
1350 * @throws JmeException
1351 * if translation is not size 3.
1353 public void setInverseTranslation(float[] translation) {
1354 if (translation.length != 3) { throw new JmeException(
1355 "Translation size must be 3."); }
1356 m03 = -translation[0];
1357 m13 = -translation[1];
1358 m23 = -translation[2];
1362 * <code>angleRotation</code> sets this matrix to that of a rotation about
1363 * three axes (x, y, z). Where each axis has a specified rotation in
1364 * degrees. These rotations are expressed in a single <code>Vector3f</code>
1368 * the angles to rotate.
1370 public void angleRotation(Vector3f angles) {
1372 float sr, sp, sy, cr, cp, cy;
1374 angle = (angles.z * FastMath.DEG_TO_RAD);
1375 sy = FastMath.sin(angle);
1376 cy = FastMath.cos(angle);
1377 angle = (angles.y * FastMath.DEG_TO_RAD);
1378 sp = FastMath.sin(angle);
1379 cp = FastMath.cos(angle);
1380 angle = (angles.x * FastMath.DEG_TO_RAD);
1381 sr = FastMath.sin(angle);
1382 cr = FastMath.cos(angle);
1384 // matrix = (Z * Y) * X
1388 m01 = sr * sp * cy + cr * -sy;
1389 m11 = sr * sp * sy + cr * cy;
1391 m02 = (cr * sp * cy + -sr * -sy);
1392 m12 = (cr * sp * sy + -sr * cy);
1400 * <code>setRotationQuaternion</code> builds a rotation from a
1401 * <code>Quaternion</code>.
1404 * the quaternion to build the rotation from.
1405 * @throws NullPointerException
1408 public void setRotationQuaternion(Quaternion quat) {
1409 quat.toRotationMatrix(this);
1413 * <code>setInverseRotationRadians</code> builds an inverted rotation from
1414 * Euler angles that are in radians.
1417 * the Euler angles in radians.
1418 * @throws JmeException
1419 * if angles is not size 3.
1421 public void setInverseRotationRadians(float[] angles) {
1422 if (angles.length != 3) { throw new JmeException(
1423 "Angles must be of size 3."); }
1424 double cr = FastMath.cos(angles[0]);
1425 double sr = FastMath.sin(angles[0]);
1426 double cp = FastMath.cos(angles[1]);
1427 double sp = FastMath.sin(angles[1]);
1428 double cy = FastMath.cos(angles[2]);
1429 double sy = FastMath.sin(angles[2]);
1431 m00 = (float) (cp * cy);
1432 m10 = (float) (cp * sy);
1433 m20 = (float) (-sp);
1435 double srsp = sr * sp;
1436 double crsp = cr * sp;
1438 m01 = (float) (srsp * cy - cr * sy);
1439 m11 = (float) (srsp * sy + cr * cy);
1440 m21 = (float) (sr * cp);
1442 m02 = (float) (crsp * cy + sr * sy);
1443 m12 = (float) (crsp * sy - sr * cy);
1444 m22 = (float) (cr * cp);
1448 * <code>setInverseRotationDegrees</code> builds an inverted rotation from
1449 * Euler angles that are in degrees.
1452 * the Euler angles in degrees.
1453 * @throws JmeException
1454 * if angles is not size 3.
1456 public void setInverseRotationDegrees(float[] angles) {
1457 if (angles.length != 3) { throw new JmeException(
1458 "Angles must be of size 3."); }
1459 float vec[] = new float[3];
1460 vec[0] = (angles[0] * FastMath.RAD_TO_DEG);
1461 vec[1] = (angles[1] * FastMath.RAD_TO_DEG);
1462 vec[2] = (angles[2] * FastMath.RAD_TO_DEG);
1463 setInverseRotationRadians(vec);
1468 * <code>inverseTranslateVect</code> translates a given Vector3f by the
1469 * translation part of this matrix.
1472 * the Vector3f data to be translated.
1473 * @throws JmeException
1474 * if the size of the Vector3f is not 3.
1476 public void inverseTranslateVect(float[] vec) {
1477 if (vec.length != 3) { throw new JmeException(
1478 "vec must be of size 3."); }
1480 vec[0] = vec[0] - m03;
1481 vec[1] = vec[1] - m13;
1482 vec[2] = vec[2] - m23;
1487 * <code>inverseTranslateVect</code> translates a given Vector3f by the
1488 * translation part of this matrix.
1491 * the Vector3f to be translated.
1492 * @throws JmeException
1493 * if the size of the Vector3f is not 3.
1495 public void inverseTranslateVect(Vector3f data) {
1503 * <code>inverseTranslateVect</code> translates a given Vector3f by the
1504 * translation part of this matrix.
1507 * the Vector3f to be translated.
1508 * @throws JmeException
1509 * if the size of the Vector3f is not 3.
1511 public void translateVect(Vector3f data) {
1519 * <code>inverseRotateVect</code> rotates a given Vector3f by the rotation
1520 * part of this matrix.
1523 * the Vector3f to be rotated.
1525 public void inverseRotateVect(Vector3f vec) {
1526 float vx = vec.x, vy = vec.y, vz = vec.z;
1528 vec.x = vx * m00 + vy * m10 + vz * m20;
1529 vec.y = vx * m01 + vy * m11 + vz * m21;
1530 vec.z = vx * m02 + vy * m12 + vz * m22;
1533 public void rotateVect(Vector3f vec) {
1534 float vx = vec.x, vy = vec.y, vz = vec.z;
1536 vec.x = vx * m00 + vy * m01 + vz * m02;
1537 vec.y = vx * m10 + vy * m11 + vz * m12;
1538 vec.z = vx * m20 + vy * m21 + vz * m22;
1542 * <code>toString</code> returns the string representation of this object.
1543 * It is in a format of a 4x4 matrix. For example, an identity matrix would
1544 * be represented by the following string. com.jme.math.Matrix3f <br>[<br>
1545 * 1.0 0.0 0.0 0.0 <br>
1546 * 0.0 1.0 0.0 0.0 <br>
1547 * 0.0 0.0 1.0 0.0 <br>
1548 * 0.0 0.0 0.0 1.0 <br>]<br>
1550 * @return the string representation of this object.
1552 public String toString() {
1553 StringBuffer result = new StringBuffer("com.jme.math.Matrix4f\n[\n");
1562 result.append(" \n");
1571 result.append(" \n");
1580 result.append(" \n");
1589 result.append(" \n]");
1590 return result.toString();
1595 * <code>hashCode</code> returns the hash code value as an integer and is
1596 * supported for the benefit of hashing based collection classes such as
1597 * Hashtable, HashMap, HashSet etc.
1599 * @return the hashcode for this instance of Matrix4f.
1600 * @see java.lang.Object#hashCode()
1602 public int hashCode() {
1604 hash = 37 * hash + Float.floatToIntBits(m00);
1605 hash = 37 * hash + Float.floatToIntBits(m01);
1606 hash = 37 * hash + Float.floatToIntBits(m02);
1607 hash = 37 * hash + Float.floatToIntBits(m03);
1609 hash = 37 * hash + Float.floatToIntBits(m10);
1610 hash = 37 * hash + Float.floatToIntBits(m11);
1611 hash = 37 * hash + Float.floatToIntBits(m12);
1612 hash = 37 * hash + Float.floatToIntBits(m13);
1614 hash = 37 * hash + Float.floatToIntBits(m20);
1615 hash = 37 * hash + Float.floatToIntBits(m21);
1616 hash = 37 * hash + Float.floatToIntBits(m22);
1617 hash = 37 * hash + Float.floatToIntBits(m23);
1619 hash = 37 * hash + Float.floatToIntBits(m30);
1620 hash = 37 * hash + Float.floatToIntBits(m31);
1621 hash = 37 * hash + Float.floatToIntBits(m32);
1622 hash = 37 * hash + Float.floatToIntBits(m33);
1628 * are these two matrices the same? they are is they both have the same mXX values.
1631 * the object to compare for equality
1632 * @return true if they are equal
1634 public boolean equals(Object o) {
1635 if (!(o instanceof Matrix4f) || o == null) {
1643 Matrix4f comp = (Matrix4f) o;
1644 if (Float.compare(m00,comp.m00) != 0) return false;
1645 if (Float.compare(m01,comp.m01) != 0) return false;
1646 if (Float.compare(m02,comp.m02) != 0) return false;
1647 if (Float.compare(m03,comp.m03) != 0) return false;
1649 if (Float.compare(m10,comp.m10) != 0) return false;
1650 if (Float.compare(m11,comp.m11) != 0) return false;
1651 if (Float.compare(m12,comp.m12) != 0) return false;
1652 if (Float.compare(m13,comp.m13) != 0) return false;
1654 if (Float.compare(m20,comp.m20) != 0) return false;
1655 if (Float.compare(m21,comp.m21) != 0) return false;
1656 if (Float.compare(m22,comp.m22) != 0) return false;
1657 if (Float.compare(m23,comp.m23) != 0) return false;
1659 if (Float.compare(m30,comp.m30) != 0) return false;
1660 if (Float.compare(m31,comp.m31) != 0) return false;
1661 if (Float.compare(m32,comp.m32) != 0) return false;
1662 if (Float.compare(m33,comp.m33) != 0) return false;
1667 public void write(JMEExporter e) throws IOException {
1668 OutputCapsule cap = e.getCapsule(this);
1669 cap.write(m00, "m00", 1);
1670 cap.write(m01, "m01", 0);
1671 cap.write(m02, "m02", 0);
1672 cap.write(m03, "m03", 0);
1673 cap.write(m10, "m10", 0);
1674 cap.write(m11, "m11", 1);
1675 cap.write(m12, "m12", 0);
1676 cap.write(m13, "m13", 0);
1677 cap.write(m20, "m20", 0);
1678 cap.write(m21, "m21", 0);
1679 cap.write(m22, "m22", 1);
1680 cap.write(m23, "m23", 0);
1681 cap.write(m30, "m30", 0);
1682 cap.write(m31, "m31", 0);
1683 cap.write(m32, "m32", 0);
1684 cap.write(m33, "m33", 1);
1687 public void read(JMEImporter e) throws IOException {
1688 InputCapsule cap = e.getCapsule(this);
1689 m00 = cap.readFloat("m00", 1);
1690 m01 = cap.readFloat("m01", 0);
1691 m02 = cap.readFloat("m02", 0);
1692 m03 = cap.readFloat("m03", 0);
1693 m10 = cap.readFloat("m10", 0);
1694 m11 = cap.readFloat("m11", 1);
1695 m12 = cap.readFloat("m12", 0);
1696 m13 = cap.readFloat("m13", 0);
1697 m20 = cap.readFloat("m20", 0);
1698 m21 = cap.readFloat("m21", 0);
1699 m22 = cap.readFloat("m22", 1);
1700 m23 = cap.readFloat("m23", 0);
1701 m30 = cap.readFloat("m30", 0);
1702 m31 = cap.readFloat("m31", 0);
1703 m32 = cap.readFloat("m32", 0);
1704 m33 = cap.readFloat("m33", 1);
1707 public Class<? extends Matrix4f> getClassTag() {
1708 return this.getClass();
1712 * @return true if this matrix is identity
1714 public boolean isIdentity() {
1716 (m00 == 1 && m01 == 0 && m02 == 0 && m03 == 0) &&
1717 (m10 == 0 && m11 == 1 && m12 == 0 && m13 == 0) &&
1718 (m20 == 0 && m21 == 0 && m22 == 1 && m23 == 0) &&
1719 (m30 == 0 && m31 == 0 && m32 == 0 && m33 == 1);
1723 * Apply a scale to this matrix.
1726 * the scale to apply
1728 public void scale(Vector3f scale) {
1729 m00 *= scale.getX();
1730 m10 *= scale.getX();
1731 m20 *= scale.getX();
1732 m30 *= scale.getX();
1733 m01 *= scale.getY();
1734 m11 *= scale.getY();
1735 m21 *= scale.getY();
1736 m31 *= scale.getY();
1737 m02 *= scale.getZ();
1738 m12 *= scale.getZ();
1739 m22 *= scale.getZ();
1740 m32 *= scale.getZ();
1743 static final boolean equalIdentity(Matrix4f mat) {
1744 if (Math.abs(mat.m00 - 1) > 1e-4) return false;
1745 if (Math.abs(mat.m11 - 1) > 1e-4) return false;
1746 if (Math.abs(mat.m22 - 1) > 1e-4) return false;
1747 if (Math.abs(mat.m33 - 1) > 1e-4) return false;
1749 if (Math.abs(mat.m01) > 1e-4) return false;
1750 if (Math.abs(mat.m02) > 1e-4) return false;
1751 if (Math.abs(mat.m03) > 1e-4) return false;
1753 if (Math.abs(mat.m10) > 1e-4) return false;
1754 if (Math.abs(mat.m12) > 1e-4) return false;
1755 if (Math.abs(mat.m13) > 1e-4) return false;
1757 if (Math.abs(mat.m20) > 1e-4) return false;
1758 if (Math.abs(mat.m21) > 1e-4) return false;
1759 if (Math.abs(mat.m23) > 1e-4) return false;
1761 if (Math.abs(mat.m30) > 1e-4) return false;
1762 if (Math.abs(mat.m31) > 1e-4) return false;
1763 if (Math.abs(mat.m32) > 1e-4) return false;
1768 // XXX: This tests more solid than converting the q to a matrix and multiplying... why?
1769 public void multLocal(Quaternion rotation) {
1770 Vector3f axis = new Vector3f();
1771 float angle = rotation.toAngleAxis(axis);
1772 Matrix4f matrix4f = new Matrix4f();
1773 matrix4f.fromAngleAxis(angle, axis);
1774 multLocal(matrix4f);
1778 public Matrix4f clone() {
1780 return (Matrix4f) super.clone();
1781 } catch (CloneNotSupportedException e) {
1782 throw new AssertionError(); // can not happen