import org.junit.Before;
import org.junit.Test;
import org.junit.After;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import net.nullptr.math.Matrix4;
import net.nullptr.math.Quaternion;
import net.nullptr.math.Vector2;
import net.nullptr.math.Vector3;
import net.nullptr.math.Vector4;

@RunWith(JUnit4.class)
public class TestMatrix4 extends TestBase
{
    private Matrix4 a;
    private Matrix4 b;
    private Matrix4 c;
    private Matrix4 i;

    private Matrix4 aa; // do not use this in calculations
    private Matrix4 bb; // do not use this in calculations
    private Matrix4 cc; // do not use this in calculations
    private Matrix4 ii; // do not use this in calculations

    // constants used for projection and view matrices
    final float width = 1280.0f;
    final float height = 720.0f;
    final float fov = 75.0f;
    final float near = 0.1f;
    final float far = 1024.0f;

    @Before
    public void setup()
    {
        final float[] aValues = new float[] { 0.056713f, 0.891773f, 0.297535f, 0.437587f, 0.384382f, 0.645894f, 0.623564f, 0.423655f, 0.847252f, 0.544883f, 0.857946f, 0.602763f, 0.844266f, 0.715189f, 0.592845f, 0.548814f };
        a = new Matrix4(aValues);
        aa = new Matrix4(a);
        assertEquals(a, aValues);
        assertEquals(a, aa);

        final float[] bValues = new float[] { 0.648172f, 0.0871293f, 0.337396f, 0.0710361f, 0.836079f, 0.925597f, 0.392785f, 0.568045f, 0.479977f, 0.528895f, 0.812169f, 0.791725f, 0.477665f, 0.383442f, 0.272656f, 0.963663f };
        b = new Matrix4(bValues);
        bb = new Matrix4(b);
        assertEquals(b, bValues);
        assertEquals(b, bb);

        final float[] cValues = new float[] { 0.67888f, 0.780529f, 0.520477f, 0.461479f, 0.800911f, 0.799159f, 0.473608f, 0.978618f, 0.870087f, 0.870012f, 0.140351f, 0.778157f, 0.957155f, 0.83262f, 0.368242f, 0.0202184f };
        c = new Matrix4(cValues);
        cc = new Matrix4(c);
        assertEquals(c, cValues);
        assertEquals(c, cc);

        final float[] iValues = new float[] { 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f };
        i = new Matrix4(iValues);
        ii = new Matrix4(i);
        assertEquals(i, iValues);
        assertEquals(i, ii);
    }

    @After
    public void teardown()
    {
        // ensure none of the input matrices were changed
        assertEquals(a, aa);
        assertEquals(b, bb);
        assertEquals(c, cc);
        assertEquals(i, ii);
    }

    @Test
    public void setIdentity()
    {
        final Matrix4 result = new Matrix4(a);
        assertEquals(result, a);

        Matrix4.setIdentity(result);
        assertEquals(result.values[0], 1.0f);
        assertEquals(result.values[1], 0.0f);
        assertEquals(result.values[2], 0.0f);
        assertEquals(result.values[3], 0.0f);

        assertEquals(result.values[4], 0.0f);
        assertEquals(result.values[5], 1.0f);
        assertEquals(result.values[6], 0.0f);
        assertEquals(result.values[7], 0.0f);

        assertEquals(result.values[8], 0.0f);
        assertEquals(result.values[9], 0.0f);
        assertEquals(result.values[10], 1.0f);
        assertEquals(result.values[11], 0.0f);

        assertEquals(result.values[12], 0.0f);
        assertEquals(result.values[13], 0.0f);
        assertEquals(result.values[14], 0.0f);
        assertEquals(result.values[15], 1.0f);

        assertEquals(result, i);
    }

