#include "unittest/TestSuite.h"
#include "gamemath/Matrix3x3x.h"
#include <math.h>

static void testInit(void) {
	Matrix3x3x matrix;
	
	matrix = MATRIX3x3x(0x10000, 0x00000, 0x00000,
	                    0x00000, 0x10000, 0x00000,
	                    0x00000, 0x00000, 0x10000);
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x10000, 0x00000, 0x00000,
	                                                  0x00000, 0x10000, 0x00000,
	                                                  0x00000, 0x00000, 0x10000));
	
	matrix = MATRIX3x3x(0x00000, 0x30000, 0x60000,
	                    0x10000, 0x40000, 0x70000,
	                    0x20000, 0x50000, 0x80000);
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x00000, 0x30000, 0x60000,
	                                                  0x10000, 0x40000, 0x70000,
	                                                  0x20000, 0x50000, 0x80000));
	
	matrix = Matrix3x3x_fromDirectionVectors(VECTOR3x(0x10000, 0x00000, 0x00000),
	                                         VECTOR3x(0x00000, 0x10000, 0x00000),
	                                         VECTOR3x(0x00000, 0x00000, 0x10000));
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x10000, 0x00000, 0x00000,
	                                                  0x00000, 0x10000, 0x00000,
	                                                  0x00000, 0x00000, 0x10000));
	
	matrix = Matrix3x3x_fromDirectionVectors(VECTOR3x(0x00000, 0x10000, 0x00000),
	                                         VECTOR3x(0x00000, 0x00000, 0x10000),
	                                         VECTOR3x(0x10000, 0x00000, 0x00000));
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x00000, 0x00000, 0x10000,
	                                                  0x10000, 0x00000, 0x00000,
	                                                  0x00000, 0x10000, 0x00000));
}

static void testFromQuaternion(void) {
	Matrix3x3x matrix;
	
	matrix = Matrix3x3x_fromQuaternionx(QUATERNIONx(0x00000, 0x00000, 0x00000, 0x10000));
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x10000, 0x00000, 0x00000,
	                                                  0x00000, 0x10000, 0x00000,
	                                                  0x00000, 0x00000, 0x10000));
	
	matrix = Matrix3x3x_fromQuaternionx(QUATERNIONx(0x00000, 0x0B504, 0x00000, 0x0B504));
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x( 0x00002, 0x00000, 0x0FFFE,
	                                                   0x00000, 0x10000, 0x00000,
	                                                  -0x0FFFE, 0x00000, 0x00002));
	
	matrix = Matrix3x3x_fromQuaternionx(QUATERNIONx(0x08000, 0x08000, 0x08000, 0x08000));
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x00000, 0x00000, 0x10000,
	                                                  0x10000, 0x00000, 0x00000,
	                                                  0x00000, 0x10000, 0x00000));
	
	matrix = Matrix3x3x_fromQuaternionx(QUATERNIONx(0x10000, 0x10000, 0x10000, 0x10000));
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(-0x30000,  0x00000,  0x40000,
	                                                   0x40000, -0x30000,  0x00000,
	                                                   0x00000,  0x40000, -0x30000));
}

static void testFromMatrix4x4(void) {
	Matrix3x3x matrix;
	
	matrix = Matrix3x3x_fromMatrix4x4x(MATRIX4x4x(0, 4, 8,  12,
	                                              1, 5, 9,  13,
	                                              2, 6, 10, 14,
	                                              3, 7, 11, 15));
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0, 4, 8,
	                                                  1, 5, 9,
	                                                  2, 6, 10));
	matrix = Matrix3x3x_fromMatrix4x4x(MATRIX4x4x(1,  2,  3,  4,
	                                              5,  6,  7,  8,
	                                              9,  10, 11, 12,
	                                              13, 14, 15, 16));
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(1, 2,  3,
	                                                  5, 6,  7,
	                                                  9, 10, 11));
}

