use crate::camera::Camera; use crate::light::Light; use crate::primitive::*; use nalgebra::{Matrix4, Point3, Vector3}; use rhai::{Engine, EvalAltResult}; use std::sync::Arc; #[derive(Clone)] pub struct Node { pub primitive: Arc, pub model_transform: Matrix4, } impl Node { pub fn new(primitive: Arc) -> Self { Node { primitive, model_transform: Matrix4::identity(), } } pub fn rotate(&mut self, roll: f32, pitch: f32, yaw: f32) { let roll = (roll as f64).to_radians() as f32; let pitch = (pitch as f64).to_radians() as f32; let yaw = (yaw as f64).to_radians() as f32; let rotation_matrix = Matrix4::from_euler_angles(roll, pitch, yaw); self.model_transform = rotation_matrix * self.model_transform; } pub fn translate(&mut self, translation: &Vector3) { let translation_matrix = Matrix4::new_translation(translation); self.model_transform = translation_matrix * self.model_transform; } pub fn scale(&mut self, scale: &Vector3) { let scale_matrix = Matrix4::new_nonuniform_scaling(scale); self.model_transform = scale_matrix * self.model_transform; } } #[derive(Clone)] pub struct Scene { pub nodes: Vec, pub materials: Vec, pub lights: Vec, pub cameras: Vec, } impl Scene { // Creates an emptry scene pub fn empty() -> Self { Scene { nodes: Vec::new(), materials: Vec::new(), lights: Vec::new(), cameras: Vec::new(), } } fn add_node(&mut self, node: Node) { self.nodes.push(node); } fn add_material(&mut self, material: Material) { self.materials.push(material); } fn add_light(&mut self, light: Light) { self.lights.push(light); } fn add_camera(&mut self, camera: Camera) { self.cameras.push(camera); } pub fn from_rhai(script: &str) -> Result> { let mut engine = Engine::new(); engine .register_type::>() .register_fn("V", Vector3::::new); engine .register_type::>() .register_fn("P", Point3::::new); engine .register_type::() .register_fn("Scene", Scene::empty) .register_fn("addNode", Scene::add_node) .register_fn("addLight", Scene::add_light); engine .register_type::() .register_fn("Node", Node::new) .register_fn("translate", Node::translate) .register_fn("rotate", Node::rotate) .register_fn("scale", Node::scale); engine .register_type::() .register_fn("Camera", Camera::new); engine .register_type::() .register_fn("Light", Light::new); engine .register_type::() .register_fn("Material", Material::new) .register_fn("MaterialRed", Material::red) .register_fn("MaterialBlue", Material::blue) .register_fn("MaterialGreen", Material::green) .register_fn("MaterialMagenta", Material::magenta) .register_fn("MaterialTurquoise", Material::turquoise); engine .register_type::() .register_fn("Sphere", Sphere::new) .register_fn("SphereUnit", Sphere::unit); engine .register_type::() .register_fn("Cube", Cube::new) .register_fn("CubeUnit", Cube::unit); engine .register_type::() .register_fn("Cone", Cone::new) .register_fn("ConeUnit", Cone::unit); engine .register_type::() .register_fn("Cylinder", Cylinder::new); engine .register_type::() .register_fn("Circle", Circle::new) .register_fn("CircleUnit", Circle::unit); engine .register_type::() .register_fn("Rectangle", Rectangle::new) .register_fn("RectangleUnit", Rectangle::unit); engine .register_type::() .register_fn("Steiner", SteinerSurface::new); engine .register_type::() .register_fn("Torus", Torus::new); let scene: Scene = engine.eval(script.into())?; Ok(scene) } }