    @Test
    public void add()
    {
        final Matrix4 result = new Matrix4();
        {
            final float[] expected = new float[] { 0.704885f, 0.978902f, 0.634931f, 0.508623f, 1.22046f, 1.57149f, 1.01635f, 0.991699f, 1.32723f, 1.07378f, 1.67011f, 1.39449f, 1.32193f, 1.09863f, 0.865501f, 1.51248f };
            Matrix4.add(result, a, b);
            assertEquals(result, expected);
        }
        {
            final float[] expected = new float[] { 0.704885f, 0.978902f, 0.634931f, 0.508623f, 1.22046f, 1.57149f, 1.01635f, 0.991699f, 1.32723f, 1.07378f, 1.67011f, 1.39449f, 1.32193f, 1.09863f, 0.865501f, 1.51248f };
            Matrix4.add(result, b, a);
            assertEquals(result, expected);
        }
        {
            final float[] expected = new float[] { 1.05671f, 0.891773f, 0.297535f, 0.437587f, 0.384382f, 1.64589f, 0.623564f, 0.423655f, 0.847252f, 0.544883f, 1.85795f, 0.602763f, 0.844266f, 0.715189f, 0.592845f, 1.54881f };
            Matrix4.add(result, a, i);
            assertEquals(result, expected);
        }
        {
            final float[] expected = new float[] { 2f, 0f, 0f, 0f, 0f, 2f, 0f, 0f, 0f, 0f, 2f, 0f, 0f, 0f, 0f, 2f };
            Matrix4.add(result, i, i);
            assertEquals(result, expected);
        }
    }

    @Test
    public void subtract()
    {
        final Matrix4 result = new Matrix4();
        {
            final float[] expected = new float[] { -0.591459f, 0.804644f, -0.0398616f, 0.366551f, -0.451697f, -0.279703f, 0.230779f, -0.14439f, 0.367275f, 0.0159883f, 0.0457769f, -0.188962f, 0.366601f, 0.331748f, 0.320188f, -0.414849f };
            Matrix4.subtract(result, a, b);
            assertEquals(result, expected);
        }
        {
            final float[] expected = new float[] { 0.591459f, -0.804644f, 0.0398616f, -0.366551f, 0.451697f, 0.279703f, -0.230779f, 0.14439f, -0.367275f, -0.0159883f, -0.0457769f, 0.188962f, -0.366601f, -0.331748f, -0.320188f, 0.414849f };
            Matrix4.subtract(result, b, a);
            assertEquals(result, expected);
        }
        {
            final float[] expected = new float[] { -0.943287f, 0.891773f, 0.297535f, 0.437587f, 0.384382f, -0.354106f, 0.623564f, 0.423655f, 0.847252f, 0.544883f, -0.142054f, 0.602763f, 0.844266f, 0.715189f, 0.592845f, -0.451186f };
            Matrix4.subtract(result, a, i);
            assertEquals(result, expected);
        }
        {
            final float[] expected = new float[] { 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f };
            Matrix4.subtract(result, i, i);
            assertEquals(result, expected);
        }
    }

    @Test
    public void multiply()
    {
        final Matrix4 result = new Matrix4();
        {
            final float[] expected = new float[] { 0.056713f, 0.891773f, 0.297535f, 0.437587f, 0.384382f, 0.645894f, 0.623564f, 0.423655f, 0.847252f, 0.544883f, 0.857946f, 0.602763f, 0.844266f, 0.715189f, 0.592845f, 0.548814f };
            Matrix4.multiply(result, a, i);
            assertEquals(result, expected);
        }
        {
            final float[] expected = new float[] { 0.056713f, 0.891773f, 0.297535f, 0.437587f, 0.384382f, 0.645894f, 0.623564f, 0.423655f, 0.847252f, 0.544883f, 0.857946f, 0.602763f, 0.844266f, 0.715189f, 0.592845f, 0.548814f };
            Matrix4.multiply(result, i, a);
            assertEquals(result, expected);
        }
        {
            final float[] expected = new float[] { 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f };
            Matrix4.multiply(result, i, i);
            assertEquals(result, expected);
        }
        {
            final float[] expected = new float[] { 0.416083f, 0.868944f, 0.578765f, 0.5629f, 1.21557f, 1.96371f, 1.49968f, 1.3065f, 1.58706f, 1.77841f, 1.63878f, 1.35816f, 1.21907f, 1.5114f, 1.18645f, 1.06469f };
            Matrix4.multiply(result, a, b);
            assertEquals(result, expected);
        }
        {
            final float[] expected = new float[] { 1.13418f, 1.15552f, 0.730369f, 1.16785f, 1.29083f, 1.12357f, 1.00534f, 1.29615f, 1.70444f, 1.26305f, 1.36103f, 1.62982f, 1.69188f, 1.25953f, 1.19689f, 1.46447f };
            Matrix4.multiply(result, b, a);
            assertEquals(result, expected);
        }
        {
            final float[] expected = new float[] { 1.16911f, 1.72319f, 1.40883f, 1.19473f, 1.58008f, 2.18836f, 1.72312f, 1.51159f, 1.15965f, 1.97086f, 1.38313f, 1.26099f, 0.70339f, 1.60646f, 1.1319f, 1.00464f };
            Matrix4.multiply(result, a, c);
            assertEquals(result, expected);
        }
    }