static void testIdentity(void) {
	Matrix3x3x matrix;
	
	matrix = MATRIX3x3x_IDENTITY;
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x10000, 0x00000, 0x00000,
	                                                  0x00000, 0x10000, 0x00000,
	                                                  0x00000, 0x00000, 0x10000));
	
	memset(matrix.m, 0xFF, sizeof(fixed16_16) * 9);
	Matrix3x3x_loadIdentity(&matrix);
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x10000, 0x00000, 0x00000,
	                                                  0x00000, 0x10000, 0x00000,
	                                                  0x00000, 0x00000, 0x10000));
	
	TestCase_assertBoolTrue(Matrix3x3x_isIdentity(matrix));
	matrix.m[0] = 0x08000;
	TestCase_assertBoolFalse(Matrix3x3x_isIdentity(matrix));
}

static void testIsEqual(void) {
	Matrix3x3x matrix1 = MATRIX3x3x_IDENTITY;
	Matrix3x3x matrix2 = MATRIX3x3x_IDENTITY;
	TestCase_assertBoolTrue(Matrix3x3x_isEqual(matrix1, matrix2));
	matrix2.m[1] = 0x20000;
	TestCase_assertBoolFalse(Matrix3x3x_isEqual(matrix1, matrix2));
	matrix1.m[1] = 0x20000;
	TestCase_assertBoolTrue(Matrix3x3x_isEqual(matrix1, matrix2));
}

static void testMultiply(void) {
	Matrix3x3x matrix;
	
	matrix = Matrix3x3x_multiplied(MATRIX3x3x(0x20000, 0x00000, 0x00000,
	                                          0x00000, 0x20000, 0x00000,
	                                          0x00000, 0x00000, 0x20000),
	                               MATRIX3x3x(0x20000, 0x00000, 0x00000,
	                                          0x00000, 0x20000, 0x00000,
	                                          0x00000, 0x00000, 0x20000));
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x40000, 0x00000, 0x00000,
	                                                  0x00000, 0x40000, 0x00000,
	                                                  0x00000, 0x00000, 0x40000));
	
	matrix = Matrix3x3x_multiplied(MATRIX3x3x(0x00000, 0x30000, 0x60000,
	                                          0x10000, 0x40000, 0x70000,
	                                          0x20000, 0x50000, 0x80000),
	                               MATRIX3x3x(0x10000, 0x50000, 0xD0000,
	                                          0x20000, 0x70000, 0x110000,
	                                          0x30000, 0xB0000, 0x130000));
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x180000, 0x570000, 0xA50000,
	                                                  0x1E0000, 0x6E0000, 0xD60000,
	                                                  0x240000, 0x850000, 0x1070000));
	
	matrix = MATRIX3x3x(0x20000, 0x00000, 0x00000,
	                    0x00000, 0x20000, 0x00000,
	                    0x00000, 0x00000, 0x20000),
	Matrix3x3x_multiply(&matrix, MATRIX3x3x(0x20000, 0x00000, 0x00000,
	                                        0x00000, 0x20000, 0x00000,
	                                        0x00000, 0x00000, 0x20000));
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x40000, 0x00000, 0x00000,
	                                                  0x00000, 0x40000, 0x00000,
	                                                  0x00000, 0x00000, 0x40000));
	
	matrix = MATRIX3x3x(0x00000, 0x30000, 0x60000,
	                    0x10000, 0x40000, 0x70000,
	                    0x20000, 0x50000, 0x80000),
	Matrix3x3x_multiply(&matrix, MATRIX3x3x(0x10000, 0x50000, 0xD0000,
	                                        0x20000, 0x70000, 0x110000,
	                                        0x30000, 0xB0000, 0x130000));
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x180000, 0x570000, 0xA50000,
	                                                  0x1E0000, 0x6E0000, 0xD60000,
	                                                  0x240000, 0x850000, 0x1070000));
	
	matrix = MATRIX3x3x(0x10000, 0x50000, 0xD0000,
	                    0x20000, 0x70000, 0x110000,
	                    0x30000, 0xB0000, 0x130000),
	Matrix3x3x_leftMultiply(&matrix, MATRIX3x3x(0x00000, 0x30000, 0x60000,
	                                            0x10000, 0x40000, 0x70000,
	                                            0x20000, 0x50000, 0x80000));
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x180000, 0x570000, 0xA50000,
	                                                  0x1E0000, 0x6E0000, 0xD60000,
	                                                  0x240000, 0x850000, 0x1070000));
}

