chapter 3

This commit is contained in:
Zack Buhman 2024-07-23 13:18:02 -05:00
parent e889e1fb75
commit a380038f5e
7 changed files with 698 additions and 8 deletions

1
.gitignore vendored
View File

@ -2,4 +2,5 @@
*.gch
test/test_tuples
test/test_canvas
test/test_matrices
*.ppm

9
float.h Normal file
View File

@ -0,0 +1,9 @@
#pragma once
#include <stdbool.h>
inline static bool float_equal(float a, float b)
{
const float epsilon = 0.00001;
return __builtin_fabs(a - b) < epsilon;
}

265
matrices.h Normal file
View File

@ -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;
}

View File

@ -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. \

View File

@ -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; \

416
test/test_matrices.c Normal file
View File

@ -0,0 +1,416 @@
#include <stdbool.h>
#include <stdio.h>
#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)

View File

@ -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 }}};