2024-08-11 22:29:55 -05:00

103 lines
2.4 KiB
C

#pragma once
#include <assert.h>
#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;
}
}