static void testScale(void) {
	Matrix3x3x matrix;
	
	matrix = Matrix3x3x_scaled(MATRIX3x3x_IDENTITY, V3x(0x20000, -0x10000, 0x08000));
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x20000,  0x00000, 0x00000,
	                                                  0x00000, -0x10000, 0x00000,
	                                                  0x00000,  0x00000, 0x08000));
	
	matrix = Matrix3x3x_scaled(MATRIX3x3x(0x00000, 0x00000, -0x10000,
	                                      0x20000, 0x00000,  0x00000,
	                                      0x00000, 0x18000,  0x00000),
	                           V3x(0x30000, 0x18000, -0x08000));
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x00000, 0x00000, 0x08000,
	                                                  0x60000, 0x00000, 0x00000,
	                                                  0x00000, 0x24000, 0x00000));
	
	matrix = MATRIX3x3x_IDENTITY;
	Matrix3x3x_scale(&matrix, V3x(0x20000, -0x10000, 0x08000));
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x20000,  0x00000, 0x00000,
	                                                  0x00000, -0x10000, 0x00000,
	                                                  0x00000,  0x00000, 0x08000));
	
	matrix = MATRIX3x3x(0x00000, 0x00000, -0x10000,
	                    0x20000, 0x00000,  0x00000,
	                    0x00000, 0x18000,  0x00000);
	Matrix3x3x_scale(&matrix, V3x(0x30000, 0x18000, -0x08000));
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x00000, 0x00000, 0x08000,
	                                                  0x60000, 0x00000, 0x00000,
	                                                  0x00000, 0x24000, 0x00000));
}

static void testRotate(void) {
	Matrix3x3x matrix;
	
	matrix = Matrix3x3x_rotated(MATRIX3x3x_IDENTITY, VECTOR3x(0x00000, 0x10000, 0x00000), X_PI);
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(-0x10000, 0x00000,  0x00000,
	                                                   0x00000, 0x10000,  0x00000,
	                                                   0x00000, 0x00000, -0x10000));
	
	matrix = Matrix3x3x_rotated(Matrix3x3x_scaled(MATRIX3x3x_IDENTITY, V3x(0x20000, 0x20000, 0x20000)),
	                            VECTOR3x(-0x10000, 0x00000, 0x00000),
	                            xmul(X_PI, 0x08000));
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x20000,  0x00000, 0x00000,
	                                                  0x00000,  0x00000, 0x1FF9C,
	                                                  0x00000, -0x1FF9C, 0x00000));
	
	matrix = MATRIX3x3x_IDENTITY;
	Matrix3x3x_rotate(&matrix, VECTOR3x(0x00000, 0x10000, 0x00000), X_PI);
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(-0x10000, 0x00000,  0x00000,
	                                                   0x00000, 0x10000,  0x00000,
	                                                   0x00000, 0x00000, -0x10000));
	
	matrix = Matrix3x3x_scaled(MATRIX3x3x_IDENTITY, V3x(0x20000, 0x20000, 0x20000));
	Matrix3x3x_rotate(&matrix, VECTOR3x(-0x10000, 0x00000, 0x00000), xmul(X_PI, 0x08000));
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x20000,  0x00000, 0x00000,
	                                                  0x00000,  0x00000, 0x1FF9C,
	                                                  0x00000, -0x1FF9C, 0x00000));
}