    @Test
    public void inverse()
    {
        final Matrix4 result = new Matrix4();
        {
            Matrix4.inverse(result, a);
            final float[] expected = new float[] { -1.66444f, 0.683304f, -1.95779f, 2.94989f, -1.17892f, 3.97035f, -4.18357f, 2.46992f, -2.01539f, 4.88331f, -0.789333f, -1.29579f, 6.27389f, -11.50037f, 9.31627f, -4.53477f };
            assertEquals(result, expected);

            Matrix4.inverse(result, result);
            assertEquals(result, a);
        }

        Matrix4.inverse(result, b);
        {
            final float[] expected = new float[] { 1.62999f, 0.149733f, -0.938415f, 0.562566f, -1.37771f, 1.49896f, 0.15181f, -0.90675f, 0.258368f, -0.567339f, 1.78468f, -1.15088f, -0.332858f, -0.510134f, -0.100209f, 1.44528f };
            assertEquals(result, expected);
        }

        Matrix4.inverse(result, c);
        {
            final float[] expected = new float[] { -5.64455f, 4.17761f, -1.99379f, 3.36502f, 6.23452f, -5.66133f, 3.49682f, -2.86349f, 0.617252f, 1.86943f, -2.72952f, 0.479164f, -0.770401f, 1.32128f, 0.0971307f, -0.647475f };
            assertEquals(result, expected);
        }

        Matrix4.inverse(result, i);
        {
            final float[] expected = new float[] { 1f, -0f, 0f, -0f, -0f, 1f, -0f, 0f, 0f, -0f, 1f, -0f, -0f, 0f, -0f, 1f };
            assertEquals(result, expected);
        }
    }

    @Test
    public void transpose()
    {
        final Matrix4 result = new Matrix4();
        {
            final float[] expected = new float[] { 0.056713f, 0.384382f, 0.847252f, 0.844266f, 0.891773f, 0.645894f, 0.544883f, 0.715189f, 0.297535f, 0.623564f, 0.857946f, 0.592845f, 0.437587f, 0.423655f, 0.602763f, 0.548814f };

            Matrix4.transpose(result, a);
            assertEquals(result, expected);

            Matrix4.transpose(result, result);
            assertEquals(result, a);
        }
        {
            final float[] expected = new float[] { 0.648172f, 0.836079f, 0.479977f, 0.477665f, 0.0871293f, 0.925597f, 0.528895f, 0.383442f, 0.337396f, 0.392785f, 0.812169f, 0.272656f, 0.0710361f, 0.568045f, 0.791725f, 0.963663f };

            Matrix4.transpose(result, b);
            assertEquals(result, expected);

            Matrix4.transpose(result, result);
            assertEquals(result, b);
        }
        {
            final float[] expected = new float[] { 0.67888f, 0.800911f, 0.870087f, 0.957155f, 0.780529f, 0.799159f, 0.870012f, 0.83262f, 0.520477f, 0.473608f, 0.140351f, 0.368242f, 0.461479f, 0.978618f, 0.778157f, 0.0202184f };

            Matrix4.transpose(result, c);
            assertEquals(result, expected);

            Matrix4.transpose(result, result);
            assertEquals(result, c);
        }
        {
            final float[] expected = new float[] { 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f };

            Matrix4.transpose(result, i);
            assertEquals(result, expected);
            assertEquals(result, i);

            Matrix4.transpose(result, result);
            assertEquals(result, i);
        }
    }

