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

#define assertMatrix(matrix, expected0, expected3, expected6, \
                             expected1, expected4, expected7, \
                             expected2, expected5, expected8) { \
	fixed16_16 expectedValues[9] = {expected0, expected1, expected2, expected3, expected4, expected5, expected6, expected7, expected8}; \
	for (unsigned int index = 0; index < 9; index++) { \
		TestCase_assert(matrix.m[index] == expectedValues[index], "Expected matrix: {0x%05X, 0x%05X, 0x%05X,\n                  0x%05X, 0x%05X, 0x%05X,\n                  0x%05X, 0x%05X, 0x%05X}\nActual matrix: {0x%05X, 0x%05X, 0x%05X,\n                0x%05X, 0x%05X, 0x%05X,\n                0x%05X, 0x%05X, 0x%05X} (nonmatching index %u)", expected0, expected3, expected6, expected1, expected4, expected7, expected2, expected5, expected8, matrix.m[0], matrix.m[3], matrix.m[6], matrix.m[1], matrix.m[4], matrix.m[7], matrix.m[2], matrix.m[5], matrix.m[8], index); \
	} \
}

#define assertVector2x(vector, expectedX, expectedY) \
	TestCase_assert(vector.x == expectedX && vector.y == expectedY, "Expected {0x%05X, 0x%05X} but got {0x%05X, 0x%05X}", expectedX, expectedY, vector.x, vector.y);

#define assertVector3x(vector, expectedX, expectedY, expectedZ) \
	TestCase_assert(vector.x == expectedX && vector.y == expectedY && vector.z == expectedZ, "Expected {0x%05X, 0x%05X, 0x%05X} but got {0x%05X, 0x%05X, 0x%05X}", expectedX, expectedY, expectedZ, vector.x, vector.y, vector.z);

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

static void testFromQuaternion(void) {
	Matrix3x3x matrix;
	
	matrix = Matrix3x3x_fromQuaternionx(QUATERNIONx(0x00000, 0x00000, 0x00000, 0x10000));
	assertMatrix(matrix, 0x10000, 0x00000, 0x00000,
	                     0x00000, 0x10000, 0x00000,
	                     0x00000, 0x00000, 0x10000);
	
	matrix = Matrix3x3x_fromQuaternionx(QUATERNIONx(0x00000, 0x0B504, 0x00000, 0x0B504));
	assertMatrix(matrix,  0x00002, 0x00000, 0x0FFFE,
	                      0x00000, 0x10000, 0x00000,
	                     -0x0FFFE, 0x00000, 0x00002);
	
	matrix = Matrix3x3x_fromQuaternionx(QUATERNIONx(0x08000, 0x08000, 0x08000, 0x08000));
	assertMatrix(matrix, 0x00000, 0x00000, 0x10000,
	                     0x10000, 0x00000, 0x00000,
	                     0x00000, 0x10000, 0x00000);
	
	matrix = Matrix3x3x_fromQuaternionx(QUATERNIONx(0x10000, 0x10000, 0x10000, 0x10000));
	assertMatrix(matrix, -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));
	assertMatrix(matrix, 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));
	assertMatrix(matrix, 1, 2,  3,
	                     5, 6,  7,
	                     9, 10, 11);
}

static void testIdentity(void) {
	Matrix3x3x matrix;
	
	matrix = MATRIX3x3x_IDENTITY;
	assertMatrix(matrix, 0x10000, 0x00000, 0x00000,
	                     0x00000, 0x10000, 0x00000,
	                     0x00000, 0x00000, 0x10000);
	
	memset(matrix.m, 0xFF, sizeof(fixed16_16) * 9);
	Matrix3x3x_loadIdentity(&matrix);
	assertMatrix(matrix, 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));
	assertMatrix(matrix, 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));
	assertMatrix(matrix, 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));
	assertMatrix(matrix, 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));
	assertMatrix(matrix, 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));
	assertMatrix(matrix, 0x180000, 0x570000, 0xA50000,
	                     0x1E0000, 0x6E0000, 0xD60000,
	                     0x240000, 0x850000, 0x1070000);
}