static void testShear(void) {
	Matrix3x3x matrix;
	
	matrix = Matrix3x3x_shearedX(MATRIX3x3x_IDENTITY, 0x10000, 0x10000);
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x10000, 0x00000, 0x00000,
	                                                  0x10000, 0x10000, 0x00000,
	                                                  0x10000, 0x00000, 0x10000));
	
	matrix = Matrix3x3x_shearedX(Matrix3x3x_fromDirectionVectors(VECTOR3x(0x00000, 0x10000, 0x00000),
	                                                             VECTOR3x(0x00000, 0x00000, 0x10000),
	                                                             VECTOR3x(0x10000, 0x00000, 0x00000)),
	                             0x08000, -0x08000);
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(-0x08000, 0x00000, 0x10000,
	                                                   0x10000, 0x00000, 0x00000,
	                                                   0x08000, 0x10000, 0x00000));
	
	matrix = Matrix3x3x_shearedY(MATRIX3x3x_IDENTITY, 0x10000, 0x10000);
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x10000, 0x10000, 0x00000,
	                                                  0x00000, 0x10000, 0x00000,
	                                                  0x00000, 0x10000, 0x10000));
	
	matrix = Matrix3x3x_shearedY(Matrix3x3x_fromDirectionVectors(VECTOR3x(0x00000, 0x10000, 0x00000),
	                                                             VECTOR3x(0x00000, 0x00000, 0x10000),
	                                                             VECTOR3x(0x10000, 0x00000, 0x00000)),
	                             0x08000, -0x08000);
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x00000, -0x08000, 0x10000,
	                                                  0x10000,  0x08000, 0x00000,
	                                                  0x00000,  0x10000, 0x00000));
	
	matrix = Matrix3x3x_shearedZ(MATRIX3x3x_IDENTITY, 0x10000, 0x10000);
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x10000, 0x00000, 0x10000,
	                                                  0x00000, 0x10000, 0x10000,
	                                                  0x00000, 0x00000, 0x10000));
	
	matrix = Matrix3x3x_shearedZ(Matrix3x3x_fromDirectionVectors(VECTOR3x(0x00000, 0x10000, 0x00000),
	                                                             VECTOR3x(0x00000, 0x00000, 0x10000),
	                                                             VECTOR3x(0x10000, 0x00000, 0x00000)),
	                             0x08000, -0x08000);
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x00000, 0x00000,  0x10000,
	                                                  0x10000, 0x00000,  0x08000,
	                                                  0x00000, 0x10000, -0x08000));
	
	matrix = MATRIX3x3x_IDENTITY;
	Matrix3x3x_shearX(&matrix, 0x10000, 0x10000);
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x10000, 0x00000, 0x00000,
	                                                  0x10000, 0x10000, 0x00000,
	                                                  0x10000, 0x00000, 0x10000));
	
	matrix = Matrix3x3x_fromDirectionVectors(VECTOR3x(0x00000, 0x10000, 0x00000),
	                                         VECTOR3x(0x00000, 0x00000, 0x10000),
	                                         VECTOR3x(0x10000, 0x00000, 0x00000));
	Matrix3x3x_shearX(&matrix, 0x08000, -0x08000);
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(-0x08000, 0x00000, 0x10000,
	                                                   0x10000, 0x00000, 0x00000,
	                                                   0x08000, 0x10000, 0x00000));
	
	matrix = MATRIX3x3x_IDENTITY;
	Matrix3x3x_shearY(&matrix, 0x10000, 0x10000);
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x10000, 0x10000, 0x00000,
	                                                  0x00000, 0x10000, 0x00000,
	                                                  0x00000, 0x10000, 0x10000));
	
	matrix = Matrix3x3x_fromDirectionVectors(VECTOR3x(0x00000, 0x10000, 0x00000),
	                                         VECTOR3x(0x00000, 0x00000, 0x10000),
	                                         VECTOR3x(0x10000, 0x00000, 0x00000));
	Matrix3x3x_shearY(&matrix, 0x08000, -0x08000);
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x00000, -0x08000, 0x10000,
	                                                  0x10000,  0x08000, 0x00000,
	                                                  0x00000,  0x10000, 0x00000));
	
	matrix = MATRIX3x3x_IDENTITY;
	Matrix3x3x_shearZ(&matrix, 0x10000, 0x10000);
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x10000, 0x00000, 0x10000,
	                                                  0x00000, 0x10000, 0x10000,
	                                                  0x00000, 0x00000, 0x10000));
	
	matrix = Matrix3x3x_fromDirectionVectors(VECTOR3x(0x00000, 0x10000, 0x00000),
	                                     VECTOR3x(0x00000, 0x00000, 0x10000),
	                                     VECTOR3x(0x10000, 0x00000, 0x00000));
	Matrix3x3x_shearZ(&matrix, 0x08000, -0x08000);
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x00000, 0x00000,  0x10000,
	                                                  0x10000, 0x00000,  0x08000,
	                                                  0x00000, 0x10000, -0x08000));
}