    @Test
    public void determinant()
    {
        assertEquals(Matrix4.determinant(a), -0.019561f);
        assertEquals(Matrix4.determinant(b), 0.213917f);
        assertEquals(Matrix4.determinant(c), -0.048003f);
        assertEquals(Matrix4.determinant(i), 1f);
    }

    @Test
    public void translate()
    {
        final Vector3 v = new Vector3(0.639921f, 0.720633f, 0.118274f);
        final Matrix4 result = new Matrix4();
        {
            final float[] expected = new float[] { 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0.639921f, 0.720633f, 0.118274f, 1f };
            Matrix4.setIdentity(result);
            Matrix4.translate(result, result, v);
            assertEquals(result, expected);
        }
        {
            final float[] expected = new float[] { 0.056713f, 0.891773f, 0.297535f, 0.437587f, 0.384382f, 0.645894f, 0.623564f, 0.423655f, 0.847252f, 0.544883f, 0.857946f, 0.602763f, 1.25776f, 1.81575f, 1.33408f, 1.20543f };
            Matrix4.translate(result, a, v);
            assertEquals(result, expected);
        }
        {
            final float[] expected = new float[] { 0.648172f, 0.0871293f, 0.337396f, 0.0710361f, 0.836079f, 0.925597f, 0.392785f, 0.568045f, 0.479977f, 0.528895f, 0.812169f, 0.791725f, 1.55172f, 1.16877f, 0.867676f, 1.51211f };
            Matrix4.translate(result, b, v);
            assertEquals(result, expected);
        }
        {
            final float[] expected = new float[] { 0.67888f, 0.780529f, 0.520477f, 0.461479f, 0.800911f, 0.799159f, 0.473608f, 0.978618f, 0.870087f, 0.870012f, 0.140351f, 0.778157f, 2.07166f, 2.0109f, 1.0592f, 1.11279f };
            Matrix4.translate(result, c, v);
            assertEquals(result, expected);
        }
    }

    @Test
    public void scale()
    {
        final Vector3 v = new Vector3(0.639921f, 0.720633f, 0.118274f);
        final Matrix4 result = new Matrix4();
        {
            final float[] expected = new float[] { 0.639921f, 0f, 0f, 0f, 0f, 0.720633f, 0f, 0f, 0f, 0f, 0.118274f, 0f, 0f, 0f, 0f, 1f };
            Matrix4.setIdentity(result);
            Matrix4.scale(result, result, v);
            assertEquals(result, expected);
        }
        {
            final float[] expected = new float[] { 0.0362918f, 0.570664f, 0.190399f, 0.280021f, 0.276998f, 0.465452f, 0.44936f, 0.305299f, 0.100208f, 0.0644457f, 0.101473f, 0.0712915f, 0.844266f, 0.715189f, 0.592845f, 0.548814f };
            Matrix4.scale(result, a, v);
            assertEquals(result, expected);
        }
        {
            final float[] expected = new float[] { 0.414779f, 0.0557559f, 0.215907f, 0.0454575f, 0.602506f, 0.667015f, 0.283054f, 0.409351f, 0.056769f, 0.0625547f, 0.0960588f, 0.0936408f, 0.477665f, 0.383442f, 0.272656f, 0.963663f };
            Matrix4.scale(result, b, v);
            assertEquals(result, expected);
        }
        {
            final float[] expected = new float[] { 0.434429f, 0.499477f, 0.333064f, 0.29531f, 0.577162f, 0.5759f, 0.341297f, 0.705224f, 0.102909f, 0.1029f, 0.0165999f, 0.092036f, 0.957155f, 0.83262f, 0.368242f, 0.0202184f };
            Matrix4.scale(result, c, v);
            assertEquals(result, expected);
        }
    }

