#include #include #include "transformations.h" #include "runner.h" static bool transformations_test_0(const char ** scenario) { *scenario = "Multiplying by a translation matrix"; struct mat4x4 transform = translation(5.0f, -3.0f, 2.0f); struct tuple p = point(-3.0f, 4.0f, 5.0f); return tuple_equal(mat4x4_mul_t(&transform, &p), point(2.0f, 1.0f, 7.0f)); } static bool transformations_test_1(const char ** scenario) { *scenario = "Multiplying by the inverse of a translation matrix"; struct mat4x4 transform = translation(5.0f, -3.0f, 2.0f); struct mat4x4 inv = mat4x4_inverse(&transform); struct tuple p = point(-3.0f, 4.0f, 5.0f); return tuple_equal(mat4x4_mul_t(&inv, &p), point(-8.0f, 7.0f, 3.0f)); } static bool transformations_test_2(const char ** scenario) { *scenario = "Translation does not affect vectors"; struct mat4x4 transform = translation(5.0f, -3.0f, 2.0f); struct tuple v = vector(-3.0f, 4.0f, 5.0f); return tuple_equal(mat4x4_mul_t(&transform, &v), v); } static bool transformations_test_3(const char ** scenario) { *scenario = "A scaling matrix applied to a point"; struct mat4x4 transform = scaling(2.0f, 3.0f, 4.0f); struct tuple p = point(-4.0f, 6.0f, 8.0f); return tuple_equal(mat4x4_mul_t(&transform, &p), point(-8.0f, 18.0f, 32.0f)); } static bool transformations_test_4(const char ** scenario) { *scenario = "A scaling matrix applied to a vector"; struct mat4x4 transform = scaling(2.0f, 3.0f, 4.0f); struct tuple v = vector(-4.0f, 6.0f, 8.0f); return tuple_equal(mat4x4_mul_t(&transform, &v), vector(-8.0f, 18.0f, 32.0f)); } static bool transformations_test_5(const char ** scenario) { *scenario = "Multiplying by the inverse of a scaling matrix"; struct mat4x4 transform = scaling(2.0f, 3.0f, 4.0f); struct mat4x4 inv = mat4x4_inverse(&transform); struct tuple v = vector(-4.0f, 6.0f, 8.0f); return tuple_equal(mat4x4_mul_t(&inv, &v), vector(-2.0f, 2.0f, 2.0f)); } static bool transformations_test_6(const char ** scenario) { *scenario = "Reflection is scaling by a negative value"; struct mat4x4 transform = scaling(-1.0f, 1.0f, 1.0f); struct tuple p = point(2.0f, 3.0f, 4.0f); return tuple_equal(mat4x4_mul_t(&transform, &p), point(-2.0f, 3.0f, 4.0f)); } static bool transformations_test_7(const char ** scenario) { *scenario = "Rotating a point around the x axis"; struct tuple p = point(0.0f, 1.0f, 0.0f); struct mat4x4 half_quarter = rotation_x(tau / 8); struct mat4x4 full_quarter = rotation_x(tau / 4); return tuple_equal(mat4x4_mul_t(&half_quarter, &p), point(0.0f, 0.7071067811865476, 0.7071067811865476)) && tuple_equal(mat4x4_mul_t(&full_quarter, &p), point(0.0f, 0.0f, 1.0f)); } static bool transformations_test_8(const char ** scenario) { *scenario = "Rotating a point around the y axis"; struct tuple p = point(0.0f, 0.0f, 1.0f); struct mat4x4 half_quarter = rotation_y(tau / 8); struct mat4x4 full_quarter = rotation_y(tau / 4); return tuple_equal(mat4x4_mul_t(&half_quarter, &p), point(0.7071067811865476, 0.0f, 0.7071067811865476)) && tuple_equal(mat4x4_mul_t(&full_quarter, &p), point(1.0f, 0.0f, 0.0f)); } static bool transformations_test_9(const char ** scenario) { *scenario = "Rotating a point around the z axis"; struct tuple p = point(0.0f, 1.0f, 0.0f); struct mat4x4 half_quarter = rotation_z(tau / 8); struct mat4x4 full_quarter = rotation_z(tau / 4); return tuple_equal(mat4x4_mul_t(&half_quarter, &p), point(-0.7071067811865476, 0.7071067811865476, 0.0f)) && tuple_equal(mat4x4_mul_t(&full_quarter, &p), point(-1.0f, 0.0f, 0.0f)); } static bool transformations_test_10(const char ** scenario) { *scenario = "A shearing transformation moves x in proportion to y"; struct mat4x4 transform = shearing(1.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f); struct tuple p = point(2.0f, 3.0f, 4.0f); return tuple_equal(mat4x4_mul_t(&transform, &p), point(5.0f, 3.0f, 4.0f)); } static bool transformations_test_11(const char ** scenario) { *scenario = "A shearing transformation moves x in proportion to z"; struct mat4x4 transform = shearing(0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 0.0f); struct tuple p = point(2.0f, 3.0f, 4.0f); return tuple_equal(mat4x4_mul_t(&transform, &p), point(6.0f, 3.0f, 4.0f)); } static bool transformations_test_12(const char ** scenario) { *scenario = "A shearing transformation moves y in proportion to x"; struct mat4x4 transform = shearing(0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); struct tuple p = point(2.0f, 3.0f, 4.0f); return tuple_equal(mat4x4_mul_t(&transform, &p), point(2.0f, 5.0f, 4.0f)); } static bool transformations_test_13(const char ** scenario) { *scenario = "A shearing transformation moves y in proportion to z"; struct mat4x4 transform = shearing(0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f); struct tuple p = point(2.0f, 3.0f, 4.0f); return tuple_equal(mat4x4_mul_t(&transform, &p), point(2.0f, 7.0f, 4.0f)); } static bool transformations_test_14(const char ** scenario) { *scenario = "A shearing transformation moves z in proportion to x"; struct mat4x4 transform = shearing(0.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f); struct tuple p = point(2.0f, 3.0f, 4.0f); return tuple_equal(mat4x4_mul_t(&transform, &p), point(2.0f, 3.0f, 6.0f)); } static bool transformations_test_15(const char ** scenario) { *scenario = "A shearing transformation moves z in proportion to y"; struct mat4x4 transform = shearing(0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 1.0f); struct tuple p = point(2.0f, 3.0f, 4.0f); return tuple_equal(mat4x4_mul_t(&transform, &p), point(2.0f, 3.0f, 7.0f)); } static bool transformations_test_16(const char ** scenario) { *scenario = "Individual transforms are applied in sequence"; struct tuple p = point(1.0f, 0.0f, 1.0f); struct mat4x4 a = rotation_x(tau / 4.0f); struct mat4x4 b = scaling(5.0f, 5.0f, 5.0f); struct mat4x4 c = translation(10.0f, 5.0f, 7.0f); struct tuple p2 = mat4x4_mul_t(&a, &p); struct tuple p3 = mat4x4_mul_t(&b, &p2); struct tuple p4 = mat4x4_mul_t(&c, &p3); return tuple_equal(p2, point(1.0f, -1.0f, 0.0f)) && tuple_equal(p3, point(5.0f, -5.0f, 0.0f)) && tuple_equal(p4, point(15.0f, 0.0f, 7.0f)); } static bool transformations_test_17(const char ** scenario) { *scenario = "Chained transformations must be applied in reverse order"; struct tuple p = point(1.0f, 0.0f, 1.0f); struct mat4x4 a = rotation_x(tau / 4.0f); struct mat4x4 b = scaling(5.0f, 5.0f, 5.0f); struct mat4x4 c = translation(10.0f, 5.0f, 7.0f); struct mat4x4 t1 = mat4x4_mul_m(&c, &b); struct mat4x4 t2 = mat4x4_mul_m(&t1, &a); struct tuple p1 = mat4x4_mul_t(&t2, &p); return tuple_equal(p1, point(15.0f, 0.0f, 7.0f)); } static bool transformations_test_18(const char ** scenario) { *scenario = "The transformation matrix for the default orientation"; struct tuple from = point(0.0f, 0.0f, 0.0f); struct tuple to = point(0.0f, 0.0f, -1.0f); struct tuple up = vector(0.0f, 1.0f, 0.0f); struct mat4x4 t = view_transform(from, to, up); struct mat4x4 identity_matrix = mat4x4_identity(); return mat4x4_equal(&t, &identity_matrix); } static bool transformations_test_19(const char ** scenario) { *scenario = "A view transformation matrix looking in positive Z direction"; struct tuple from = point(0.0f, 0.0f, 0.0f); struct tuple to = point(0.0f, 0.0f, 1.0f); struct tuple up = vector(0.0f, 1.0f, 0.0f); struct mat4x4 t = view_transform(from, to, up); struct mat4x4 scaled = scaling(-1.0f, 1.0f, -1.0f); return mat4x4_equal(&t, &scaled); } static bool transformations_test_20(const char ** scenario) { *scenario = "The view transformation moves the world"; struct tuple from = point(0.0f, 0.0f, 8.0f); struct tuple to = point(0.0f, 0.0f, 0.0f); struct tuple up = vector(0.0f, 1.0f, 0.0f); struct mat4x4 t = view_transform(from, to, up); struct mat4x4 translated = translation(0.0f, 0.0f, -8.0f); return mat4x4_equal(&t, &translated); } static bool transformations_test_21(const char ** scenario) { *scenario = "An arbitrary view transformation"; struct tuple from = point(1.0f, 3.0f, 2.0f); struct tuple to = point(4.0f, -2.0f, 8.0f); struct tuple up = vector(1.0f, 1.0f, 0.0f); struct mat4x4 t = view_transform(from, to, up); struct mat4x4 expected = mat4x4(-0.50709f, 0.50709f, 0.67612f, -2.36643f, 0.76772f, 0.60609f, 0.12122f, -2.82843f, -0.35857f, 0.59761f, -0.71714f, 0.00000f, 0.00000f, 0.00000f, 0.00000f, 1.00000f ); return mat4x4_equal(&t, &expected); } test_t transformations_tests[] = { transformations_test_0, transformations_test_1, transformations_test_2, transformations_test_3, transformations_test_4, transformations_test_5, transformations_test_6, transformations_test_7, transformations_test_8, transformations_test_9, transformations_test_10, transformations_test_11, transformations_test_12, transformations_test_13, transformations_test_14, transformations_test_15, transformations_test_16, transformations_test_17, transformations_test_18, transformations_test_19, transformations_test_20, transformations_test_21, }; RUNNER(transformations_tests)