static void testTranspose(void) {
	Matrix3x3x matrix;
	
	matrix = Matrix3x3x_transposed(MATRIX3x3x(0x10000, 0x00000, 0x00000,
	                                          0x10000, 0x10000, 0x00000,
	                                          0x10000, 0x10000, 0x10000));
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x10000, 0x10000, 0x10000,
	                                                  0x00000, 0x10000, 0x10000,
	                                                  0x00000, 0x00000, 0x10000));
	
	matrix = Matrix3x3x_transposed(MATRIX3x3x(0x00000, 0x06666, 0x0CCCC,
	                                          0x01999, 0x08000, 0x0E666,
	                                          0x03333, 0x09999, 0x10000));
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x00000, 0x01999, 0x03333,
	                                                  0x06666, 0x08000, 0x09999,
	                                                  0x0CCCC, 0x0E666, 0x10000));
	
	matrix = MATRIX3x3x(0x10000, 0x00000, 0x00000,
	                    0x10000, 0x10000, 0x00000,
	                    0x10000, 0x10000, 0x10000);
	Matrix3x3x_transpose(&matrix);
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x10000, 0x10000, 0x10000,
	                                                  0x00000, 0x10000, 0x10000,
	                                                  0x00000, 0x00000, 0x10000));
	
	matrix = MATRIX3x3x(0x00000, 0x06666, 0x0CCCC,
	                    0x01999, 0x08000, 0x0E666,
	                    0x03333, 0x09999, 0x10000);
	Matrix3x3x_transpose(&matrix);
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x00000, 0x01999, 0x03333,
	                                                  0x06666, 0x08000, 0x09999,
	                                                  0x0CCCC, 0x0E666, 0x10000));
}

static void testDeterminant(void) {
	fixed16_16 determinant;
	
	determinant = Matrix3x3x_determinant(MATRIX3x3x_IDENTITY);
	TestCase_assertFixed16_16Equal(determinant, 0x10000);
	
	determinant = Matrix3x3x_determinant(MATRIX3x3x(0x00000, 0x00000, 0x20000,
	                                                0x20000, 0x00000, 0x00000,
	                                                0x00000, 0x20000, 0x00000));
	TestCase_assertFixed16_16Equal(determinant, 0x80000);
}

