diff --git a/rtiow/src/texture.rs b/rtiow/src/texture.rs deleted file mode 100644 index b7f9af0..0000000 --- a/rtiow/src/texture.rs +++ /dev/null @@ -1,160 +0,0 @@ -use std::sync::Arc; - -use image::RgbImage; -use rand; - -use perlin::Perlin; -use vec3::Vec3; - -pub trait Texture: Send + Sync { - fn value(&self, u: f32, v: f32, p: Vec3) -> Vec3; -} - -impl Texture for Arc { - fn value(&self, u: f32, v: f32, p: Vec3) -> Vec3 { - (**self).value(u, v, p) - } -} - -#[derive(Debug, PartialEq)] -pub struct ConstantTexture { - color: Vec3, -} - -impl ConstantTexture { - pub fn new(color: V) -> ConstantTexture - where - V: Into, - { - ConstantTexture { - color: color.into(), - } - } -} - -impl Texture for ConstantTexture { - fn value(&self, _u: f32, _v: f32, _p: Vec3) -> Vec3 { - self.color - } -} - -pub struct CheckerTexture -where - T: Texture, -{ - odd: T, - even: T, -} - -impl CheckerTexture -where - T: Texture, -{ - pub fn new(odd: T, even: T) -> CheckerTexture { - CheckerTexture { odd, even } - } -} - -impl Texture for CheckerTexture -where - T: Texture, -{ - fn value(&self, u: f32, v: f32, p: Vec3) -> Vec3 { - let sines = (10. * p.x).sin() * (10. * p.y).sin() * (10. * p.z).sin(); - if sines < 0. { - self.odd.value(u, v, p) - } else { - self.even.value(u, v, p) - } - } -} - -pub struct NoiseTexture { - scale: f32, - perlin: Perlin, -} - -impl NoiseTexture { - pub fn new(rng: &mut R) -> NoiseTexture - where - R: rand::Rng, - { - NoiseTexture::with_scale(rng, 1.) - } - pub fn with_scale(rng: &mut R, scale: f32) -> NoiseTexture - where - R: rand::Rng, - { - NoiseTexture { - scale, - perlin: Perlin::new(rng), - } - } -} - -impl Texture for NoiseTexture { - fn value(&self, _u: f32, _v: f32, p: Vec3) -> Vec3 { - Vec3::new(1., 1., 1.) * 0.5 * (1. + self.perlin.noise(self.scale * p)) - - //Vec3::new(1., 1., 1.) * turb(self.scale * p, 7) - //Vec3::new(1., 1., 1.) * 0.5 * (1. + turb(self.scale * p, 7)) - //Vec3::new(1., 1., 1.) * 0.5 * (1. + (self.scale * p.z + 10. * self.perlin.turb(p, 7)).sin()) - //Vec3::new(1., 1., 1.) * 0.5 * (1. + GENERATOR.noise(self.scale * p)) - } -} - -pub struct ImageTexture { - img: RgbImage, - width: f32, - height: f32, -} - -impl ImageTexture { - pub fn new(img: RgbImage) -> ImageTexture { - let (w, h) = img.dimensions(); - ImageTexture { - img, - width: f32::from(w.min(64000) as u16), - height: f32::from(h.min(64000) as u16), - } - } -} - -impl Texture for ImageTexture { - fn value(&self, u: f32, v: f32, _p: Vec3) -> Vec3 { - // Wrap texcoords by default. - let x = (u % 1. * (self.width - 1.)) as u32; - let y = ((1. - v % 1.) * (self.height - 1.)) as u32; - if x >= self.width as u32 { - panic!(format!( - "u {} v {} x {} y {} w {} h {}", - u, v, x, y, self.width, self.height - )); - } - if y >= self.height as u32 { - panic!(format!( - "u {} v {} x {} y {} w {} h {}", - u, v, x, y, self.width, self.height - )); - } - let pixel = self.img.get_pixel(x, y); - Vec3::new( - f32::from(pixel[0]) / 255., - f32::from(pixel[1]) / 255., - f32::from(pixel[2]) / 255., - ) - } -} - -#[cfg(test)] -mod test { - use super::*; - - #[test] - fn constant_texture_from_array() { - assert_eq!( - ConstantTexture::new(Vec3::new(1., 2., 3.)), - ConstantTexture::new([1., 2., 3.]) - ); - } -} diff --git a/rtiow/src/texture/checker.rs b/rtiow/src/texture/checker.rs new file mode 100644 index 0000000..68d016a --- /dev/null +++ b/rtiow/src/texture/checker.rs @@ -0,0 +1,33 @@ +use texture::Texture; +use vec3::Vec3; + +pub struct CheckerTexture +where + T: Texture, +{ + odd: T, + even: T, +} + +impl CheckerTexture +where + T: Texture, +{ + pub fn new(odd: T, even: T) -> CheckerTexture { + CheckerTexture { odd, even } + } +} + +impl Texture for CheckerTexture +where + T: Texture, +{ + fn value(&self, u: f32, v: f32, p: Vec3) -> Vec3 { + let sines = (10. * p.x).sin() * (10. * p.y).sin() * (10. * p.z).sin(); + if sines < 0. { + self.odd.value(u, v, p) + } else { + self.even.value(u, v, p) + } + } +} diff --git a/rtiow/src/texture/constant.rs b/rtiow/src/texture/constant.rs new file mode 100644 index 0000000..766cab8 --- /dev/null +++ b/rtiow/src/texture/constant.rs @@ -0,0 +1,24 @@ +use texture::Texture; +use vec3::Vec3; + +#[derive(Debug, PartialEq)] +pub struct ConstantTexture { + color: Vec3, +} + +impl ConstantTexture { + pub fn new(color: V) -> ConstantTexture + where + V: Into, + { + ConstantTexture { + color: color.into(), + } + } +} + +impl Texture for ConstantTexture { + fn value(&self, _u: f32, _v: f32, _p: Vec3) -> Vec3 { + self.color + } +} diff --git a/rtiow/src/texture/image.rs b/rtiow/src/texture/image.rs new file mode 100644 index 0000000..3a5e9f8 --- /dev/null +++ b/rtiow/src/texture/image.rs @@ -0,0 +1,47 @@ +use image::RgbImage; + +use texture::Texture; +use vec3::Vec3; + +pub struct ImageTexture { + img: RgbImage, + width: f32, + height: f32, +} + +impl ImageTexture { + pub fn new(img: RgbImage) -> ImageTexture { + let (w, h) = img.dimensions(); + ImageTexture { + img, + width: f32::from(w.min(64000) as u16), + height: f32::from(h.min(64000) as u16), + } + } +} + +impl Texture for ImageTexture { + fn value(&self, u: f32, v: f32, _p: Vec3) -> Vec3 { + // Wrap texcoords by default. + let x = (u % 1. * (self.width - 1.)) as u32; + let y = ((1. - v % 1.) * (self.height - 1.)) as u32; + if x >= self.width as u32 { + panic!(format!( + "u {} v {} x {} y {} w {} h {}", + u, v, x, y, self.width, self.height + )); + } + if y >= self.height as u32 { + panic!(format!( + "u {} v {} x {} y {} w {} h {}", + u, v, x, y, self.width, self.height + )); + } + let pixel = self.img.get_pixel(x, y); + Vec3::new( + f32::from(pixel[0]) / 255., + f32::from(pixel[1]) / 255., + f32::from(pixel[2]) / 255., + ) + } +} diff --git a/rtiow/src/texture/mod.rs b/rtiow/src/texture/mod.rs new file mode 100644 index 0000000..f138a14 --- /dev/null +++ b/rtiow/src/texture/mod.rs @@ -0,0 +1,35 @@ +mod checker; +mod constant; +mod image; +mod noise; +pub use texture::checker::CheckerTexture; +pub use texture::constant::ConstantTexture; +pub use texture::image::ImageTexture; +pub use texture::noise::NoiseTexture; + +use std::sync::Arc; + +use vec3::Vec3; + +pub trait Texture: Send + Sync { + fn value(&self, u: f32, v: f32, p: Vec3) -> Vec3; +} + +impl Texture for Arc { + fn value(&self, u: f32, v: f32, p: Vec3) -> Vec3 { + (**self).value(u, v, p) + } +} + +#[cfg(test)] +mod test { + use super::*; + + #[test] + fn constant_texture_from_array() { + assert_eq!( + ConstantTexture::new(Vec3::new(1., 2., 3.)), + ConstantTexture::new([1., 2., 3.]) + ); + } +} diff --git a/rtiow/src/texture/noise.rs b/rtiow/src/texture/noise.rs new file mode 100644 index 0000000..410eb21 --- /dev/null +++ b/rtiow/src/texture/noise.rs @@ -0,0 +1,39 @@ +use rand; + +use perlin::Perlin; +use texture::Texture; +use vec3::Vec3; + +pub struct NoiseTexture { + scale: f32, + perlin: Perlin, +} + +impl NoiseTexture { + pub fn new(rng: &mut R) -> NoiseTexture + where + R: rand::Rng, + { + NoiseTexture::with_scale(rng, 1.) + } + pub fn with_scale(rng: &mut R, scale: f32) -> NoiseTexture + where + R: rand::Rng, + { + NoiseTexture { + scale, + perlin: Perlin::new(rng), + } + } +} + +impl Texture for NoiseTexture { + fn value(&self, _u: f32, _v: f32, p: Vec3) -> Vec3 { + Vec3::new(1., 1., 1.) * 0.5 * (1. + self.perlin.noise(self.scale * p)) + + //Vec3::new(1., 1., 1.) * turb(self.scale * p, 7) + //Vec3::new(1., 1., 1.) * 0.5 * (1. + turb(self.scale * p, 7)) + //Vec3::new(1., 1., 1.) * 0.5 * (1. + (self.scale * p.z + 10. * self.perlin.turb(p, 7)).sin()) + //Vec3::new(1., 1., 1.) * 0.5 * (1. + GENERATOR.noise(self.scale * p)) + } +}