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