static void testInvert(void) {
	Matrix3x3x matrix;
	
	matrix = Matrix3x3x_inverted(MATRIX3x3x_IDENTITY);
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x10000, 0x00000, 0x00000,
	                                                  0x00000, 0x10000, 0x00000,
	                                                  0x00000, 0x00000, 0x10000));
	
	matrix = Matrix3x3x_inverted(MATRIX3x3x(0x00000, 0x00000, 0x20000,
	                                        0x20000, 0x00000, 0x00000,
	                                        0x00000, 0x20000, 0x00000));
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x00000, 0x08000, 0x00000,
	                                                  0x00000, 0x00000, 0x08000,
	                                                  0x08000, 0x00000, 0x00000));
	
	matrix = MATRIX3x3x_IDENTITY;
	Matrix3x3x_invert(&matrix);
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x10000, 0x00000, 0x00000,
	                                                  0x00000, 0x10000, 0x00000,
	                                                  0x00000, 0x00000, 0x10000));
	
	matrix = MATRIX3x3x(0x00000, 0x00000, 0x20000,
	                    0x20000, 0x00000, 0x00000,
	                    0x00000, 0x20000, 0x00000);
	Matrix3x3x_invert(&matrix);
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x00000, 0x08000, 0x00000,
	                                                  0x00000, 0x00000, 0x08000,
	                                                  0x08000, 0x00000, 0x00000));
}

static void testInterpolate(void) {
	Matrix3x3x matrixLeft, matrixRight, matrixInterpolated;
	
	matrixLeft = MATRIX3x3x_IDENTITY;
	matrixRight = MATRIX3x3x(0x00000, 0x10000, 0x10000,
	                         0x10000, 0x00000, 0x10000,
	                         0x10000, 0x10000, 0x00000);
	
	matrixInterpolated = Matrix3x3x_interpolated(matrixLeft, matrixRight, 0x00000);
	TestCase_assertMatrix3x3xEqual(matrixInterpolated, MATRIX3x3x(0x10000, 0x00000, 0x00000,
	                                                              0x00000, 0x10000, 0x00000,
	                                                              0x00000, 0x00000, 0x10000));
	
	matrixInterpolated = Matrix3x3x_interpolated(matrixLeft, matrixRight, 0x04000);
	TestCase_assertMatrix3x3xEqual(matrixInterpolated, MATRIX3x3x(0x0C000, 0x04000, 0x04000,
	                                                              0x04000, 0x0C000, 0x04000,
	                                                              0x04000, 0x04000, 0x0C000));
	
	matrixInterpolated = matrixLeft;
	Matrix3x3x_interpolate(&matrixInterpolated, matrixRight, 0x00000);
	TestCase_assertMatrix3x3xEqual(matrixInterpolated, MATRIX3x3x(0x10000, 0x00000, 0x00000,
	                                                              0x00000, 0x10000, 0x00000,
	                                                              0x00000, 0x00000, 0x10000));
	
	matrixInterpolated = matrixLeft;
	Matrix3x3x_interpolate(&matrixInterpolated, matrixRight, 0x04000);
	TestCase_assertMatrix3x3xEqual(matrixInterpolated, MATRIX3x3x(0x0C000, 0x04000, 0x04000,
	                                                              0x04000, 0x0C000, 0x04000,
	                                                              0x04000, 0x04000, 0x0C000));
	
	matrixLeft = MATRIX3x3x(0x00000, 0x40000, 0x80000,
	                        0x10000, 0x50000, 0x90000,
	                        0x20000, 0x60000, 0xA0000);
	matrixRight = MATRIX3x3x_IDENTITY;
	
	matrixInterpolated = Matrix3x3x_interpolated(matrixLeft, matrixRight, -0x10000);
	TestCase_assertMatrix3x3xEqual(matrixInterpolated, MATRIX3x3x(-0x10000, 0x80000, 0x100000,
	                                                               0x20000, 0x90000, 0x120000,
	                                                               0x40000, 0xC0000, 0x130000));
	
	matrixInterpolated = Matrix3x3x_interpolated(matrixLeft, matrixRight, 0x20000);
	TestCase_assertMatrix3x3xEqual(matrixInterpolated, MATRIX3x3x( 0x20000, -0x40000, -0x80000,
	                                                              -0x10000, -0x30000, -0x90000,
	                                                              -0x20000, -0x60000, -0x80000));
	
	matrixInterpolated = matrixLeft;
	Matrix3x3x_interpolate(&matrixInterpolated, matrixRight, -0x10000);
	TestCase_assertMatrix3x3xEqual(matrixInterpolated, MATRIX3x3x(-0x10000, 0x80000, 0x100000,
	                                                               0x20000, 0x90000, 0x120000,
	                                                               0x40000, 0xC0000, 0x130000));
	
	matrixInterpolated = matrixLeft;
	Matrix3x3x_interpolate(&matrixInterpolated, matrixRight, 0x20000);
	TestCase_assertMatrix3x3xEqual(matrixInterpolated, MATRIX3x3x( 0x20000, -0x40000, -0x80000,
	                                                              -0x10000, -0x30000, -0x90000,
	                                                              -0x20000, -0x60000, -0x80000));
}