    @Test
    public void rotate()
    {
        final Quaternion rotation = new Quaternion(0.616934f, 0.386489f, 0.943748f, 0.902599f);
        assertEquals(rotation, 0.616934f, 0.386489f, 0.943748f, 0.902599f);

        final Matrix4 result = new Matrix4();
        assertEquals(result, i);

        Matrix4.rotate(result, result, rotation);
        {
            final float[] expected = new float[] { -1.08007f, 2.18053f, 0.466772f, 0f, -1.22677f, -1.54254f, 1.84318f, 0f, 1.86215f, -0.384191f, -0.0599626f, 0f, 0f, 0f, 0f, 1f };
            assertEquals(result, expected);
        }

        Matrix4.rotate(result, a, rotation);
        {
            final float[] expected = new float[] { 1.17237f, 0.69955f, 1.4388f, 0.73252f, 0.899144f, -1.086f, 0.254474f, -0.0793201f, -0.0928714f, 1.3798f, 0.263042f, 0.615945f, 0.844266f, 0.715189f, 0.592845f, 0.548814f };
            assertEquals(result, expected);
        }

        Matrix4.rotate(result, b, rotation);
        {
            final float[] expected = new float[] { 1.34706f, 2.17106f, 0.871165f, 1.53147f, -1.20016f, -0.559804f, 0.477182f, 0.49592f, 0.856998f, -0.225072f, 0.428678f, -0.133432f, 0.477665f, 0.383442f, 0.272656f, 0.963663f };
            assertEquals(result, expected);
        }

        Matrix4.rotate(result, c, rotation);
        {
            final float[] expected = new float[] { 1.4193f, 1.30566f, 0.536076f, 1.9987f, -0.464535f, -0.586672f, -1.11037f, -0.641399f, 0.9043f, 1.09426f, 0.778835f, 0.436707f, 0.957155f, 0.83262f, 0.368242f, 0.0202184f };
            assertEquals(result, expected);
        }
    }

    @Test
    public void setPerspective()
    {
        final Matrix4 result = new Matrix4();
        assertEquals(result, i);

        Matrix4.setPerspective(result, fov, width / height, near, far);

        final float[] expected = new float[] { 0.733064f, 0f, 0f, 0f, 0f, 1.30323f, 0f, 0f, 0f, 0f, -1.0002f, -1f, 0f, 0f, -0.20002f, 0f };
        assertEquals(result, expected);
    }

    @Test
    public void setLookAt()
    {
        // vectors for testing
        final Vector3 eye = new Vector3(64.0f, 64.0f, 64.0f);
        assertEquals(eye, 64.0f, 64.0f, 64.0f);

        final Vector3 target = new Vector3(0.0f, 0.0f, 0.0f);
        assertEquals(target, 0.0f, 0.0f, 0.0f);

        final Vector3 up = new Vector3(0.0f, 1.0f, 0.0f);
        assertEquals(up, 0.0f, 1.0f, 0.0f);

        // result matrix, make sure it's set to identity initially
        final Matrix4 result = new Matrix4();
        assertEquals(result, i);

        Matrix4.setLookAt(result, eye, target, up);
        {
            final float[] expected = new float[]
                    {
                            0.707107f, -0.408248f,  0.57735f,    0f,
                            0f,         0.816497f,  0.57735f,    0f,
                            -0.707107f, -0.408248f,  0.57735f,    0f,
                            -0f,        -0f,        -110.851249f, 1f
                    };
            assertEquals(result, expected);
        }

        // randomize values
        eye.set(0.58202f, 0.143353f, 0.537373f);
        assertEquals(eye, 0.58202f, 0.143353f, 0.537373f);

        target.set(0.944669f, 0.758616f, 0.521848f);
        assertEquals(target, 0.944669f, 0.758616f, 0.521848f);

        up.set(0.105908f, 0.414662f, 0.4736f);
        assertEquals(up, 0.105908f, 0.414662f, 0.4736f);

        Matrix4.setLookAt(result, eye, target, up);
        {
            final float[] expected = new float[]
                    {
                            0.838937f, -0.196129f, -0.507659f, 0f,
                            -0.488431f, 0.140092f, -0.861284f, 0f,
                            0.240042f, 0.970519f, 0.0217328f, 0f,
                            -0.547252f, -0.427463f, 0.407257f, 1f
                    };
            assertEquals(result, expected);
        }
    }

