chapter 3
This commit is contained in:
parent
e889e1fb75
commit
a380038f5e
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,4 +2,5 @@
|
||||
*.gch
|
||||
test/test_tuples
|
||||
test/test_canvas
|
||||
test/test_matrices
|
||||
*.ppm
|
9
float.h
Normal file
9
float.h
Normal 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
265
matrices.h
Normal 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;
|
||||
}
|
@ -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. \
|
||||
|
@ -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
416
test/test_matrices.c
Normal 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)
|
11
tuples.h
11
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 }}};
|
||||
|
Loading…
x
Reference in New Issue
Block a user