static void testScale(void) {
	Matrix3x3x matrix;
	
	matrix = Matrix3x3x_scaled(MATRIX3x3x_IDENTITY, V3x(0x20000, -0x10000, 0x08000));
	assertMatrix(matrix, 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));
	assertMatrix(matrix, 0x00000, 0x00000, 0x08000,
	                     0x60000, 0x00000, 0x00000,
	                     0x00000, 0x24000, 0x00000);
	
	matrix = MATRIX3x3x_IDENTITY;
	Matrix3x3x_scale(&matrix, V3x(0x20000, -0x10000, 0x08000));
	assertMatrix(matrix, 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));
	assertMatrix(matrix, 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);
	assertMatrix(matrix, -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));
	assertMatrix(matrix, 0x20000,  0x00000, 0x00000,
	                     0x00000,  0x00000, 0x1FF9C,
	                     0x00000, -0x1FF9C, 0x00000);
	
	matrix = MATRIX3x3x_IDENTITY;
	Matrix3x3x_rotate(&matrix, VECTOR3x(0x00000, 0x10000, 0x00000), X_PI);
	assertMatrix(matrix, -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));
	assertMatrix(matrix, 0x20000,  0x00000, 0x00000,
	                     0x00000,  0x00000, 0x1FF9C,
	                     0x00000, -0x1FF9C, 0x00000);
}

