From a380038f5eb2e448d54548f1ff7e3a4b5a800c8f Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Tue, 23 Jul 2024 13:18:02 -0500 Subject: [PATCH] chapter 3 --- .gitignore | 1 + float.h | 9 + matrices.h | 265 +++++++++++++++++++++++++++ test/run.sh | 2 +- test/runner.h | 2 +- test/test_matrices.c | 416 +++++++++++++++++++++++++++++++++++++++++++ tuples.h | 11 +- 7 files changed, 698 insertions(+), 8 deletions(-) create mode 100644 float.h create mode 100644 matrices.h create mode 100644 test/test_matrices.c diff --git a/.gitignore b/.gitignore index 57854d4..93fa848 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,5 @@ *.gch test/test_tuples test/test_canvas +test/test_matrices *.ppm \ No newline at end of file diff --git a/float.h b/float.h new file mode 100644 index 0000000..963704c --- /dev/null +++ b/float.h @@ -0,0 +1,9 @@ +#pragma once + +#include + +inline static bool float_equal(float a, float b) +{ + const float epsilon = 0.00001; + return __builtin_fabs(a - b) < epsilon; +} diff --git a/matrices.h b/matrices.h new file mode 100644 index 0000000..4041818 --- /dev/null +++ b/matrices.h @@ -0,0 +1,265 @@ +#pragma once + +#include "float.h" +#include "tuples.h" + +struct mat4x4 { + float e[4][4]; +}; + +struct mat3x3 { + float e[3][3]; +}; + +struct mat2x2 { + float e[2][2]; +}; + +inline static struct mat4x4 mat4x4(float a1, float a2, float a3, float a4, + float b1, float b2, float b3, float b4, + float c1, float c2, float c3, float c4, + float d1, float d2, float d3, float d4) +{ + return (struct mat4x4){{ + { a1, a2, a3, a4 }, + { b1, b2, b3, b4 }, + { c1, c2, c3, c4 }, + { d1, d2, d3, d4 } + }}; +} + +inline static struct mat3x3 mat3x3(float a1, float a2, float a3, + float b1, float b2, float b3, + float c1, float c2, float c3) +{ + return (struct mat3x3){{ + { a1, a2, a3 }, + { b1, b2, b3 }, + { c1, c2, c3 }, + }}; +} + +inline static struct mat2x2 mat2x2(float a1, float a2, + float b1, float b2) +{ + return (struct mat2x2){{ + { a1, a2 }, + { b1, b2 }, + }}; +} + +inline static bool mat4x4_equal(struct mat4x4 const * const a, + struct mat4x4 const * const b) +{ + return + float_equal(a->e[0][0], b->e[0][0]) && + float_equal(a->e[0][1], b->e[0][1]) && + float_equal(a->e[0][2], b->e[0][2]) && + float_equal(a->e[0][3], b->e[0][3]) && + float_equal(a->e[1][0], b->e[1][0]) && + float_equal(a->e[1][1], b->e[1][1]) && + float_equal(a->e[1][2], b->e[1][2]) && + float_equal(a->e[1][3], b->e[1][3]) && + float_equal(a->e[2][0], b->e[2][0]) && + float_equal(a->e[2][1], b->e[2][1]) && + float_equal(a->e[2][2], b->e[2][2]) && + float_equal(a->e[2][3], b->e[2][3]) && + float_equal(a->e[3][0], b->e[3][0]) && + float_equal(a->e[3][1], b->e[3][1]) && + float_equal(a->e[3][2], b->e[3][2]) && + float_equal(a->e[3][3], b->e[3][3]); +} + +inline static bool mat3x3_equal(struct mat3x3 * a, + struct mat3x3 * b) +{ + return + float_equal(a->e[0][0], b->e[0][0]) && + float_equal(a->e[0][1], b->e[0][1]) && + float_equal(a->e[0][2], b->e[0][2]) && + float_equal(a->e[1][0], b->e[1][0]) && + float_equal(a->e[1][1], b->e[1][1]) && + float_equal(a->e[1][2], b->e[1][2]) && + float_equal(a->e[2][0], b->e[2][0]) && + float_equal(a->e[2][1], b->e[2][1]) && + float_equal(a->e[2][2], b->e[2][2]); +} + +inline static bool mat2x2_equal(struct mat2x2 * a, + struct mat2x2 * b) +{ + return + float_equal(a->e[0][0], b->e[0][0]) && + float_equal(a->e[0][1], b->e[0][1]) && + float_equal(a->e[1][0], b->e[1][0]) && + float_equal(a->e[1][1], b->e[1][1]); +} + +inline static struct mat4x4 mat4x4_mul_m(struct mat4x4 const * const a, + struct mat4x4 const * const b) +{ +#define dot(row, col) \ + a->e[row][0] * b->e[0][col] + \ + a->e[row][1] * b->e[1][col] + \ + a->e[row][2] * b->e[2][col] + \ + a->e[row][3] * b->e[3][col] + + return mat4x4(dot(0, 0), dot(0, 1), dot(0, 2), dot(0, 3), + dot(1, 0), dot(1, 1), dot(1, 2), dot(1, 3), + dot(2, 0), dot(2, 1), dot(2, 2), dot(2, 3), + dot(3, 0), dot(3, 1), dot(3, 2), dot(3, 3) + ); +#undef dot +} + +inline static struct tuple mat4x4_mul_t(struct mat4x4 const * const a, + struct tuple * b) +{ +#define dot(row) \ + a->e[row][0] * b->e[0] + \ + a->e[row][1] * b->e[1] + \ + a->e[row][2] * b->e[2] + \ + a->e[row][3] * b->e[3] + + return tuple(dot(0), dot(1), dot(2), dot(3)); +#undef dot +} + +inline static struct mat4x4 mat4x4_identity() +{ + return mat4x4(1.0f, 0.0f, 0.0f, 0.0f, + 0.0f, 1.0f, 0.0f, 0.0f, + 0.0f, 0.0f, 1.0f, 0.0f, + 0.0f, 0.0f, 0.0f, 1.0f); +} + +inline static struct mat4x4 mat4x4_transpose(struct mat4x4 const * const a) +{ + return mat4x4(a->e[0][0], a->e[1][0], a->e[2][0], a->e[3][0], + a->e[0][1], a->e[1][1], a->e[2][1], a->e[3][1], + a->e[0][2], a->e[1][2], a->e[2][2], a->e[3][2], + a->e[0][3], a->e[1][3], a->e[2][3], a->e[3][3]); +} + +inline static float mat2x2_determinant(struct mat2x2 * a) +{ + return a->e[0][0] * a->e[1][1] - a->e[0][1] * a->e[1][0]; +} + +inline static struct mat2x2 mat3x3_submatrix(struct mat3x3 * a, int r, int c) +{ + struct mat2x2 b; + int row2 = 0; + for (int row3 = 0; row3 < 3; row3++) { + if (row3 == r) continue; + int col2 = 0; + for (int col3 = 0; col3 < 3; col3++) { + if (col3 == c) continue; + b.e[row2][col2] = a->e[row3][col3]; + col2++; + } + row2++; + } + return b; +} + +inline static struct mat3x3 mat4x4_submatrix(struct mat4x4 const * const a, int r, int c) +{ + struct mat3x3 b; + int row3 = 0; + for (int row4 = 0; row4 < 4; row4++) { + if (row4 == r) continue; + int col3 = 0; + for (int col4 = 0; col4 < 4; col4++) { + if (col4 == c) continue; + b.e[row3][col3] = a->e[row4][col4]; + col3++; + } + row3++; + } + return b; +} + +inline static float mat3x3_minor(struct mat3x3 * a, int r, int c) +{ + struct mat2x2 s = mat3x3_submatrix(a, r, c); + float ret = mat2x2_determinant(&s); + return ret; +} + +inline static float mat3x3_cofactor(struct mat3x3 * a, int r, int c) +{ + float minor = mat3x3_minor(a, r, c); + if ((r + c) & 1) + return -minor; + else + return minor; +} + +inline static float mat3x3_determinant(struct mat3x3 * a) +{ + float f0 = mat3x3_cofactor(a, 0, 0); + float f1 = mat3x3_cofactor(a, 0, 1); + float f2 = mat3x3_cofactor(a, 0, 2); + return + a->e[0][0] * f0 + + a->e[0][1] * f1 + + a->e[0][2] * f2; +} + +inline static float mat4x4_minor(struct mat4x4 const * const a, int r, int c) +{ + struct mat3x3 s = mat4x4_submatrix(a, r, c); + float ret = mat3x3_determinant(&s); + return ret; +} + +inline static float mat4x4_cofactor(struct mat4x4 const * const a, int r, int c) +{ + float minor = mat4x4_minor(a, r, c); + if ((r + c) & 1) + return -minor; + else + return minor; +} + +inline static float mat4x4_determinant(struct mat4x4 const * const a) +{ + float f0 = mat4x4_cofactor(a, 0, 0); + float f1 = mat4x4_cofactor(a, 0, 1); + float f2 = mat4x4_cofactor(a, 0, 2); + float f3 = mat4x4_cofactor(a, 0, 3); + return + a->e[0][0] * f0 + + a->e[0][1] * f1 + + a->e[0][2] * f2 + + a->e[0][3] * f3; +} + +inline static bool mat4x4_is_invertible(struct mat4x4 const * const a) +{ + return !float_equal(mat4x4_determinant(a), 0.f); +} + +inline static struct mat4x4 mat4x4_inverse(struct mat4x4 const * const a) +{ + struct mat4x4 m; + float det = mat4x4_determinant(a); + m.e[0][0] = mat4x4_cofactor(a, 0, 0) / det; + m.e[1][0] = mat4x4_cofactor(a, 0, 1) / det; + m.e[2][0] = mat4x4_cofactor(a, 0, 2) / det; + m.e[3][0] = mat4x4_cofactor(a, 0, 3) / det; + m.e[0][1] = mat4x4_cofactor(a, 1, 0) / det; + m.e[1][1] = mat4x4_cofactor(a, 1, 1) / det; + m.e[2][1] = mat4x4_cofactor(a, 1, 2) / det; + m.e[3][1] = mat4x4_cofactor(a, 1, 3) / det; + m.e[0][2] = mat4x4_cofactor(a, 2, 0) / det; + m.e[1][2] = mat4x4_cofactor(a, 2, 1) / det; + m.e[2][2] = mat4x4_cofactor(a, 2, 2) / det; + m.e[3][2] = mat4x4_cofactor(a, 2, 3) / det; + m.e[0][3] = mat4x4_cofactor(a, 3, 0) / det; + m.e[1][3] = mat4x4_cofactor(a, 3, 1) / det; + m.e[2][3] = mat4x4_cofactor(a, 3, 2) / det; + m.e[3][3] = mat4x4_cofactor(a, 3, 3) / det; + return m; +} diff --git a/test/run.sh b/test/run.sh index a8d67f2..04d963d 100644 --- a/test/run.sh +++ b/test/run.sh @@ -2,7 +2,7 @@ set -eux -for name in tuples canvas; do +for name in tuples canvas matrices; do gcc -g -gdwarf-5 \ -Wall -Werror -Wfatal-errors \ -I. \ diff --git a/test/runner.h b/test/runner.h index 0507bed..1986355 100644 --- a/test/runner.h +++ b/test/runner.h @@ -7,7 +7,7 @@ typedef bool (*test_t)(const char ** scenario); { \ int fail_count = 0; \ for (int i = 0; i < (sizeof (tests)) / (sizeof (test_t)); i++) { \ - const char * scenario; \ + const char * scenario = NULL; \ bool result = tests[i](&scenario); \ const char * result_s = result ? "ok" : "fail"; \ fail_count += !result; \ diff --git a/test/test_matrices.c b/test/test_matrices.c new file mode 100644 index 0000000..7071abf --- /dev/null +++ b/test/test_matrices.c @@ -0,0 +1,416 @@ +#include +#include + +#include "matrices.h" +#include "runner.h" + +static bool matrices_test_0(const char ** scenario) +{ + *scenario = "A 4x4 matrix ought to be representable"; + struct mat4x4 m = mat4x4( 1.0f, 2.0f, 3.0f, 4.0f, + 5.5f, 6.5f, 7.5f, 8.5f, + 9.0f, 10.0f, 11.0f, 12.0f, + 13.5f, 14.5f, 15.5f, 16.5f); + return + m.e[0][0] == 1.0f && + m.e[0][3] == 4.0f && + m.e[1][0] == 5.5f && + m.e[1][2] == 7.5f && + m.e[2][2] == 11.0f && + m.e[3][0] == 13.5f && + m.e[3][2] == 15.5f; +} + +static bool matrices_test_1(const char ** scenario) +{ + *scenario = "A 2x2 matrix ought to be representable"; + struct mat2x2 m = mat2x2(-3.0f, 5.0f, + 1.0f, -2.0f); + return + m.e[0][0] == -3.0f && + m.e[0][1] == 5.0f && + m.e[1][0] == 1.0f && + m.e[1][1] == -2.0f; +} + +static bool matrices_test_2(const char ** scenario) +{ + *scenario = "A 3x3 matrix ought to be representable"; + struct mat3x3 m = mat3x3(-3.0f, 5.0f, 0.0f, + 1.0f, -2.0f, -7.0f, + 0.0f, 1.0f, 1.0f); + return + m.e[0][0] == -3.0f && + m.e[1][1] == -2.0f && + m.e[2][2] == 1.0f; +} + +static bool matrices_test_3(const char ** scenario) +{ + *scenario = "Matrix equality with identical matrices"; + struct mat4x4 a = mat4x4(1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.0f, 7.0f, 8.0f, + 9.0f, 8.0f, 7.0f, 6.0f, + 5.0f, 4.0f, 3.0f, 2.0f); + + struct mat4x4 b = mat4x4(1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.0f, 7.0f, 8.0f, + 9.0f, 8.0f, 7.0f, 6.0f, + 5.0f, 4.0f, 3.0f, 2.0f); + + return mat4x4_equal(&a, &b); +} + +static bool matrices_test_4(const char ** scenario) +{ + *scenario = "Matrix equality with different matrices"; + + struct mat4x4 a = mat4x4(1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.0f, 7.0f, 8.0f, + 9.0f, 8.0f, 7.0f, 6.0f, + 5.0f, 4.0f, 3.0f, 2.0f); + + struct mat4x4 b = mat4x4(2.0f, 3.0f, 4.0f, 5.0f, + 6.0f, 7.0f, 8.0f, 9.0f, + 8.0f, 7.0f, 6.0f, 5.0f, + 4.0f, 3.0f, 2.0f, 1.0f); + + return !mat4x4_equal(&a, &b); +} + +static bool matrices_test_5(const char ** scenario) +{ + *scenario = "Multiplying two matrices"; + + struct mat4x4 a = mat4x4(1.0f, 2.0f, 3.0f, 4.0f, + 5.0f, 6.0f, 7.0f, 8.0f, + 9.0f, 8.0f, 7.0f, 6.0f, + 5.0f, 4.0f, 3.0f, 2.0f); + + struct mat4x4 b = mat4x4(-2.0f, 1.0f, 2.0f, 3.0f, + 3.0f, 2.0f, 1.0f, -1.0f, + 4.0f, 3.0f, 6.0f, 5.0f, + 1.0f, 2.0f, 7.0f, 8.0f); + + struct mat4x4 m1 = mat4x4_mul_m(&a, &b); + struct mat4x4 m2 = mat4x4(20.0f, 22.0f, 50.0f, 48.0f, + 44.0f, 54.0f, 114.0f, 108.0f, + 40.0f, 58.0f, 110.0f, 102.0f, + 16.0f, 26.0f, 46.0f, 42.0f); + return mat4x4_equal(&m1, &m2); +} + +static bool matrices_test_6(const char ** scenario) +{ + *scenario = "A matrix multiplied by a tuple"; + + struct mat4x4 a = mat4x4(1.0f, 2.0f, 3.0f, 4.0f, + 2.0f, 4.0f, 4.0f, 2.0f, + 8.0f, 6.0f, 4.0f, 1.0f, + 0.0f, 0.0f, 0.0f, 1.0f); + struct tuple b = tuple(1.0f, 2.0f, 3.0f, 1.0f); + + struct tuple c = mat4x4_mul_t(&a, &b); + return tuple_equal(c, tuple(18, 24, 33, 1)); +} + +static bool matrices_test_7(const char ** scenario) +{ + *scenario = "Multiplying a matrix by the identity matrix"; + + struct mat4x4 a = mat4x4(0.0f, 1.0f, 2.0f, 4.0f, + 1.0f, 2.0f, 4.0f, 8.0f, + 2.0f, 4.0f, 8.0f, 16.0f, + 4.0f, 8.0f, 16.0f, 32.0f); + + struct mat4x4 id = mat4x4_identity(); + struct mat4x4 c = mat4x4_mul_m(&a, &id); + return mat4x4_equal(&a, &c); +} + +static bool matrices_test_8(const char ** scenario) +{ + *scenario = "Multiplying a the identity matrix by a tuple"; + + struct tuple a = tuple(1.0f, 2.0f, 3.0f, 4.0f); + + struct mat4x4 id = mat4x4_identity(); + struct tuple c = mat4x4_mul_t(&id, &a); + return tuple_equal(a, c); +} + +static bool matrices_test_9(const char ** scenario) +{ + *scenario = "Transposing a matrix"; + + struct mat4x4 a = mat4x4(0.0f, 9.0f, 3.0f, 0.0f, + 9.0f, 8.0f, 0.0f, 8.0f, + 1.0f, 8.0f, 5.0f, 3.0f, + 0.0f, 0.0f, 5.0f, 8.0f); + + struct mat4x4 b = mat4x4(0.0f, 9.0f, 1.0f, 0.0f, + 9.0f, 8.0f, 8.0f, 0.0f, + 3.0f, 0.0f, 5.0f, 5.0f, + 0.0f, 8.0f, 3.0f, 8.0f); + + struct mat4x4 c = mat4x4_transpose(&a); + + return mat4x4_equal(&c, &b); +} + +static bool matrices_test_10(const char ** scenario) +{ + *scenario = "Transposing the identity matrix"; + + struct mat4x4 a = mat4x4_identity(); + + struct mat4x4 c = mat4x4_transpose(&a); + + return mat4x4_equal(&a, &c); +} + +static bool matrices_test_11(const char ** scenario) +{ + *scenario = "Calculating the determinant of a 2x2 matrix"; + + struct mat2x2 a = mat2x2( 1.0f, 5.0f, + -3.0f, 2.0f); + + return float_equal(mat2x2_determinant(&a), 17); +} + +static bool matrices_test_12(const char ** scenario) +{ + *scenario = "A submatrix of a 3x3 matrix is a 2x2 matrix"; + + struct mat3x3 a = mat3x3( 1.0f, 5.0f, 0.0f, + -3.0f, 2.0f, 7.0f, + 0.0f, 6.0f, -3.0f); + + struct mat2x2 b = mat3x3_submatrix(&a, 0, 2); + struct mat2x2 c = mat2x2(-3.0f, 2.0f, + 0.0f, 6.0f); + + return mat2x2_equal(&b, &c); +} + +static bool matrices_test_13(const char ** scenario) +{ + *scenario = "A submatrix of a 4x4 matrix is a 3x3 matrix"; + + struct mat4x4 a = mat4x4(-6.0f, 1.0f, 1.0f, 6.0f, + -8.0f, 5.0f, 8.0f, 6.0f, + -1.0f, 0.0f, 8.0f, 2.0f, + -7.0f, 1.0f, -1.0f, 1.0f); + + struct mat3x3 b = mat4x4_submatrix(&a, 2, 1); + struct mat3x3 c = mat3x3(-6.0f, 1.0f, 6.0f, + -8.0f, 8.0f, 6.0f, + -7.0f, -1.0f, 1.0f); + + return mat3x3_equal(&b, &c); +} + +static bool matrices_test_14(const char ** scenario) +{ + *scenario = "Calculating a minor of a 3x3 matrix"; + + struct mat3x3 a = mat3x3(3, 5, 0, + 2, -1, -7, + 6, -1, 5); + struct mat2x2 b = mat3x3_submatrix(&a, 1, 0); + + return + float_equal(mat2x2_determinant(&b), 25.0f) && + float_equal(mat3x3_minor(&a, 1, 0), 25.0f); +} + +static bool matrices_test_15(const char ** scenario) +{ + *scenario = "Calculating a cofactor of a 3x3 matrix"; + + struct mat3x3 a = mat3x3(3, 5, 0, + 2, -1, -7, + 6, -1, 5); + + return + float_equal(mat3x3_minor(&a, 0, 0), -12.0f) && + float_equal(mat3x3_cofactor(&a, 0, 0), -12.0f) && + float_equal(mat3x3_minor(&a, 1, 0), 25.0f) && + float_equal(mat3x3_cofactor(&a, 1, 0), -25.0f) && + float_equal(mat3x3_cofactor(&a, 2, 1), 21.0f); + +} + +static bool matrices_test_16(const char ** scenario) +{ + *scenario = "Calculating the determinant of a 3x3 matrix"; + + struct mat3x3 a = mat3x3( 1.0f, 2.0f, 6.0f, + -5.0f, 8.0f, -4.0f, + 2.0f, 6.0f, 4.0f); + + return + float_equal(mat3x3_cofactor(&a, 0, 0), 56.0f) && + float_equal(mat3x3_cofactor(&a, 0, 1), 12.0f) && + float_equal(mat3x3_cofactor(&a, 0, 2), -46.0f) && + float_equal(mat3x3_determinant(&a), -196.0f); +} + +static bool matrices_test_17(const char ** scenario) +{ + *scenario = "Calculating the determinant of a 4x4 matrix"; + + struct mat4x4 a = mat4x4(-2.0f, -8.0f, 3.0f, 5.0f, + -3.0f, 1.0f, 7.0f, 3.0f, + 1.0f, 2.0f, -9.0f, 6.0f, + -6.0f, 7.0f, 7.0f, -9.0f); + + return + float_equal(mat4x4_cofactor(&a, 0, 0), 690.0f) && + float_equal(mat4x4_cofactor(&a, 0, 1), 447.0f) && + float_equal(mat4x4_cofactor(&a, 0, 2), 210.0f) && + float_equal(mat4x4_cofactor(&a, 0, 3), 51.0f) && + float_equal(mat4x4_determinant(&a), -4071.0f); +} + +static bool matrices_test_18(const char ** scenario) +{ + *scenario = "Testing an invertible matrix for invertibility"; + + struct mat4x4 a = mat4x4(6.0f, 4.0f, 4.0f, 4.0f, + 5.0f, 5.0f, 7.0f, 6.0f, + 4.0f, -9.0f, 3.0f, -7.0f, + 9.0f, 1.0f, 7.0f, -6.0f); + + return + float_equal(mat4x4_determinant(&a), -2120.0f) && + mat4x4_is_invertible(&a); +} + +static bool matrices_test_19(const char ** scenario) +{ + *scenario = "Testing a noninvertible matrix for invertibility"; + + struct mat4x4 a = mat4x4(-4.0f, 2.0f, -2.0f, -3.0f, + 9.0f, 6.0f, 2.0f, 6.0f, + 0.0f, -5.0f, 1.0f, -5.0f, + 0.0f, 0.0f, 0.0f, 0.0f); + + return + float_equal(mat4x4_determinant(&a), 0.0f) && + !mat4x4_is_invertible(&a); +} + +static bool matrices_test_20(const char ** scenario) +{ + *scenario = "Calculating the inverse of a matrix"; + + struct mat4x4 a = mat4x4(-5.0, 2.0, 6.0, -8.0, + 1.0, -5.0, 1.0, 8.0, + 7.0, 7.0, -6.0, -7.0, + 1.0, -3.0, 7.0, 4.0); + struct mat4x4 b = mat4x4_inverse(&a); + + struct mat4x4 c = mat4x4( 0.218045f, 0.451128f, 0.240602f, -0.045113f, + -0.808271f, -1.456767f, -0.443609f, 0.520677f, + -0.078947f, -0.223684f, -0.052632f, 0.197368f, + -0.522564f, -0.813910f, -0.300752f, 0.306391f); + + return + float_equal(mat4x4_determinant(&a), 532.0f) && + float_equal(mat4x4_cofactor(&a, 2, 3), -160.0f) && + float_equal(b.e[3][2], -160.0f/532.0f) && + float_equal(mat4x4_cofactor(&a, 3, 2), 105.0f) && + float_equal(b.e[2][3], 105.0f/532.0f) && + mat4x4_equal(&b, &c); +} + +static bool matrices_test_21(const char ** scenario) +{ + *scenario = "Calculating the inverse of a second matrix"; + + struct mat4x4 a = mat4x4( 8.0f, -5.0f, 9.0f, 2.0f, + 7.0f, 5.0f, 6.0f, 1.0f, + -6.0f, 0.0f, 9.0f, 6.0f, + -3.0f, 0.0f, -9.0f, -4.0f); + + struct mat4x4 b = mat4x4_inverse(&a); + + struct mat4x4 c = mat4x4(-0.15385f, -0.15385f, -0.28205f, -0.53846f, + -0.07692f, 0.12308f, 0.02564f, 0.03077f, + 0.35897f, 0.35897f, 0.43590f, 0.92308f, + -0.69231f, -0.69231f, -0.76923f, -1.92308f); + + return mat4x4_equal(&b, &c); +} + +static bool matrices_test_22(const char ** scenario) +{ + *scenario = "Calculating the inverse of a third matrix"; + + struct mat4x4 a = mat4x4( 9.0f, 3.0f, 0.0f, 9.0f, + -5.0f, -2.0f, -6.0f, -3.0f, + -4.0f, 9.0f, 6.0f, 4.0f, + -7.0f, 6.0f, 6.0f, 2.0f); + + struct mat4x4 b = mat4x4_inverse(&a); + + struct mat4x4 c = mat4x4(-0.04074f, -0.07778f, 0.14444f, -0.22222f, + -0.07778f, 0.03333f, 0.36667f, -0.33333f, + -0.02901f, -0.14630f, -0.10926f, 0.12963f, + 0.17778f, 0.06667f, -0.26667f, 0.33333f); + + return mat4x4_equal(&b, &c); +} + +static bool matrices_test_23(const char ** scenario) +{ + *scenario = "Multiplying a product by its inverse"; + + struct mat4x4 a = mat4x4( 3.0f, -9.0f, 7.0f, 3.0f, + 3.0f, -8.0f, 2.0f, -9.0f, + -4.0f, 4.0f, 4.0f, 1.0f, + -6.0f, 5.0f, -1.0f, 1.0f); + + struct mat4x4 b = mat4x4( 8.0f, 2.0f, 2.0f, 2.0f, + 3.0f, -1.0f, 7.0f, 0.0f, + 7.0f, 0.0f, 5.0f, 4.0f, + 6.0f, -2.0f, 0.0f, 5.0f); + + struct mat4x4 c = mat4x4_mul_m(&a, &b); + + struct mat4x4 b_i = mat4x4_inverse(&b); + struct mat4x4 d = mat4x4_mul_m(&c, &b_i); + + return mat4x4_equal(&d, &a); +} + +test_t matrices_tests[] = { + matrices_test_0, + matrices_test_1, + matrices_test_2, + matrices_test_3, + matrices_test_4, + matrices_test_5, + matrices_test_6, + matrices_test_7, + matrices_test_8, + matrices_test_9, + matrices_test_10, + matrices_test_11, + matrices_test_12, + matrices_test_13, + matrices_test_14, + matrices_test_15, + matrices_test_16, + matrices_test_17, + matrices_test_18, + matrices_test_19, + matrices_test_20, + matrices_test_21, + matrices_test_22, + matrices_test_23, +}; + +RUNNER(matrices_tests) diff --git a/tuples.h b/tuples.h index bbdd9d7..8dd8e64 100644 --- a/tuples.h +++ b/tuples.h @@ -1,5 +1,7 @@ #pragma once +#include "float.h" + struct tuple { union { struct { @@ -14,15 +16,12 @@ struct tuple { float b; float a; }; + struct { + float e[4]; + }; }; }; -inline static bool float_equal(float a, float b) -{ - const float epsilon = 0.00001; - return __builtin_fabs(a - b) < epsilon; -} - inline static struct tuple tuple(float x, float y, float z, float w) { return (struct tuple){{{ x, y, z, w }}};