#pragma once #include #include "tuples.h" #include "matrices.h" enum pattern_type { PATTERN_STRIPE, PATTERN_GRADIENT, PATTERN_RING, PATTERN_CHECKERS }; struct pattern { enum pattern_type type; struct tuple a; struct tuple b; struct mat4x4 transform; }; inline static struct pattern stripe_pattern(struct tuple a, struct tuple b) { return (struct pattern) { PATTERN_STRIPE, a, b, mat4x4_identity() }; } inline static struct pattern gradient_pattern(struct tuple a, struct tuple b) { return (struct pattern) { PATTERN_GRADIENT, a, b, mat4x4_identity() }; } inline static struct pattern ring_pattern(struct tuple a, struct tuple b) { return (struct pattern) { PATTERN_RING, a, b, mat4x4_identity() }; } inline static struct pattern checkers_pattern(struct tuple a, struct tuple b) { return (struct pattern) { PATTERN_CHECKERS, a, b, mat4x4_identity() }; } inline static struct tuple stripe_at(struct pattern pattern, struct tuple point) { return ((int)floorf(point.x)) % 2 == 0 ? pattern.a : pattern.b; } inline static struct tuple gradient_at(struct pattern pattern, struct tuple point) { struct tuple distance = tuple_sub(pattern.b, pattern.a); float fraction = point.x - floorf(point.x); return tuple_add(pattern.a, tuple_mul(distance, fraction)); } inline static struct tuple ring_at(struct pattern pattern, struct tuple point) { return ((int)floorf(sqrtf(point.x * point.x + point.z * point.z))) % 2 == 0 ? pattern.a : pattern.b; } inline static struct tuple checkers_at(struct pattern pattern, struct tuple point) { return (int)(floorf(point.x) + floorf(point.y) + floorf(point.z)) % 2 == 0 ? pattern.a : pattern.b; } inline static struct tuple pattern_at_object(struct pattern pattern, struct mat4x4 object_transform, struct tuple point) { struct tuple object_point = mat4x4_mul_t(mat4x4_inverse(object_transform), point); struct tuple pattern_point = mat4x4_mul_t(mat4x4_inverse(pattern.transform), object_point); switch (pattern.type) { case PATTERN_STRIPE: return stripe_at(pattern, pattern_point); case PATTERN_GRADIENT: return gradient_at(pattern, pattern_point); case PATTERN_RING: return ring_at(pattern, pattern_point); case PATTERN_CHECKERS: return checkers_at(pattern, pattern_point); default: assert(false); break; } }