static void testShear(void) {
	Matrix3x3x matrix;
	
	matrix = Matrix3x3x_shearedX(MATRIX3x3x_IDENTITY, 0x10000, 0x10000);
	assertMatrix(matrix, 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);
	assertMatrix(matrix, -0x08000, 0x00000, 0x10000,
	                      0x10000, 0x00000, 0x00000,
	                      0x08000, 0x10000, 0x00000);
	
	matrix = Matrix3x3x_shearedY(MATRIX3x3x_IDENTITY, 0x10000, 0x10000);
	assertMatrix(matrix, 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);
	assertMatrix(matrix, 0x00000, -0x08000, 0x10000,
	                     0x10000,  0x08000, 0x00000,
	                     0x00000,  0x10000, 0x00000);
	
	matrix = Matrix3x3x_shearedZ(MATRIX3x3x_IDENTITY, 0x10000, 0x10000);
	assertMatrix(matrix, 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);
	assertMatrix(matrix, 0x00000, 0x00000,  0x10000,
	                     0x10000, 0x00000,  0x08000,
	                     0x00000, 0x10000, -0x08000);
	
	matrix = MATRIX3x3x_IDENTITY;
	Matrix3x3x_shearX(&matrix, 0x10000, 0x10000);
	assertMatrix(matrix, 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);
	assertMatrix(matrix, -0x08000, 0x00000, 0x10000,
	                      0x10000, 0x00000, 0x00000,
	                      0x08000, 0x10000, 0x00000);
	
	matrix = MATRIX3x3x_IDENTITY;
	Matrix3x3x_shearY(&matrix, 0x10000, 0x10000);
	assertMatrix(matrix, 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);
	assertMatrix(matrix, 0x00000, -0x08000, 0x10000,
	                     0x10000,  0x08000, 0x00000,
	                     0x00000,  0x10000, 0x00000);
	
	matrix = MATRIX3x3x_IDENTITY;
	Matrix3x3x_shearZ(&matrix, 0x10000, 0x10000);
	assertMatrix(matrix, 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);
	assertMatrix(matrix, 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));
	assertMatrix(matrix, 0x10000, 0x10000, 0x10000,
	                     0x00000, 0x10000, 0x10000,
	                     0x00000, 0x00000, 0x10000);
	
	matrix = Matrix3x3x_transposed(MATRIX3x3x(0x00000, 0x06666, 0x0CCCC,
	                                          0x01999, 0x08000, 0x0E666,
	                                          0x03333, 0x09999, 0x10000));
	assertMatrix(matrix, 0x00000, 0x01999, 0x03333,
	                     0x06666, 0x08000, 0x09999,
	                     0x0CCCC, 0x0E666, 0x10000);
	
	matrix = MATRIX3x3x(0x10000, 0x00000, 0x00000,
	                    0x10000, 0x10000, 0x00000,
	                    0x10000, 0x10000, 0x10000);
	Matrix3x3x_transpose(&matrix);
	assertMatrix(matrix, 0x10000, 0x10000, 0x10000,
	                     0x00000, 0x10000, 0x10000,
	                     0x00000, 0x00000, 0x10000);
	
	matrix = MATRIX3x3x(0x00000, 0x06666, 0x0CCCC,
	                    0x01999, 0x08000, 0x0E666,
	                    0x03333, 0x09999, 0x10000);
	Matrix3x3x_transpose(&matrix);
	assertMatrix(matrix, 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);
	assertMatrix(matrix, 0x10000, 0x00000, 0x00000,
	                     0x00000, 0x10000, 0x00000,
	                     0x00000, 0x00000, 0x10000);
	
	matrix = Matrix3x3x_inverted(MATRIX3x3x(0x00000, 0x00000, 0x20000,
	                                        0x20000, 0x00000, 0x00000,
	                                        0x00000, 0x20000, 0x00000));
	assertMatrix(matrix, 0x00000, 0x08000, 0x00000,
	                     0x00000, 0x00000, 0x08000,
	                     0x08000, 0x00000, 0x00000);
	
	matrix = MATRIX3x3x_IDENTITY;
	Matrix3x3x_invert(&matrix);
	assertMatrix(matrix, 0x10000, 0x00000, 0x00000,
	                     0x00000, 0x10000, 0x00000,
	                     0x00000, 0x00000, 0x10000);
	
	matrix = MATRIX3x3x(0x00000, 0x00000, 0x20000,
	                    0x20000, 0x00000, 0x00000,
	                    0x00000, 0x20000, 0x00000);
	Matrix3x3x_invert(&matrix);
	assertMatrix(matrix, 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);
	assertMatrix(matrixInterpolated, 0x10000, 0x00000, 0x00000,
	                                 0x00000, 0x10000, 0x00000,
	                                 0x00000, 0x00000, 0x10000);
	
	matrixInterpolated = Matrix3x3x_interpolated(matrixLeft, matrixRight, 0x04000);
	assertMatrix(matrixInterpolated, 0x0C000, 0x04000, 0x04000,
	                                 0x04000, 0x0C000, 0x04000,
	                                 0x04000, 0x04000, 0x0C000);
	
	matrixInterpolated = matrixLeft;
	Matrix3x3x_interpolate(&matrixInterpolated, matrixRight, 0x00000);
	assertMatrix(matrixInterpolated, 0x10000, 0x00000, 0x00000,
	                                 0x00000, 0x10000, 0x00000,
	                                 0x00000, 0x00000, 0x10000);
	
	matrixInterpolated = matrixLeft;
	Matrix3x3x_interpolate(&matrixInterpolated, matrixRight, 0x04000);
	assertMatrix(matrixInterpolated, 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);
	assertMatrix(matrixInterpolated, -0x10000, 0x80000, 0x100000,
	                                  0x20000, 0x90000, 0x120000,
	                                  0x40000, 0xC0000, 0x130000);
	
	matrixInterpolated = Matrix3x3x_interpolated(matrixLeft, matrixRight, 0x20000);
	assertMatrix(matrixInterpolated,  0x20000, -0x40000, -0x80000,
	                                 -0x10000, -0x30000, -0x90000,
	                                 -0x20000, -0x60000, -0x80000);
	
	matrixInterpolated = matrixLeft;
	Matrix3x3x_interpolate(&matrixInterpolated, matrixRight, -0x10000);
	assertMatrix(matrixInterpolated, -0x10000, 0x80000, 0x100000,
	                                  0x20000, 0x90000, 0x120000,
	                                  0x40000, 0xC0000, 0x130000);
	
	matrixInterpolated = matrixLeft;
	Matrix3x3x_interpolate(&matrixInterpolated, matrixRight, 0x20000);
	assertMatrix(matrixInterpolated,  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);
	assertMatrix(normalizedMatrix, 0x10000, 0x00000, 0x00000,
	                               0x00000, 0x10000, 0x00000,
	                               0x00000, 0x00000, 0x10000);
	Matrix3x3x_normalize(&matrix);
	assertMatrix(matrix, 0x10000, 0x00000, 0x00000,
	                     0x00000, 0x10000, 0x00000,
	                     0x00000, 0x00000, 0x10000);
	
	matrix = MATRIX3x3x(0x00000,  0x10000, -0x10000,
	                   -0x10000,  0x00000,  0x10000,
	                   -0x10000, -0x10000,  0x00000);
	normalizedMatrix = Matrix3x3x_normalized(matrix);
	assertMatrix(normalizedMatrix, 0x00000,  0x0B505, -0x0B505,
	                              -0x0B505,  0x00000,  0x0B505,
	                              -0x0B505, -0x0B505,  0x00000);
	Matrix3x3x_normalize(&matrix);
	assertMatrix(matrix, 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));
	assertVector2x(vector2, 0x10000, 0x00000);
	
	vector3 = Matrix3x3x_multiplyVector3x(matrix, VECTOR3x(0x00000, 0x10000, 0x00000));
	assertVector3x(vector3, 0x00000, 0x10000, 0x00000);
	
	matrix = MATRIX3x3x(0x00000, 0x20000,  0x00000,
	                    0x20000, 0x00000,  0x00000,
	                    0x00000, 0x00000, -0x20000);
	vector2 = Matrix3x3x_multiplyVector2x(matrix, VECTOR2x(-0x10000, 0x10000));
	assertVector2x(vector2, 0x20000, -0x20000);
	
	vector3 = Matrix3x3x_multiplyVector3x(matrix, VECTOR3x(0x00000, -0x10000, 0x00000));
	assertVector3x(vector3, -0x20000, 0x00000, 0x00000);
}

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