#![feature(core_float_math)] mod camera; mod objects; mod ray; mod raytracer; mod scenes; mod vec3; use std::{env, fs}; use std::sync::Arc; use crate::camera::Camera; use crate::objects::materials::dielectric::Dielectric; use crate::objects::materials::lambertian::{Lambertian, Metal}; use crate::objects::sphere::Sphere; use crate::objects::traits::Hittable; use crate::ray::Ray; use crate::raytracer::render; use crate::scenes::scene::Scene; use crate::vec3::Vec3; use dotenv::dotenv; use rand::RngExt; // TODO: implement scene serialization fn main() { dotenv().ok(); pretty_env_logger::init(); // TODO: better cli parsing let mut json_file = "./scenes/scene.json"; let args: Vec = env::args().collect(); if args.len() > 1 { json_file = &args[1]; } let json_str = fs::read_to_string(json_file).expect("Reading specified scene file failed!"); let mut scene: Scene = serde_json::from_str(&json_str).unwrap(); render(&mut scene); return; // random spheres code; thought: make this available as cli flag? let ground = Lambertian::rgb(-2.5, 0.5, 0.5, 1.); let mut world: Vec> = vec![Arc::new(Sphere::xyz( 0., -1000., 0., 1000., Arc::new(ground), ))]; let mut rng = rand::rng(); let point = Vec3::new(4., 0.2, 0.); for a in -11..11 { for b in -11..11 { let mat = rng.random_range((0.)..1.); let center = Vec3::new( a as f32 + 0.9 * rng.random_range((0.)..1.), 0.2, b as f32 + 0.9 * rng.random_range((0.)..1.), ); if (center - point).length() > 0.9 { if mat < 0.8 { // diffuse world.push(Arc::new(Sphere::new( center, 0.2, Arc::new(Lambertian::new(Vec3::random() * Vec3::random(), 1.)), ))); } else if mat < 0.95 { // metal world.push(Arc::new(Sphere::new( center, 0.2, Arc::new(Metal::rgb( rng.random_range(0.5..1.), rng.random_range(0.5..1.), rng.random_range(0.5..1.), 1., rng.random_range((0.)..0.5), )), ))); } else { // glass world.push(Arc::new(Sphere::new( center, 0.2, Arc::new(Dielectric::new(1.5)), ))); } } } } world.push(Arc::new(Sphere::xyz( 0., 1., 0., 1., Arc::new(Dielectric::new(1.5)), ))); world.push(Arc::new(Sphere::xyz( -4., 1., 0., 1., Arc::new(Lambertian::rgb(0.4, 0.2, 0.1, 1.)), ))); world.push(Arc::new(Sphere::xyz( 4., 1., 0., 1., Arc::new(Metal::rgb(0.7, 0.6, 0.5, 1., 0.)), ))); let mut c = Camera::new(); c.set_fov(20.); c.set_anti_alias_rate(23); c.set_vup(Vec3::new(0., 1., 0.)); c.set_look_from(Vec3::new(13., 2., 3.)); c.set_look_at(Vec3::new(0., 0., 0.)); c.add_defocus_blur(0.6, 10.); let mut s = Scene::new(c, world, "output.png".to_string(), 1920, 1080, 50); render(&mut s); }