diff --git a/rtchallenge/src/lib.rs b/rtchallenge/src/lib.rs index 96058bb..d6fb53e 100644 --- a/rtchallenge/src/lib.rs +++ b/rtchallenge/src/lib.rs @@ -4,6 +4,7 @@ pub mod intersections; pub mod lights; pub mod materials; pub mod matrices; +pub mod patterns; pub mod rays; pub mod shapes; pub mod transformations; diff --git a/rtchallenge/src/patterns.rs b/rtchallenge/src/patterns.rs new file mode 100644 index 0000000..ff10686 --- /dev/null +++ b/rtchallenge/src/patterns.rs @@ -0,0 +1,67 @@ +use crate::tuples::{Color, Tuple}; + +#[derive(Debug)] +pub struct StripePattern { + pub a: Color, + pub b: Color, +} + +/// Create a material pattern that alternates between the given colors along each unit of the +/// X-axis. The strip extends infinitely in the positive and negative Y and Z axes. +/// +/// # Examples +/// ``` +/// use rtchallenge::{patterns::stripe_pattern, BLACK, WHITE}; +/// +/// let pattern = stripe_pattern(BLACK, WHITE); +/// assert_eq!(pattern.a, BLACK); +/// assert_eq!(pattern.b, WHITE); +/// ``` +pub fn stripe_pattern(a: Color, b: Color) -> StripePattern { + StripePattern { a, b } +} + +impl StripePattern { + /// Sample the color at the given point. + /// + /// # Examples + /// ``` + /// use rtchallenge::{patterns::stripe_pattern, tuples::point, BLACK, WHITE}; + /// + /// let pattern = stripe_pattern(WHITE, BLACK); + /// + /// for (p, want) in &[ + /// // A stripe pattern is constant in y. + /// (point(0., 0., 0.), WHITE), + /// (point(0., 1., 0.), WHITE), + /// (point(0., 2., 0.), WHITE), + /// // A stripe pattern is constant in z. + /// (point(0., 0., 0.), WHITE), + /// (point(0., 0., 1.), WHITE), + /// (point(0., 0., 2.), WHITE), + /// // A stripe pattern alternates in z. + /// (point(0., 0., 0.), WHITE), + /// (point(0.9, 0., 0.), WHITE), + /// (point(1., 0., 0.), BLACK), + /// (point(-0.1, 0., 0.), BLACK), + /// (point(-1., 0., 0.), BLACK), + /// (point(-1.1, 0., 0.), WHITE), + /// ] { + /// assert_eq!(pattern.stripe_at(*p), *want, "{:?}", p); + /// } + /// ``` + pub fn stripe_at(&self, point: Tuple) -> Color { + let x = point.x.floor() as i64; + // Shift negative valued to get correct striping. + if x < 0 { + x - 1 + } else { + x + }; + if x % 2 == 0 { + self.a + } else { + self.b + } + } +}