diff --git a/Cargo.lock b/Cargo.lock index 326dacf..27c3a80 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,18 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "adler" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f26201604c87b1e01bd3d98f8d5d9a8fcbb815e8cedb41ffccbeb4bf593a35fe" + +[[package]] +name = "adler32" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aae1277d39aeec15cb388266ecc24b11c80469deae6067e17a1a7aa9e5c1f234" + [[package]] name = "autocfg" version = "1.0.1" @@ -14,6 +26,18 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +[[package]] +name = "bytemuck" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bed57e2090563b83ba8f83366628ce535a7584c9afa4c9fc0612a03925c6df58" + +[[package]] +name = "byteorder" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae44d1a3d5a19df61dd0c8beb138458ac2a53a7ac09eba97d55592540004306b" + [[package]] name = "cfg-if" version = "0.1.10" @@ -26,6 +50,21 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" +[[package]] +name = "color_quant" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d7b894f5411737b7867f4827955924d7c254fc9f4d91a6aad6b097804b1018b" + +[[package]] +name = "crc32fast" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81156fece84ab6a9f2afdb109ce3ae577e42b1228441eded99bd77f627953b1a" +dependencies = [ + "cfg-if 1.0.0", +] + [[package]] name = "crossbeam-channel" version = "0.5.0" @@ -71,6 +110,16 @@ dependencies = [ "lazy_static", ] +[[package]] +name = "deflate" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73770f8e1fe7d64df17ca66ad28994a0a623ea497fa69486e14984e715c5d174" +dependencies = [ + "adler32", + "byteorder", +] + [[package]] name = "either" version = "1.6.1" @@ -88,6 +137,16 @@ dependencies = [ "wasi", ] +[[package]] +name = "gif" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "02efba560f227847cb41463a7395c514d127d4f74fff12ef0137fff1b84b96c4" +dependencies = [ + "color_quant", + "weezl", +] + [[package]] name = "hermit-abi" version = "0.1.18" @@ -97,6 +156,34 @@ dependencies = [ "libc", ] +[[package]] +name = "image" +version = "0.23.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24ffcb7e7244a9bf19d35bf2883b9c080c4ced3c07a9895572178cdb8f13f6a1" +dependencies = [ + "bytemuck", + "byteorder", + "color_quant", + "gif", + "jpeg-decoder", + "num-iter", + "num-rational", + "num-traits", + "png", + "scoped_threadpool", + "tiff", +] + +[[package]] +name = "jpeg-decoder" +version = "0.1.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "229d53d58899083193af11e15917b5640cd40b29ff475a1fe4ef725deb02d0f2" +dependencies = [ + "rayon", +] + [[package]] name = "lazy_static" version = "1.4.0" @@ -118,6 +205,66 @@ dependencies = [ "autocfg", ] +[[package]] +name = "miniz_oxide" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791daaae1ed6889560f8c4359194f56648355540573244a5448a83ba1ecc7435" +dependencies = [ + "adler32", +] + +[[package]] +name = "miniz_oxide" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a92518e98c078586bc6c934028adcca4c92a53d6a958196de835170a01d84e4b" +dependencies = [ + "adler", + "autocfg", +] + +[[package]] +name = "num-integer" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.42" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2021c8337a54d21aca0d59a92577a029af9431cb59b909b03252b9c164fad59" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-rational" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12ac428b1cb17fce6f731001d307d351ec70a6d202fc2e60f7d4c5e42d8f4f07" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +dependencies = [ + "autocfg", +] + [[package]] name = "num_cpus" version = "1.13.0" @@ -128,6 +275,18 @@ dependencies = [ "libc", ] +[[package]] +name = "png" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3287920cb847dee3de33d301c463fba14dda99db24214ddf93f83d3021f4c6" +dependencies = [ + "bitflags", + "crc32fast", + "deflate", + "miniz_oxide 0.3.7", +] + [[package]] name = "ppv-lite86" version = "0.2.10" @@ -203,11 +362,18 @@ dependencies = [ name = "rtnw" version = "0.1.0" dependencies = [ + "image", "rand", "rayon", "sdl2", ] +[[package]] +name = "scoped_threadpool" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d51f5df5af43ab3f1360b429fa5e0152ac5ce8c0bd6485cae490332e96846a8" + [[package]] name = "scopeguard" version = "1.1.0" @@ -237,6 +403,17 @@ dependencies = [ "version-compare", ] +[[package]] +name = "tiff" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a53f4706d65497df0c4349241deddf35f84cee19c87ed86ea8ca590f4464437" +dependencies = [ + "jpeg-decoder", + "miniz_oxide 0.4.4", + "weezl", +] + [[package]] name = "version-compare" version = "0.0.10" @@ -248,3 +425,9 @@ name = "wasi" version = "0.10.2+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + +[[package]] +name = "weezl" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4a32b378380f4e9869b22f0b5177c68a5519f03b3454fde0b291455ddbae266c" diff --git a/Cargo.toml b/Cargo.toml index 66a3266..9623e9a 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,14 +1,20 @@ [package] -name = "rtnw" -version = "0.1.0" authors = ["ishanjain28 "] edition = "2018" +name = "rtnw" +version = "0.1.0" +[dependencies] +image = "*" +rayon = "1.5.0" + +[dependencies.rand] +features = ["small_rng"] +version = "0.8.3" + +[dependencies.sdl2] +optional = true +version = "0.34.0" [features] default = ["gui"] gui = ["sdl2"] - -[dependencies] -sdl2 = { version = "0.34.0", optional = true } -rand = { version = "0.8.3", features = ["small_rng"] } -rayon = "1.5.0" diff --git a/assets/earthmap.jpg b/assets/earthmap.jpg new file mode 100644 index 0000000..908c160 Binary files /dev/null and b/assets/earthmap.jpg differ diff --git a/src/demos/image_texture.rs b/src/demos/image_texture.rs new file mode 100644 index 0000000..2934a19 --- /dev/null +++ b/src/demos/image_texture.rs @@ -0,0 +1,60 @@ +use std::sync::Arc; + +use rand::{prelude::SmallRng, SeedableRng}; + +use crate::{ + demos::{Demo, ParallelHit}, + materials::Lambertian, + shapes::Sphere, + texture::ImageTexture, + types::Vec3, + BvhNode, Camera, +}; + +pub struct ImageTextureDemo {} + +impl Demo for ImageTextureDemo { + type DemoT = BvhNode>; + + fn name(&self) -> &'static str { + "image_texture" + } + + fn world(&self) -> Self::DemoT { + let mut world: Vec> = Vec::with_capacity(1); + + let mut rng = rand::thread_rng(); + let mut rng = SmallRng::from_rng(&mut rng).unwrap(); + + let earth_texture = match ImageTexture::from_filename("assets/earthmap.jpg") { + Ok(v) => v, + Err(e) => panic!("error in creating image texture: {}", e), + }; + + world.push(Arc::new(Sphere::new( + Vec3::new(0.0, 0.0, 0.0), + 2.0, + Lambertian::new(earth_texture), + ))); + + BvhNode::new(&mut rng, &mut world, 0.0, 1.0) + } + + fn camera(&self, aspect_ratio: f64) -> Camera { + let lookfrom = Vec3::new(13.0, 2.0, 3.0); + let lookat = Vec3::new(0.0, 0.0, 0.0); + let aperture = 0.1; + let focus_distance = 12.0; + Camera::new( + lookfrom, + lookat, + Vec3::new(0.0, 1.0, 0.0), + 20.0, + aspect_ratio, + aperture, + focus_distance, + 0.0, + 1.0, + ) + } +} diff --git a/src/demos/mod.rs b/src/demos/mod.rs index 980abee..bf8517e 100644 --- a/src/demos/mod.rs +++ b/src/demos/mod.rs @@ -12,10 +12,12 @@ use std::{ }; mod checkered_motion_blur; +mod image_texture; mod perlin_noise_ball; mod two_spheres; pub use checkered_motion_blur::CheckeredMotionBlur; +pub use image_texture::ImageTextureDemo; pub use perlin_noise_ball::PerlinNoiseBall; pub use two_spheres::TwoSpheres; diff --git a/src/main.rs b/src/main.rs index 6325d38..51021d2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,8 +26,8 @@ use std::time::Instant; const NUM_SAMPLES: u8 = 255; const VERTICAL_PARTITION: usize = 12; const HORIZONTAL_PARTITION: usize = 12; -const WIDTH: usize = 2560; -const HEIGHT: usize = 1440; +const WIDTH: usize = 1920; +const HEIGHT: usize = 1080; fn main() -> Result<(), String> { run(WIDTH, HEIGHT) @@ -68,7 +68,7 @@ fn run(mut width: usize, mut height: usize) -> Result<(), String> { .map_err(|e| e.to_string())?; let mut active_demo: &dyn Demo>> = - &demos::PerlinNoiseBall {}; + &demos::ImageTextureDemo {}; let mut should_update = true; loop { @@ -97,6 +97,10 @@ fn run(mut width: usize, mut height: usize) -> Result<(), String> { active_demo = &demos::PerlinNoiseBall {}; should_update = true; } + Some(Keycode::Num4) => { + active_demo = &demos::ImageTextureDemo {}; + should_update = true; + } None => unreachable!(), _ => (), }; @@ -140,6 +144,8 @@ fn run(width: usize, height: usize) -> Result<(), String> { run_and_save_demo(demos::PerlinNoiseBall {}, width, height); + run_and_save_demo(demos::ImageTexture {}, width, height); + Ok(()) } diff --git a/src/texture/image_texture.rs b/src/texture/image_texture.rs new file mode 100644 index 0000000..b599058 --- /dev/null +++ b/src/texture/image_texture.rs @@ -0,0 +1,55 @@ +use image::{error::ImageError, io::Reader as ImageReader}; + +use crate::{types::Vec3, Texture}; + +pub struct ImageTexture { + image: Vec, + // (width, height) + dimensions: (u32, u32), + bytes_per_scanline: u32, + bytes_per_pixel: u32, +} + +impl ImageTexture { + #[allow(dead_code)] + pub fn from_filename(filename: &str) -> Result { + let img = ImageReader::open(filename)?.decode()?; + let img = img.to_bgr8(); + + let (width, _) = img.dimensions(); + + let bytes_per_pixel = 3; + + Ok(Self { + image: img.to_vec(), + dimensions: img.dimensions(), + bytes_per_scanline: bytes_per_pixel * width, + bytes_per_pixel, + }) + } +} + +impl Texture for ImageTexture { + fn value(&self, u: f64, v: f64, _p: Vec3) -> Vec3 { + let (width, height) = self.dimensions; + + let u = u.clamp(0.0, 1.0); + let v = 1.0 - v.clamp(0.0, 1.0); + + let i = (u * width as f64) as u32; + let j = (v * height as f64) as u32; + + let i = i.clamp(0, width - 1); + let j = j.clamp(0, height - 1); + + let color_scale = 1.0 / 255.0; + + let pixel = (j * self.bytes_per_scanline + i * self.bytes_per_pixel) as usize; + + Vec3::new( + color_scale * (self.image[pixel + 2] as f64), + color_scale * (self.image[pixel + 1] as f64), + color_scale * (self.image[pixel] as f64), + ) + } +} diff --git a/src/texture/mod.rs b/src/texture/mod.rs index e4d3c10..7ec8242 100644 --- a/src/texture/mod.rs +++ b/src/texture/mod.rs @@ -1,9 +1,11 @@ mod checker; +mod image_texture; mod perlin; mod perlin_noise; mod solid; pub use checker::Checker; +pub use image_texture::ImageTexture; pub use perlin::Perlin; pub use perlin_noise::PerlinNoise; pub use solid::Solid;