chapter 1
This commit is contained in:
commit
e5b29bdc81
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
*.o
|
||||
*.gch
|
||||
test/test_tuples
|
19
test/runner.h
Normal file
19
test/runner.h
Normal file
@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
typedef bool (*test_t)(const char ** scenario);
|
||||
|
||||
#define RUNNER(tests) \
|
||||
int main() \
|
||||
{ \
|
||||
int fail_count = 0; \
|
||||
for (int i = 0; i < (sizeof (tests)) / (sizeof (test_t)); i++) { \
|
||||
const char * scenario; \
|
||||
bool result = tests[i](&scenario); \
|
||||
const char * result_s = result ? "ok" : "fail"; \
|
||||
fail_count += !result; \
|
||||
fprintf(stderr, "%s: %s\n", scenario, result_s); \
|
||||
} \
|
||||
fprintf(stderr, "\nfailed tests: %d\n", fail_count); \
|
||||
\
|
||||
return !(fail_count == 0); \
|
||||
}
|
223
test/test_tuples.c
Normal file
223
test/test_tuples.c
Normal file
@ -0,0 +1,223 @@
|
||||
#include <stdbool.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "tuples.h"
|
||||
#include "runner.h"
|
||||
|
||||
static bool tuple_test_0(const char ** scenario)
|
||||
{
|
||||
*scenario = "A tuple with w=1.0 is a point";
|
||||
|
||||
struct tuple a = tuple(4.3f, -4.2f, 3.1f, 1.0f);
|
||||
return
|
||||
a.x == 4.3f &&
|
||||
a.y == -4.2f &&
|
||||
a.z == 3.1f &&
|
||||
a.w == 1.0f &&
|
||||
tuple_is_point(a) &&
|
||||
!tuple_is_vector(a)
|
||||
;
|
||||
}
|
||||
|
||||
static bool tuple_test_1(const char ** scenario)
|
||||
{
|
||||
*scenario = "A tuple with w=0.0 is a vector";
|
||||
|
||||
struct tuple a = tuple(4.3f, -4.2f, 3.1f, 0.0f);
|
||||
return
|
||||
a.x == 4.3f &&
|
||||
a.y == -4.2f &&
|
||||
a.z == 3.1f &&
|
||||
a.w == 0.0f &&
|
||||
!tuple_is_point(a) &&
|
||||
tuple_is_vector(a)
|
||||
;
|
||||
}
|
||||
|
||||
static bool tuple_test_2(const char ** scenario)
|
||||
{
|
||||
*scenario = "point() creates tuples with w=1.0";
|
||||
struct tuple v = point(4.0f, -4.0f, 3.0f);
|
||||
return tuple_equal(v, tuple(4.0f, -4.0f, 3.0f, 1.0f));
|
||||
}
|
||||
|
||||
static bool tuple_test_3(const char ** scenario)
|
||||
{
|
||||
*scenario = "vector() creates tuples with w=0.0";
|
||||
struct tuple v = vector(4.0f, -4.0f, 3.0f);
|
||||
return tuple_equal(v, tuple(4.0f, -4.0f, 3.0f, 0.0f));
|
||||
}
|
||||
|
||||
static bool tuple_test_4(const char ** scenario)
|
||||
{
|
||||
*scenario = "Adding two tuples";
|
||||
struct tuple a1 = tuple(3.0f, -2.0f, 5.0f, 1.0f);
|
||||
struct tuple a2 = tuple(-2.0f, 3.0f, 1.0f, 0.0f);
|
||||
return tuple_equal(tuple_add(a1, a2), point(1.0f, 1.0f, 6.0f));
|
||||
}
|
||||
|
||||
static bool tuple_test_5(const char ** scenario)
|
||||
{
|
||||
*scenario = "Subtracting two points";
|
||||
struct tuple p1 = point(3.0f, 2.0f, 1.0f);
|
||||
struct tuple p2 = point(5.0f, 6.0f, 7.0f);
|
||||
return tuple_equal(tuple_sub(p1, p2), vector(-2.0f, -4.0f, -6.0f));
|
||||
}
|
||||
|
||||
static bool tuple_test_6(const char ** scenario)
|
||||
{
|
||||
*scenario = "Subtracting a vector from a point";
|
||||
struct tuple p = point(3.0f, 2.0f, 1.0f);
|
||||
struct tuple v = vector(5.0f, 6.0f, 7.0f);
|
||||
return tuple_equal(tuple_sub(p, v), point(-2.0f, -4.0f, -6.0f));
|
||||
}
|
||||
|
||||
static bool tuple_test_7(const char ** scenario)
|
||||
{
|
||||
*scenario = "Subtracting two vectors";
|
||||
struct tuple v1 = vector(3.0f, 2.0f, 1.0f);
|
||||
struct tuple v2 = vector(5.0f, 6.0f, 7.0f);
|
||||
return tuple_equal(tuple_sub(v1, v2), vector(-2.0f, -4.0f, -6.0f));
|
||||
}
|
||||
|
||||
static bool tuple_test_8(const char ** scenario)
|
||||
{
|
||||
*scenario = "Subtracting a vector from the zero vector";
|
||||
struct tuple zero = vector(0.0f, 0.0f, 0.0f);
|
||||
struct tuple v = vector(1.0f, -2.0f, 3.0f);
|
||||
return tuple_equal(tuple_sub(zero, v), vector(-1.0f, 2.0f, -3.0f));
|
||||
}
|
||||
|
||||
static bool tuple_test_9(const char ** scenario)
|
||||
{
|
||||
*scenario = "Negating a tuple";
|
||||
struct tuple a = tuple(1.0f, -2.0f, 3.0f, -4.0f);
|
||||
return tuple_equal(tuple_neg(a), tuple(-1.0f, 2.0f, -3.0f, 4.0f));
|
||||
}
|
||||
|
||||
static bool tuple_test_10(const char ** scenario)
|
||||
{
|
||||
*scenario = "Multiplying a tuple by a scalar";
|
||||
struct tuple a = tuple(1.0f, -2.0f, 3.0f, -4.0f);
|
||||
return tuple_equal(tuple_mul(a, 3.5f), tuple(3.5f, -7.0f, 10.5f, -14.0f));
|
||||
}
|
||||
|
||||
static bool tuple_test_11(const char ** scenario)
|
||||
{
|
||||
*scenario = "Multiplying a tuple by a fraction";
|
||||
struct tuple a = tuple(1.0f, -2.0f, 3.0f, -4.0f);
|
||||
return tuple_equal(tuple_mul(a, 0.5f), tuple(0.5f, -1.0f, 1.5f, -2.0f));
|
||||
}
|
||||
|
||||
static bool tuple_test_12(const char ** scenario)
|
||||
{
|
||||
*scenario = "Dividing a tuple by a scalar";
|
||||
struct tuple a = tuple(1.0f, -2.0f, 3.0f, -4.0f);
|
||||
return tuple_equal(tuple_div(a, 2.0f), tuple(0.5f, -1.0f, 1.5f, -2.0f));
|
||||
}
|
||||
|
||||
static bool tuple_test_13(const char ** scenario)
|
||||
{
|
||||
*scenario = "Computing the magnitude of vector(1, 0, 0)";
|
||||
struct tuple a = vector(1.0f, 0.0f, 0.0f);
|
||||
return float_equal(tuple_magnitude(a), 1.0f);
|
||||
}
|
||||
|
||||
static bool tuple_test_14(const char ** scenario)
|
||||
{
|
||||
*scenario = "Computing the magnitude of vector(0, 1, 0)";
|
||||
struct tuple a = vector(0.0f, 1.0f, 0.0f);
|
||||
return float_equal(tuple_magnitude(a), 1.0f);
|
||||
}
|
||||
|
||||
static bool tuple_test_15(const char ** scenario)
|
||||
{
|
||||
*scenario = "Computing the magnitude of vector(0, 0, 1)";
|
||||
struct tuple a = vector(0.0f, 0.0f, 1.0f);
|
||||
return float_equal(tuple_magnitude(a), 1.0f);
|
||||
}
|
||||
|
||||
static bool tuple_test_16(const char ** scenario)
|
||||
{
|
||||
*scenario = "Computing the magnitude of vector(1, 2, 3)";
|
||||
struct tuple a = vector(1.0f, 2.0f, 3.0f);
|
||||
return float_equal(tuple_magnitude(a), 3.7416573867739413);
|
||||
}
|
||||
|
||||
static bool tuple_test_17(const char ** scenario)
|
||||
{
|
||||
*scenario = "Computing the magnitude of vector(-1, -2, -3)";
|
||||
struct tuple a = vector(-1.0f, -2.0f, -3.0f);
|
||||
return float_equal(tuple_magnitude(a), 3.7416573867739413);
|
||||
}
|
||||
|
||||
static bool tuple_test_18(const char ** scenario)
|
||||
{
|
||||
*scenario = "Normalizing vector(4, 0, 0)";
|
||||
struct tuple v = vector(4.0f, 0.0f, 0.0f);
|
||||
return tuple_equal(tuple_normalize(v), vector(1.0f, 0.0f, 0.0f));
|
||||
}
|
||||
|
||||
static bool tuple_test_19(const char ** scenario)
|
||||
{
|
||||
*scenario = "Normalizing vector(1, 2, 3)";
|
||||
struct tuple v = vector(1.0f, 2.0f, 3.0f);
|
||||
return tuple_equal(tuple_normalize(v), vector(0.2672612419124244,
|
||||
0.5345224838248488,
|
||||
0.8017837257372732));
|
||||
}
|
||||
|
||||
static bool tuple_test_20(const char ** scenario)
|
||||
{
|
||||
*scenario = "The magnitude of a normalized vector";
|
||||
struct tuple v = vector(1.0f, 2.0f, 3.0f);
|
||||
struct tuple norm = tuple_normalize(v);
|
||||
return float_equal(tuple_magnitude(norm), 1.0f);
|
||||
}
|
||||
|
||||
static bool tuple_test_21(const char ** scenario)
|
||||
{
|
||||
*scenario = "The dot product of two tuples";
|
||||
struct tuple a = vector(1.0f, 2.0f, 3.0f);
|
||||
struct tuple b = vector(2.0f, 3.0f, 4.0f);
|
||||
return float_equal(tuple_dot(a, b), 20.0f);
|
||||
}
|
||||
|
||||
static bool tuple_test_22(const char ** scenario)
|
||||
{
|
||||
*scenario = "The cross product of two vectors";
|
||||
struct tuple a = vector(1.0f, 2.0f, 3.0f);
|
||||
struct tuple b = vector(2.0f, 3.0f, 4.0f);
|
||||
return
|
||||
tuple_equal(tuple_cross(a, b), vector(-1.0f, 2.0f, -1.0f)) &&
|
||||
tuple_equal(tuple_cross(b, a), vector( 1.0f, -2.0f, 1.0f))
|
||||
;
|
||||
}
|
||||
|
||||
test_t tuple_tests[] = {
|
||||
tuple_test_0,
|
||||
tuple_test_1,
|
||||
tuple_test_2,
|
||||
tuple_test_3,
|
||||
tuple_test_4,
|
||||
tuple_test_5,
|
||||
tuple_test_6,
|
||||
tuple_test_7,
|
||||
tuple_test_8,
|
||||
tuple_test_9,
|
||||
tuple_test_10,
|
||||
tuple_test_11,
|
||||
tuple_test_12,
|
||||
tuple_test_13,
|
||||
tuple_test_14,
|
||||
tuple_test_15,
|
||||
tuple_test_16,
|
||||
tuple_test_17,
|
||||
tuple_test_18,
|
||||
tuple_test_19,
|
||||
tuple_test_20,
|
||||
tuple_test_21,
|
||||
tuple_test_22
|
||||
};
|
||||
|
||||
RUNNER(tuple_tests)
|
130
tuples.h
Normal file
130
tuples.h
Normal file
@ -0,0 +1,130 @@
|
||||
#pragma once
|
||||
|
||||
struct tuple {
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
float w;
|
||||
};
|
||||
|
||||
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 };
|
||||
}
|
||||
|
||||
inline static bool tuple_is_point(struct tuple t)
|
||||
{
|
||||
return t.w == 1.0f;
|
||||
}
|
||||
|
||||
inline static bool tuple_is_vector(struct tuple t)
|
||||
{
|
||||
return t.w == 0.0f;
|
||||
}
|
||||
|
||||
inline static bool tuple_equal(struct tuple a, struct tuple b)
|
||||
{
|
||||
return
|
||||
float_equal(a.x, b.x) &&
|
||||
float_equal(a.y, b.y) &&
|
||||
float_equal(a.z, b.z) &&
|
||||
float_equal(a.w, b.w);
|
||||
}
|
||||
|
||||
inline static struct tuple point(float x, float y, float z)
|
||||
{
|
||||
return (struct tuple){x, y, z, 1.0f};
|
||||
}
|
||||
|
||||
inline static struct tuple vector(float x, float y, float z)
|
||||
{
|
||||
return (struct tuple){x, y, z, 0.0f};
|
||||
}
|
||||
|
||||
inline static struct tuple tuple_add(struct tuple a, struct tuple b)
|
||||
{
|
||||
return (struct tuple){
|
||||
a.x + b.x,
|
||||
a.y + b.y,
|
||||
a.z + b.z,
|
||||
a.w + b.w
|
||||
};
|
||||
}
|
||||
|
||||
inline static struct tuple tuple_sub(struct tuple a, struct tuple b)
|
||||
{
|
||||
return (struct tuple){
|
||||
a.x - b.x,
|
||||
a.y - b.y,
|
||||
a.z - b.z,
|
||||
a.w - b.w
|
||||
};
|
||||
}
|
||||
|
||||
inline static struct tuple tuple_neg(struct tuple a)
|
||||
{
|
||||
return (struct tuple){
|
||||
-a.x,
|
||||
-a.y,
|
||||
-a.z,
|
||||
-a.w
|
||||
};
|
||||
}
|
||||
|
||||
inline static struct tuple tuple_mul(struct tuple a, float s)
|
||||
{
|
||||
return (struct tuple){
|
||||
a.x * s,
|
||||
a.y * s,
|
||||
a.z * s,
|
||||
a.w * s
|
||||
};
|
||||
}
|
||||
|
||||
inline static struct tuple tuple_div(struct tuple a, float s)
|
||||
{
|
||||
return (struct tuple){
|
||||
a.x / s,
|
||||
a.y / s,
|
||||
a.z / s,
|
||||
a.w / s
|
||||
};
|
||||
}
|
||||
|
||||
inline static float tuple_magnitude(struct tuple a)
|
||||
{
|
||||
return __builtin_sqrtf(a.x * a.x +
|
||||
a.y * a.y +
|
||||
a.z * a.z +
|
||||
a.w * a.w);
|
||||
}
|
||||
|
||||
inline static struct tuple tuple_normalize(struct tuple a)
|
||||
{
|
||||
float magnitude = tuple_magnitude(a);
|
||||
return tuple_div(a, magnitude);
|
||||
}
|
||||
|
||||
inline static float tuple_dot(struct tuple a, struct tuple b)
|
||||
{
|
||||
return
|
||||
a.x * b.x +
|
||||
a.y * b.y +
|
||||
a.z * b.z;
|
||||
}
|
||||
|
||||
inline static struct tuple tuple_cross(struct tuple a, struct tuple b)
|
||||
{
|
||||
return (struct tuple){
|
||||
a.y * b.z - a.z * b.y,
|
||||
a.z * b.x - a.x * b.z,
|
||||
a.x * b.y - a.y * b.x,
|
||||
0.0f
|
||||
};
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user