    @Test
    public void setOrtho()
    {
        // result matrix, make sure it's set to identity initially
        final Matrix4 result = new Matrix4();

        Matrix4.setIdentity(result);
        assertEquals(result, i);

        Matrix4.setOrtho(result, -this.width * 0.5f, this.width * 0.5f, -this.height * 0.5f, this.height * 0.5f, this.near, this.far);
        {
            final float[] expected = new float[] { 0.0015625f, 0f, 0f, 0f, 0f, 0.00277778f, 0f, 0f, 0f, 0f, -0.00195332f, 0f, -0f, -0f, -1.0002f, 1f };
            assertEquals(result, expected);
        }

        Matrix4.setIdentity(result);
        assertEquals(result, i);

        Matrix4.setOrtho(result, 0.0f, this.width, 0.0f, this.height, this.near, this.far);
        {
            final float[] expected = new float[] { 0.0015625f, 0f, 0f, 0f, 0f, 0.00277778f, 0f, 0f, 0f, 0f, -0.00195332f, 0f, -1f, -1f, -1.0002f, 1f };
            assertEquals(result, expected);
        }
    }

    @Test
    public void setFrustum()
    {
        // result matrix, make sure it's set to identity initially
        final Matrix4 result = new Matrix4();
        assertEquals(result, i);

        Matrix4.setFrustum(result, -width / 2.0f, width / 2.0f, -height / 2.0f, height / 2.0f, near, far);
        {
            final float[] expected = new float[] { 0.00015625f, 0f, 0f, 0f, 0f, 0.000277778f, 0f, 0f, 0f, 0f, -1.0002f, -1f, 0f, 0f, -0.20002f, 0f };
            assertEquals(result, expected);
        }
    }

    @Test
    public void setFromQuaternion()
    {
        // rotation quaternion
        final Quaternion rotation = new Quaternion(0.264556f, 0.186332f, 0.774234f, 0.736918f);
        assertEquals(rotation, 0.264556f, 0.186332f, 0.774234f, 0.736918f);

        // result matrix, make sure it's set to identity initially
        final Matrix4 result = new Matrix4();
        assertEquals(result, i);

        result.set(rotation);
        {
            final float[] expected = new float[] { -0.268315f, 1.23968f, 0.135032f, 0f, -1.0425f, -0.338855f, 0.678441f, 0f, 0.684279f, -0.101382f, 0.790581f, 0f, 0f, 0f, 0f, 1f };
            assertEquals(result, expected);
        }
    }

    @Test
    public void cumulativeTransformMatrix()
    {
        final Matrix4 result = new Matrix4();
        assertEquals(result, i);

        final Vector3 translate = new Vector3(0.45615f, 0.21655f, 0.568434f);
        assertEquals(translate, 0.45615f, 0.21655f, 0.568434f);

        final Quaternion rotation = new Quaternion(0.135218f, 0.0187898f, 0.324141f, 0.617635f);
        assertEquals(rotation, 0.135218f, 0.0187898f, 0.324141f, 0.617635f);

        final Vector3 scale = new Vector3(0.149675f, 0.612096f, 0.222321f);
        assertEquals(scale, 0.149675f, 0.612096f, 0.222321f);

        {
            Matrix4.translate(result, result, translate);
            {
                final float[] expected = new float[] { 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0f, 0f, 0f, 1f, 0f, 0.45615f, 0.21655f, 0.568434f, 1f };
                assertEquals(result, expected);
            }

            final Matrix4 rotMat = new Matrix4(rotation);
            Matrix4.multiply(result, result, rotMat);
            {
                final float[] expected = new float[] { 0.789159f, 0.405483f, 0.064449f, 0f, -0.395321f, 0.753297f, 0.179212f, 0f, 0.11087f, -0.15485f, 0.962726f, 0f, 0.45615f, 0.21655f, 0.568434f, 1f };
                assertEquals(result, expected);
            }

            Matrix4.scale(result, result, scale);
            {
                final float[] expected = new float[] { 0.118117f, 0.0606907f, 0.0096464f, 0f, -0.241974f, 0.46109f, 0.109695f, 0f, 0.0246488f, -0.0344265f, 0.214035f, 0f, 0.45615f, 0.21655f, 0.568434f, 1f };
                assertEquals(result, expected);
            }
        }
    }