static void testNormalize(void) {
	Matrix3x3x matrix = MATRIX3x3x(0x08000, 0x00000, 0x00000,
	                               0x00000, 0x04000, 0x00000,
	                               0x00000, 0x00000, 0x02000);
	Matrix3x3x normalizedMatrix = Matrix3x3x_normalized(matrix);
	TestCase_assertMatrix3x3xEqual(normalizedMatrix, MATRIX3x3x(0x10000, 0x00000, 0x00000,
	                                                            0x00000, 0x10000, 0x00000,
	                                                            0x00000, 0x00000, 0x10000));
	Matrix3x3x_normalize(&matrix);
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x10000, 0x00000, 0x00000,
	                                                  0x00000, 0x10000, 0x00000,
	                                                  0x00000, 0x00000, 0x10000));
	
	matrix = MATRIX3x3x(0x00000,  0x10000, -0x10000,
	                   -0x10000,  0x00000,  0x10000,
	                   -0x10000, -0x10000,  0x00000);
	normalizedMatrix = Matrix3x3x_normalized(matrix);
	TestCase_assertMatrix3x3xEqual(normalizedMatrix, MATRIX3x3x(0x00000,  0x0B505, -0x0B505,
	                                                           -0x0B505,  0x00000,  0x0B505,
	                                                           -0x0B505, -0x0B505,  0x00000));
	Matrix3x3x_normalize(&matrix);
	TestCase_assertMatrix3x3xEqual(matrix, MATRIX3x3x(0x00000,  0x0B505, -0x0B505,
	                                                 -0x0B505,  0x00000,  0x0B505,
	                                                 -0x0B505, -0x0B505,  0x00000));
}

static void testMultiplyVector(void) {
	Matrix3x3x matrix;
	Vector2x vector2;
	Vector3x vector3;
	
	matrix = MATRIX3x3x_IDENTITY;
	vector2 = Matrix3x3x_multiplyVector2x(matrix, VECTOR2x(0x10000, 0x00000));
	TestCase_assertVector2xEqual(vector2, V2x(0x10000, 0x00000));
	
	vector3 = Matrix3x3x_multiplyVector3x(matrix, VECTOR3x(0x00000, 0x10000, 0x00000));
	TestCase_assertVector3xEqual(vector3, V3x(0x00000, 0x10000, 0x00000));
	
	matrix = MATRIX3x3x(0x00000, 0x20000,  0x00000,
	                    0x20000, 0x00000,  0x00000,
	                    0x00000, 0x00000, -0x20000);
	vector2 = Matrix3x3x_multiplyVector2x(matrix, VECTOR2x(-0x10000, 0x10000));
	TestCase_assertVector2xEqual(vector2, V2x(0x20000, -0x20000));
	
	vector3 = Matrix3x3x_multiplyVector3x(matrix, VECTOR3x(0x00000, -0x10000, 0x00000));
	TestCase_assertVector3xEqual(vector3, V3x(-0x20000, 0x00000, 0x00000));
}

TEST_SUITE(Matrix3x3xTest,
           testInit,
           testFromQuaternion,
           testFromMatrix4x4,
           testIdentity,
           testIsEqual,
           testMultiply,
           testScale,
           testRotate,
           testShear,
           testTranspose,
           testDeterminant,
           testInvert,
           testInterpolate,
           testNormalize,
           testMultiplyVector)
