Subversion Repositories AndroidProjects

Rev

Rev 784 | Blame | Compare with Previous | Last modification | View Log | RSS feed

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace BauzoidNET.math
{
    public class Matrix4
    {
            public const int M11 = 0;
            public const int M21 = 1;
            public const int M31 = 2;
            public const int M41 = 3;
            public const int M12 = 4;
            public const int M22 = 5;
            public const int M32 = 6;
            public const int M42 = 7;
            public const int M13 = 8;
            public const int M23 = 9;
            public const int M33 = 10;
            public const int M43 = 11;
            public const int M14 = 12;
            public const int M24 = 13;
            public const int M34 = 14;
            public const int M44 = 15;
       
            public const int MATRIX_SIZE = 4;
       
            public float[] values = new float[MATRIX_SIZE*MATRIX_SIZE];
       
            public Matrix4()
            {
            }
       
            /** Copy constructor. */
            public Matrix4(Matrix4 b)
            {
                    for (int i = 0; i < values.Length; i++)
                            this.values[i] = b.values[i];
            }
       
            public Matrix4(float[] m)
            {
            for (int i = 0; i < values.Length; i++)
                            this.values[i] = m[i];
            }
       
            public float get(int row, int col)
            {
                    return values[col*MATRIX_SIZE + row];
            }
       
            public void set(int row, int col, float value)
            {
                    values[col*MATRIX_SIZE + row] = value;
            }
       
            public void zero()
            {
            for (int i = 0; i < values.Length; i++)
                            values[i] = 0.0f;
        }
       
            public void identity()
            {
                    zero();
                    values[M11] = 1.0f; values[M22] = 1.0f; values[M33] = 1.0f; values[M44] = 1.0f;
            }
       
            public bool equals(Matrix4 other)
            {
            for (int i = 0; i < values.Length; i++)
                    {
                            if (this.values[i] != other.values[i])
                                    return false;
                    }
                    return true;
            }
       
            public bool isSingular()
        {
            float determinant = getDeterminant();
            return ((float)Math.Abs(determinant) < MathUtil.EPSILON);
        }
       
            public Matrix4 getTranspose()
            {
                    Matrix4 result = new Matrix4();
               
                    for (int row = 0; row < MATRIX_SIZE; row++)
                    {
                            for (int col = 0; col < MATRIX_SIZE; col++)
                            {
                                    float v = this.get(row, col);
                                    this.set(col, row, v);
                            }
                    }

                    return result;
            }
       
            public float getDeterminant()
            {
               
            float result =
                    values[M14] * values[M23] * values[M32] * values[M41] -
                    values[M13] * values[M24] * values[M32] * values[M41] -
                    values[M14] * values[M22] * values[M33] * values[M41] +
                    values[M12] * values[M24] * values[M33] * values[M41] +
                    values[M13] * values[M22] * values[M34] * values[M41] -
                    values[M12] * values[M23] * values[M34] * values[M41] -
                    values[M14] * values[M23] * values[M31] * values[M42] +
                    values[M13] * values[M24] * values[M31] * values[M42] +
                    values[M14] * values[M21] * values[M33] * values[M42] -
                    values[M11] * values[M24] * values[M33] * values[M42] -
                    values[M13] * values[M21] * values[M34] * values[M42] +
                    values[M11] * values[M23] * values[M34] * values[M42] +
                    values[M14] * values[M22] * values[M31] * values[M43] -
                    values[M12] * values[M24] * values[M31] * values[M43] -
                    values[M14] * values[M21] * values[M32] * values[M43] +
                    values[M11] * values[M24] * values[M32] * values[M43] +
                    values[M12] * values[M21] * values[M34] * values[M43] -
                    values[M11] * values[M22] * values[M34] * values[M43] -
                    values[M13] * values[M22] * values[M31] * values[M44] +
                    values[M12] * values[M23] * values[M31] * values[M44] +
                    values[M13] * values[M21] * values[M32] * values[M44] -
                    values[M11] * values[M23] * values[M32] * values[M44] -
                    values[M12] * values[M21] * values[M33] * values[M44] +
                    values[M11] * values[M22] * values[M33] * values[M44];
            return result;
            }
       
            public Matrix4 getInverse()
            {
                    Matrix4 result = new Matrix4();
               
                    float determinant = getDeterminant();
                    if (determinant == 0.0f)
                    {
                            // singular matrix cannot be inverted
                            return this;
                    }
               
            result.values[M11] = values[M23] * values[M34] * values[M42]
                            - values[M24] * values[M33] * values[M42]
                            + values[M24] * values[M32] * values[M43]
                            - values[M22] * values[M34] * values[M43]
                            - values[M23] * values[M32] * values[M44]
                            + values[M22] * values[M33] * values[M44];
                    result.values[M12] = values[M14] * values[M33] * values[M42]
                            - values[M13] * values[M34] * values[M42]
                            - values[M14] * values[M32] * values[M43]
                            + values[M12] * values[M34] * values[M43]
                            + values[M13] * values[M32] * values[M44]
                            - values[M12] * values[M33] * values[M44];
                    result.values[M13] = values[M13] * values[M24] * values[M42]
                            - values[M14] * values[M23] * values[M42]
                            + values[M14] * values[M22] * values[M43]
                            - values[M12] * values[M24] * values[M43]
                            - values[M13] * values[M22] * values[M44]
                            + values[M12] * values[M23] * values[M44];
                    result.values[M14] = values[M14] * values[M23] * values[M32]
                            - values[M13] * values[M24] * values[M32]
                            - values[M14] * values[M22] * values[M33]
                            + values[M12] * values[M24] * values[M33]
                            + values[M13] * values[M22] * values[M34]
                            - values[M12] * values[M23] * values[M34];
                    result.values[M21] = values[M24] * values[M33] * values[M41]
                            - values[M23] * values[M34] * values[M41]
                            - values[M24] * values[M31] * values[M43]
                            + values[M21] * values[M34] * values[M43]
                            + values[M23] * values[M31] * values[M44]
                            - values[M21] * values[M33] * values[M44];
                    result.values[M22] = values[M13] * values[M34] * values[M41]
                            - values[M14] * values[M33] * values[M41]
                            + values[M14] * values[M31] * values[M43]
                            - values[M11] * values[M34] * values[M43]
                            - values[M13] * values[M31] * values[M44]
                            + values[M11] * values[M33] * values[M44];
                    result.values[M23] = values[M14] * values[M23] * values[M41]
                            - values[M13] * values[M24] * values[M41]
                            - values[M14] * values[M21] * values[M43]
                            + values[M11] * values[M24] * values[M43]
                            + values[M13] * values[M21] * values[M44]
                            - values[M11] * values[M23] * values[M44];
                    result.values[M24] = values[M13] * values[M24] * values[M31]
                            - values[M14] * values[M23] * values[M31]
                            + values[M14] * values[M21] * values[M33]
                            - values[M11] * values[M24] * values[M33]
                            - values[M13] * values[M21] * values[M34]
                            + values[M11] * values[M23] * values[M34];
                    result.values[M31] = values[M22] * values[M34] * values[M41]
                            - values[M24] * values[M32] * values[M41]
                            + values[M24] * values[M31] * values[M42]
                            - values[M21] * values[M34] * values[M42]
                            - values[M22] * values[M31] * values[M44]
                            + values[M21] * values[M32] * values[M44];
                    result.values[M32] = values[M14] * values[M32] * values[M41]
                            - values[M12] * values[M34] * values[M41]
                            - values[M14] * values[M31] * values[M42]
                            + values[M11] * values[M34] * values[M42]
                            + values[M12] * values[M31] * values[M44]
                            - values[M11] * values[M32] * values[M44];
                    result.values[M33] = values[M12] * values[M24] * values[M41]
                            - values[M14] * values[M22] * values[M41]
                            + values[M14] * values[M21] * values[M42]
                            - values[M11] * values[M24] * values[M42]
                            - values[M12] * values[M21] * values[M44]
                            + values[M11] * values[M22] * values[M44];
                    result.values[M34] = values[M14] * values[M22] * values[M31]
                            - values[M12] * values[M24] * values[M31]
                            - values[M14] * values[M21] * values[M32]
                            + values[M11] * values[M24] * values[M32]
                            + values[M12] * values[M21] * values[M34]
                            - values[M11] * values[M22] * values[M34];
                    result.values[M41] = values[M23] * values[M32] * values[M41]
                            - values[M22] * values[M33] * values[M41]
                            - values[M23] * values[M31] * values[M42]
                            + values[M21] * values[M33] * values[M42]
                            + values[M22] * values[M31] * values[M43]
                            - values[M21] * values[M32] * values[M43];
                    result.values[M42] = values[M12] * values[M33] * values[M41]
                            - values[M13] * values[M32] * values[M41]
                            + values[M13] * values[M31] * values[M42]
                            - values[M11] * values[M33] * values[M42]
                            - values[M12] * values[M31] * values[M43]
                            + values[M11] * values[M32] * values[M43];
                    result.values[M43] = values[M13] * values[M22] * values[M41]
                            - values[M12] * values[M23] * values[M41]
                            - values[M13] * values[M21] * values[M42]
                            + values[M11] * values[M23] * values[M42]
                            + values[M12] * values[M21] * values[M43]
                            - values[M11] * values[M22] * values[M43];
                    result.values[M44] = values[M12] * values[M23] * values[M31]
                            - values[M13] * values[M22] * values[M31]
                            + values[M13] * values[M21] * values[M32]
                            - values[M11] * values[M23] * values[M32]
                            - values[M12] * values[M21] * values[M33]
                            + values[M11] * values[M22] * values[M33];

                    float multiply = 1.0f / determinant;

            for (int i = 0; i < values.Length; i++)
                            result.values[i] *= multiply;

                    return result;
            }

            public void copyTo(Matrix4 target)
            {
            for (int i = 0; i < values.Length; i++)
                            target.values[i] = this.values[i];
            }
       
            public void copyFrom(Matrix4 source)
            {
            for (int i = 0; i < values.Length; i++)
                            this.values[i] = source.values[i];
            }
       
            public void postMultiply(Matrix4 v)
            {
                    multiply(this, this, v);
            }
       
            public void preMultiply(Matrix4 v)
            {
                    multiply(this, v, this);
            }
       
            static public void multiply(Matrix4 result, Matrix4 a, Matrix4 b)
            {
            float result11 = a.values[M11] * b.values[M11] + a.values[M21] * b.values[M12] + a.values[M31] * b.values[M13] + a.values[M41] * b.values[M14];
            float result21 = a.values[M11] * b.values[M21] + a.values[M21] * b.values[M22] + a.values[M31] * b.values[M23] + a.values[M41] * b.values[M24];
            float result31 = a.values[M11] * b.values[M31] + a.values[M21] * b.values[M32] + a.values[M31] * b.values[M33] + a.values[M41] * b.values[M34];
            float result41 = a.values[M11] * b.values[M41] + a.values[M21] * b.values[M42] + a.values[M31] * b.values[M43] + a.values[M41] * b.values[M44];
            float result12 = a.values[M12] * b.values[M11] + a.values[M22] * b.values[M12] + a.values[M32] * b.values[M13] + a.values[M42] * b.values[M14];
            float result22 = a.values[M12] * b.values[M21] + a.values[M22] * b.values[M22] + a.values[M32] * b.values[M23] + a.values[M42] * b.values[M24];
            float result32 = a.values[M12] * b.values[M31] + a.values[M22] * b.values[M32] + a.values[M32] * b.values[M33] + a.values[M42] * b.values[M34];
            float result42 = a.values[M12] * b.values[M41] + a.values[M22] * b.values[M42] + a.values[M32] * b.values[M43] + a.values[M42] * b.values[M44];
            float result13 = a.values[M13] * b.values[M11] + a.values[M23] * b.values[M12] + a.values[M33] * b.values[M13] + a.values[M43] * b.values[M14];
            float result23 = a.values[M13] * b.values[M21] + a.values[M23] * b.values[M22] + a.values[M33] * b.values[M23] + a.values[M43] * b.values[M24];
                    float result33 = a.values[M13] * b.values[M31] + a.values[M23] * b.values[M32] + a.values[M33] * b.values[M33] + a.values[M43] * b.values[M34];
                    float result43 = a.values[M13] * b.values[M41] + a.values[M23] * b.values[M42] + a.values[M33] * b.values[M43] + a.values[M43] * b.values[M44];
                    float result14 = a.values[M14] * b.values[M11] + a.values[M24] * b.values[M12] + a.values[M34] * b.values[M13] + a.values[M44] * b.values[M14];
                    float result24 = a.values[M14] * b.values[M21] + a.values[M24] * b.values[M22] + a.values[M34] * b.values[M23] + a.values[M44] * b.values[M24];
                    float result34 = a.values[M14] * b.values[M31] + a.values[M24] * b.values[M32] + a.values[M34] * b.values[M33] + a.values[M44] * b.values[M34];
                    float result44 = a.values[M14] * b.values[M41] + a.values[M24] * b.values[M42] + a.values[M34] * b.values[M43] + a.values[M44] * b.values[M44];
                    result.values[M11] = result11;
                    result.values[M21] = result21;
                    result.values[M31] = result31;
                    result.values[M41] = result41;
                    result.values[M12] = result12;
                    result.values[M22] = result22;
                    result.values[M32] = result32;
                    result.values[M42] = result42;
                    result.values[M13] = result13;
                    result.values[M23] = result23;
                    result.values[M33] = result33;
                    result.values[M43] = result43;
                    result.values[M14] = result14;
                    result.values[M24] = result24;
                    result.values[M34] = result34;
                    result.values[M44] = result44;
            }
       
            static public Matrix4 multiply(Matrix4 a, Matrix4 b)
            {
                    Matrix4 result = new Matrix4();
                    multiply(result, a, b);
                    return result;
            }
       
            public void multiply(Matrix4 other)
            {
                    Matrix4.multiply(this, this, other);
            }
       
            static public Matrix4 createIdentity()
            {
                    return createScale(1.0f, 1.0f, 1.0f);
            }
       
            static public Matrix4 createScale(float sx, float sy, float sz)
            {
                    Matrix4 result = new Matrix4();
                    result.setScale(sx, sy, sz);
                    return result;             
            }
       
            static public Matrix4 createScale(Vector3 scale)
            {
                    return createScale(scale.x, scale.y, scale.z);
            }
       
            static public Matrix4 createScale(float s)
            {
                    return createScale(s, s, s);
            }
       
            public void setScale(float sx, float sy, float sz)
            {
                    zero();
                    this.values[M11] = sx;
                    this.values[M22] = sy;
                    this.values[M33] = sz;
                    this.values[M44] = 1.0f;
            }
       
            public void setScale(Vector3 scale)
            {
                    setScale(scale.x, scale.y, scale.z);
            }
       
            public void setScale(float s)
            {
                    setScale(s, s, s);
            }
       
            static public Matrix4 createRotationX(float degrees)
            {
            Matrix4 matrix = new Matrix4();
            matrix.setRotationX(degrees);
            return matrix;
            }
       
            public void setRotationX(float degrees)
            {
                    float degreesrad = MathUtil.degToRad(degrees);
            float sinvalue = (float)Math.Sin(degreesrad);
            float cosvalue = (float)Math.Cos(degreesrad);

                    this.identity();
            this.values[M22] = cosvalue;
            this.values[M32] = -sinvalue;
            this.values[M23] = sinvalue;
            this.values[M33] = cosvalue;
            }
       
            static public Matrix4 createRotationY(float degrees)
            {
                    Matrix4 matrix = new Matrix4();
                    matrix.setRotationY(degrees);
            return matrix;
            }
       
            public void setRotationY(float degrees)
            {
            float degreesrad = MathUtil.degToRad(degrees);
            float sinvalue = (float)Math.Sin(degreesrad);
            float cosvalue = (float)Math.Cos(degreesrad);

            this.identity();
            this.values[M11] = cosvalue;
            this.values[M31] = sinvalue;
            this.values[M13] = -sinvalue;
            this.values[M33] = cosvalue;
            }
       
            static public Matrix4 createRotationZ(float degrees)
            {
                    Matrix4 matrix = new Matrix4();
                    matrix.setRotationZ(degrees);
            return matrix;
            }
       
            public void setRotationZ(float degrees)
            {
            float degreesrad = MathUtil.degToRad(degrees);
            float sinvalue = (float)Math.Sin(degreesrad);
            float cosvalue = (float)Math.Cos(degreesrad);

            this.identity();
            this.values[M11] = cosvalue;
            this.values[M21] = -sinvalue;
            this.values[M12] = sinvalue;
            this.values[M22] = cosvalue;
            }
       
            static public Matrix4 createRotation(Vector3 axis, float degrees)
            {
                    Matrix4 matrix = new Matrix4();
                    matrix.setRotation(axis, degrees);
            return matrix;
            }
       
            public void setRotation(Vector3 axis, float degrees)
            {
            float radangle = MathUtil.degToRad(degrees);
            float radcos = (float)Math.Cos(radangle);
            float radsin = (float)Math.Sin(radangle);

            this.identity();
            this.values[M11] = radcos + axis.x * axis.x * (1 - radcos);
            this.values[M21] = axis.z * radsin + axis.y * axis.x * (1 - radcos);
            this.values[M31] = -axis.y * radsin + axis.z * axis.x * (1 - radcos);
            this.values[M12] = -axis.z * radsin + axis.x * axis.y * (1 - radcos);
            this.values[M22] = radcos + axis.y * axis.y * (1 - radcos);
            this.values[M32] = axis.x * radsin + axis.z * axis.y * (1 - radcos);
            this.values[M13] = axis.y * radsin + axis.x * axis.z * (1 - radcos);
            this.values[M23] = -axis.x * radsin + axis.y * axis.z * (1 - radcos);
            this.values[M33] = radcos + axis.z * axis.z * (1 - radcos);
            this.values[M44] = 1.0f;
            }
       
            static public Matrix4 createTranslation(float x, float y, float z)
            {
                    Matrix4 result = new Matrix4();
                    result.setTranslation(x, y, z);
            return result;
            }
       
            static public Matrix4 createTranslation(Vector3 translate)
            {
                    return createTranslation(translate.x, translate.y, translate.z);
            }
       
            public void setTranslation(float x, float y, float z)
            {          
                    this.values[M11] = 1.0f; this.values[M21] = 0.0f; this.values[M31] = 0.0f; this.values[M41] = 0.0f;
                    this.values[M12] = 0.0f; this.values[M22] = 1.0f; this.values[M32] = 0.0f; this.values[M42] = 0.0f;
                    this.values[M13] = 0.0f; this.values[M23] = 0.0f; this.values[M33] = 1.0f; this.values[M43] = 0.0f;
                    this.values[M14] = x;    this.values[M24] = y;    this.values[M34] = z;    this.values[M44] = 1.0f;
            }
       
            public void setTranslation(Vector3 translate)
            {
                    setTranslation(translate.x, translate.y, translate.z);
            }
       
            static public Matrix4 createFromVectors(Vector3 forward, Vector3 up, Vector3 right)
            {
            forward.normalize();
            up.normalize();
            right.normalize();
       
            Matrix4 result = new Matrix4();
            result.setFromVectors(forward, up, right);        
            return result;
            }
       
            public void setFromVectors(Vector3 forward, Vector3 up, Vector3 right)
            {
            forward.normalize();
            up.normalize();
            right.normalize();
       
            identity();
       
            this.values[M11] = right.x;
            this.values[M12] = right.y;
            this.values[M13] = right.z;
            this.values[M21] = up.x;
            this.values[M22] = up.y;
            this.values[M23] = up.z;
            this.values[M31] = -forward.x;
            this.values[M32] = -forward.y;
            this.values[M33] = -forward.z;
            this.values[M44] = 1.0f;
            }
       
            static public Matrix4 createPerspective(float fovDegreesY, float aspect, float zNear, float zFar)
            {
                    Matrix4 result = new Matrix4();
                    result.setPerspective(fovDegreesY, aspect, zNear, zFar);
                    return result;
            }
       
            public void setPerspective(float fovDegreesY, float aspect, float zNear, float zFar)
            {
            float f = 1.0f / (float) Math.Tan(fovDegreesY * (Math.PI / 360.0));
            float rangeReciprocal = 1.0f / (zNear - zFar);
               
                    this.values[M11] = f / aspect;
                    this.values[M21] = 0.0f;
                    this.values[M31] = 0.0f;
                    this.values[M41] = 0.0f;
               
                    this.values[M12] = 0.0f;
                    this.values[M22] = f;
                    this.values[M32] = 0.0f;
                    this.values[M42] = 0.0f;
               
                    this.values[M13] = 0.0f;
                    this.values[M23] = 0.0f;
                    this.values[M33] = (zFar + zNear) * rangeReciprocal;
                    this.values[M43] = -1.0f;
               
                    this.values[M14] = 0.0f;
                    this.values[M24] = 0.0f;
                    this.values[M34] = 2.0f * zFar * zNear * rangeReciprocal;
                    this.values[M44] = 0.0f;
            }
       
            static public Matrix4 createFrustum(float left, float right, float bottom, float top, float near, float far)
            {
                    Matrix4 matrix = new Matrix4();
                    matrix.setFrustum(left, right, bottom, top, near, far);
                    return matrix;
            }
       
            public void setFrustum(float left, float right, float bottom, float top, float near, float far)
            {
            if (left == right)
            {
                throw new ArgumentException("left == right");
            }
            if (top == bottom)
            {
                throw new ArgumentException("top == bottom");
            }
            if (near == far)
            {
                throw new ArgumentException("near == far");
            }
            if (near <= 0.0f)
            {
                throw new ArgumentException("near <= 0.0f");
            }
            if (far <= 0.0f)
            {
                throw new ArgumentException("far <= 0.0f");
            }
       
            float r_width  = 1.0f / (right - left);
            float r_height = 1.0f / (top - bottom);
            float r_depth  = 1.0f / (near - far);
            float x = 2.0f * (near * r_width);
            float y = 2.0f * (near * r_height);
            float A = 2.0f * ((right + left) * r_width);
            float B = (top + bottom) * r_height;
            float C = (far + near) * r_depth;
            float D = 2.0f * (far * near * r_depth);
       
            this.values[M11] = x;
            this.values[M21] = 0.0f;
            this.values[M31] = 0.0f;
            this.values[M41] = 0.0f;
       
            this.values[M12] = 0.0f;
            this.values[M22] = y;
            this.values[M32] = 0.0f;
            this.values[M42] = 0.0f;
       
            this.values[M13] = A;
            this.values[M23] = B;
            this.values[M33] = C;
            this.values[M43] = -1.0f;
       
            this.values[M14] = 0.0f;
            this.values[M24] = 0.0f;
            this.values[M34] = D;
            this.values[M44] = 0.0f;
            }

            static public Matrix4 createOrtho(float left, float right, float bottom, float top, float near, float far)
            {
                    Matrix4 matrix = new Matrix4();
                    matrix.setOrtho(left, right, bottom, top, near, far);
                    return matrix;
            }
       
            public void setOrtho(float left, float right, float bottom, float top, float near, float far)
            {
                    if (left == right)
                throw new ArgumentException("left and right must not be identical!");
               
                    if (bottom == top)
                throw new ArgumentException("bottom and top must not be identical!");
               
                    if (near == far)
                throw new ArgumentException("near and far must not be identical!");
               
                    float r_width  = 1.0f / (right - left);
                    float r_height = 1.0f / (top - bottom);
                    float r_depth  = 1.0f / (far - near);
                    float x =  2.0f * (r_width);
                    float y =  2.0f * (r_height);
                    float z = -2.0f * (r_depth);
                    float tx = -(right + left) * r_width;
                    float ty = -(top + bottom) * r_height;
                    float tz = -(far + near) * r_depth;

                    this.values[M11] = x;               this.values[M21] = 0.0f;        this.values[M31] = 0.0f;        this.values[M41] = 0.0f;
                    this.values[M12] = 0.0f;    this.values[M22] = y;           this.values[M32] = 0.0f;        this.values[M42] = 0.0f;
                    this.values[M13] = 0.0f;    this.values[M23] = 0.0f;        this.values[M33] = z;           this.values[M43] = 0.0f;
                    this.values[M14] = tx;              this.values[M24] = ty;          this.values[M34] = tz;          this.values[M44] = 1.0f;
            }          

            static public Matrix4 createLookAt(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ)
            {
                    Matrix4 matrix = new Matrix4();
                    matrix.setLookAt(eyeX, eyeY, eyeZ, centerX, centerY, centerZ, upX, upY, upZ);
                    return matrix;
            }
       
            public void setLookAt(float eyeX, float eyeY, float eyeZ, float centerX, float centerY, float centerZ, float upX, float upY, float upZ)
            {
            float fx = centerX - eyeX;
            float fy = centerY - eyeY;
            float fz = centerZ - eyeZ;

            // Normalize f
            float rlf = 1.0f / Vector3.length(fx, fy, fz);
            fx *= rlf;
            fy *= rlf;
            fz *= rlf;

            // compute s = f x up (x means "cross product")
            float sx = fy * upZ - fz * upY;
            float sy = fz * upX - fx * upZ;
            float sz = fx * upY - fy * upX;

            // and normalize s
            float rls = 1.0f / Vector3.length(sx, sy, sz);
            sx *= rls;
            sy *= rls;
            sz *= rls;

            // compute u = s x f
            float ux = sy * fz - sz * fy;
            float uy = sz * fx - sx * fz;
            float uz = sx * fy - sy * fx;
       
            this.values[M11] = sx;
            this.values[M21] = ux;
            this.values[M31] = -fx;
            this.values[M41] = 0.0f;

            this.values[M12] = sy;
            this.values[M22] = uy;
            this.values[M32] = -fy;
            this.values[M42] = 0.0f;

            this.values[M13] = sz;
            this.values[M23] = uz;
            this.values[M33] = -fz;
            this.values[M43] = 0.0f;

            this.values[M14] = 0.0f;
            this.values[M24] = 0.0f;
            this.values[M34] = 0.0f;
            this.values[M44] = 1.0f;
       
            this.values[M14] = this.values[M11] * -eyeX + this.values[M12] * -eyeY + this.values[M13] * -eyeZ + this.values[M14];
            this.values[M24] = this.values[M21] * -eyeX + this.values[M22] * -eyeY + this.values[M23] * -eyeZ + this.values[M24];
            this.values[M34] = this.values[M31] * -eyeX + this.values[M32] * -eyeY + this.values[M33] * -eyeZ + this.values[M34];
            this.values[M44] = this.values[M41] * -eyeX + this.values[M42] * -eyeY + this.values[M43] * -eyeZ + this.values[M44];
            }
       
            public Vector3 transform(Vector3 vector)
            {
               
                    return new Vector3(
                    values[M11] * vector.x + values[M21] * vector.y + values[M31] * vector.z + values[M41],
                    values[M12] * vector.x + values[M22] * vector.y + values[M32] * vector.z + values[M42],
                    values[M13] * vector.x + values[M23] * vector.y + values[M33] * vector.z + values[M43]);
            }
       
            public Vector4 transform(Vector4 vector)
            {
            return new Vector4(
                    values[M11] * vector.x + values[M21] * vector.y + values[M31] * vector.z + values[M41] * vector.w,
                    values[M12] * vector.x + values[M22] * vector.y + values[M32] * vector.z + values[M42] * vector.w,
                    values[M13] * vector.x + values[M23] * vector.y + values[M33] * vector.z + values[M43] * vector.w,
                    values[M14] * vector.x + values[M24] * vector.y + values[M34] * vector.z + values[M44] * vector.w);
            }
       
            static public void interpolate(Matrix4 result, Matrix4 a, Matrix4 b, float ratio)
            {
            result.values[M11] = a.values[M11] + (b.values[M11] - a.values[M11]) * ratio;
            result.values[M21] = a.values[M21] + (b.values[M21] - a.values[M21]) * ratio;
            result.values[M31] = a.values[M31] + (b.values[M31] - a.values[M31]) * ratio;
            result.values[M41] = a.values[M41] + (b.values[M41] - a.values[M41]) * ratio;
            result.values[M12] = a.values[M12] + (b.values[M12] - a.values[M12]) * ratio;
            result.values[M22] = a.values[M22] + (b.values[M22] - a.values[M22]) * ratio;
            result.values[M32] = a.values[M32] + (b.values[M32] - a.values[M32]) * ratio;
            result.values[M42] = a.values[M42] + (b.values[M42] - a.values[M42]) * ratio;
            result.values[M13] = a.values[M13] + (b.values[M13] - a.values[M13]) * ratio;
            result.values[M23] = a.values[M23] + (b.values[M23] - a.values[M23]) * ratio;
            result.values[M33] = a.values[M33] + (b.values[M33] - a.values[M33]) * ratio;
            result.values[M43] = a.values[M43] + (b.values[M43] - a.values[M43]) * ratio;
            result.values[M14] = a.values[M14] + (b.values[M14] - a.values[M14]) * ratio;
            result.values[M24] = a.values[M24] + (b.values[M24] - a.values[M24]) * ratio;
            result.values[M34] = a.values[M34] + (b.values[M34] - a.values[M34]) * ratio;
            result.values[M44] = a.values[M44] + (b.values[M44] - a.values[M44]) * ratio;
            }
       
            static public Matrix4 interpolate(Matrix4 a, Matrix4 b, float ratio)
            {
                    Matrix4 result = createIdentity();
                    interpolate(result, a, b, ratio);
                    return result;
            }
       
            public Vector3 getForwardVector()
            {
                    Vector3 forward = new Vector3(-values[M31], -values[M32], -values[M33]);
            forward.normalize();
            return forward;
            }
       
            public Vector3 getUpVector()
            {
            Vector3 up = new Vector3(values[M21], values[M22], values[M23]);
            up.normalize();
            return up;
            }
       
            public Vector3 getRightVector()
            {
            Vector3 right = new Vector3(values[M11], values[M12], values[M13]);
            right.normalize();
            return right;
            }
       
            public float[] toGLMatrix()
            {
                    return values;
            }
       
            public void fromGLMatrix(float[] m)
            {
                    //values = m;
            for (int i = 0; i < values.Length; i++)
                values[i] = m[i];
            }  
       
            // TODO: convert to C# equivalent
        /*
            public FloatBuffer toFloatBuffer()
            {
                    FloatBuffer buffer = BufferUtils.newFloatBuffer(16);
               
                    BufferUtils.copy(values, buffer, values.length, 0);

                    return buffer;
            }*/

    }
}