    @Test
    public void transformVector4()
    {
        final Vector4 vector = new Vector4(0.68182f, 0.44995f, 0.359508f, 0.613063f);
        assertEquals(vector, 0.68182f, 0.44995f, 0.359508f, 0.613063f);

        Vector4 result = Matrix4.transform(i, vector);
        assertEquals(result, 0.68182f, 0.44995f, 0.359508f, 0.613063f);

        result = Matrix4.transform(a, vector);
        assertEquals(result, 1.0338f, 1.533f, 1.15533f, 1.04214f);

        result = Matrix4.transform(b, vector);
        assertEquals(result, 1.28352f, 0.901095f, 0.865914f, 1.17944f);

        result = Matrix4.transform(c, vector);
        assertEquals(result, 1.72284f, 1.71499f, 0.844185f, 1.04712f);
    }

    @Test
    public void transformNormalVector3()
    {
        final Vector3 vector = new Vector3(0.437032f, 0.902349f, 0.697631f);
        assertEquals(vector, 0.437032f, 0.902349f, 0.697631f);

        Vector3 result = Matrix4.transformNormal(i, vector);
        assertEquals(result, 0.437032f, 0.902349f, 0.697631f);

        result = Matrix4.transformNormal(a, vector);
        assertEquals(result, 0.962701f, 1.35268f, 1.29123f);

        result = Matrix4.transformNormal(b, vector);
        assertEquals(result, 1.37255f, 1.24226f, 1.06848f);

        result = Matrix4.transformNormal(c, vector);
        assertEquals(result, 1.62639f, 1.66918f, 0.752738f);
    }


    @Test
    public void transformVector3()
    {
        final Vector3 vector = new Vector3(0.437032f, 0.902349f, 0.697631f);
        assertEquals(vector, 0.437032f, 0.902349f, 0.697631f);

        Vector3 result = Matrix4.transform(i, vector);
        assertEquals(result, 0.437032f, 0.902349f, 0.697631f);

        result = Matrix4.transform(a, vector);
        assertEquals(result, 1.80697f, 2.06787f, 1.88408f);

        result = Matrix4.transform(b, vector);
        assertEquals(result, 1.85022f, 1.6257f, 1.34113f);

        result = Matrix4.transform(c, vector);
        assertEquals(result, 2.58355f, 2.5018f, 1.12098f);
    }


    @Test
    public void transformNormalVector2()
    {
        final Vector2 vector = new Vector2(0.0992803f, 0.0602255f);
        assertEquals(vector, 0.0992803f, 0.0602255f);

        Vector2 result = Matrix4.transformNormal(i, vector);
        assertEquals(result, 0.0992803f, 0.0602255f);

        result = Matrix4.transformNormal(a, vector);
        assertEquals(result, 0.0287801f, 0.127435f);

        result = Matrix4.transformNormal(b, vector);
        assertEquals(result, 0.114704f, 0.0643947f);

        result = Matrix4.transformNormal(c, vector);
        assertEquals(result, 0.115635f, 0.125621f);
    }

    @Test
    public void transformVector2()
    {
        final Vector2 vector = new Vector2(0.0992803f, 0.0602255f);
        assertEquals(vector, 0.0992803f, 0.0602255f);

        Vector2 result = Matrix4.transform(i, vector);
        assertEquals(result, 0.0992803f, 0.0602255f);

        result = Matrix4.transform(a, vector);
        assertEquals(result, 0.873046f, 0.842624f);

        result = Matrix4.transform(b, vector);
        assertEquals(result, 0.592369f, 0.447836f);

        result = Matrix4.transform(c, vector);
        assertEquals(result, 1.07279f, 0.958241f);
    }
}
