Adding scripting language

This commit is contained in:
STP
2023-11-19 21:39:03 -05:00
parent f31ebb06bd
commit 3dbbb67536
7 changed files with 90 additions and 349 deletions

View File

@@ -1,16 +1,9 @@
use crate::ray::Ray; use crate::ray::Ray;
use crate::{EPSILON, INFINITY}; use crate::{EPSILON, INFINITY};
use log::error;
use nalgebra::{Matrix4, Perspective3, Point3, Unit, Vector3}; use nalgebra::{Matrix4, Perspective3, Point3, Unit, Vector3};
use std::env;
#[rustfmt::skip] const ZNEAR: f32 = EPSILON;
pub const OPENGL_TO_WGPU_MATRIX: Matrix4<f32> = Matrix4::new( const ZFAR: f32 = INFINITY;
1.0, 0.0, 0.0, 0.0,
0.0, 1.0, 0.0, 0.0,
0.0, 0.0, 0.5, 0.5,
0.0, 0.0, 0.0, 1.0,
);
#[derive(Clone)] #[derive(Clone)]
pub struct Camera { pub struct Camera {
@@ -19,8 +12,6 @@ pub struct Camera {
up: Vector3<f32>, up: Vector3<f32>,
fovy: f32, fovy: f32,
aspect: f32, aspect: f32,
znear: f32,
zfar: f32,
matrix: Matrix4<f32>, matrix: Matrix4<f32>,
inverse: Matrix4<f32>, inverse: Matrix4<f32>,
} }
@@ -33,20 +24,15 @@ impl Camera {
fovy: f32, fovy: f32,
aspect: f32, aspect: f32,
) -> Self { ) -> Self {
let znear = EPSILON; let (matrix, inverse) = Camera::build_matrix_and_inverse(&eye, &target, &up, fovy, aspect);
let zfar = INFINITY;
let (matrix, inverse) =
Camera::build_matrix_and_inverse(&eye, &target, &up, aspect, fovy, znear, zfar);
Camera { Camera {
eye, eye,
target, target,
up, up,
fovy, fovy,
aspect,
znear,
zfar,
matrix, matrix,
inverse, inverse,
aspect,
} }
} }
@@ -54,13 +40,11 @@ impl Camera {
eye: &Point3<f32>, eye: &Point3<f32>,
target: &Point3<f32>, target: &Point3<f32>,
up: &Vector3<f32>, up: &Vector3<f32>,
aspect: f32,
fovy: f32, fovy: f32,
znear: f32, aspect: f32,
zfar: f32,
) -> (Matrix4<f32>, Matrix4<f32>) { ) -> (Matrix4<f32>, Matrix4<f32>) {
let view = Matrix4::look_at_lh(eye, target, up); let view = Matrix4::look_at_lh(eye, target, up);
let proj = Perspective3::new(aspect, fovy, znear, zfar); let proj = Perspective3::new(aspect, fovy, ZNEAR, ZFAR);
let matrix = proj.as_matrix() * view; let matrix = proj.as_matrix() * view;
let inverse = view.try_inverse().expect("No view") * proj.inverse(); let inverse = view.try_inverse().expect("No view") * proj.inverse();
(matrix, inverse) (matrix, inverse)
@@ -103,8 +87,6 @@ impl Camera {
let fovy_radians = (self.fovy as f64).to_radians(); let fovy_radians = (self.fovy as f64).to_radians();
let fovh_radians = 2.0 * ((fovy_radians / 2.0).tan() * aspect).atan(); let fovh_radians = 2.0 * ((fovy_radians / 2.0).tan() * aspect).atan();
let view_direction = (self.target - self.eye).normalize(); // Normalize the view direction vector let view_direction = (self.target - self.eye).normalize(); // Normalize the view direction vector
let dx = 2.0 / width as f32;
let dy = 2.0 / height as f32;
let hor = view_direction.cross(&self.up).normalize(); // pointing right let hor = view_direction.cross(&self.up).normalize(); // pointing right
let vert = view_direction.cross(&hor).normalize(); // pointing up let vert = view_direction.cross(&hor).normalize(); // pointing up
let h_width = 2.0 * (fovh_radians / 2.0).tan(); let h_width = 2.0 * (fovh_radians / 2.0).tan();

View File

@@ -15,26 +15,30 @@ const CAMERA_MAX: f32 = 10.0;
const CAMERA_INIT: f32 = 5.0; const CAMERA_INIT: f32 = 5.0;
/// Manages all state required for rendering Dear ImGui over `Pixels`. /// Manages all state required for rendering Dear ImGui over `Pixels`.
pub(crate) struct Gui { pub enum GuiEvent {
BufferResize,
CameraRelocate,
SceneLoad(String),
}
pub struct Gui {
imgui: imgui::Context, imgui: imgui::Context,
platform: imgui_winit_support::WinitPlatform, platform: imgui_winit_support::WinitPlatform,
renderer: imgui_wgpu::Renderer, renderer: imgui_wgpu::Renderer,
last_frame: Instant, last_frame: Instant,
last_cursor: Option<imgui::MouseCursor>, last_cursor: Option<imgui::MouseCursor>,
about_open: bool,
pub event: Option<GuiEvent>,
pub filename: String,
pub ray_num: i32, pub ray_num: i32,
pub buffer_proportion: f32, pub buffer_proportion: f32,
pub buffer_resize: bool,
pub camera_eye: Point3<f32>, pub camera_eye: Point3<f32>,
pub camera_reposition: bool,
} }
impl Gui { impl Gui {
/// Create Dear ImGui. /// Create Dear ImGui.
pub(crate) fn new(window: &winit::window::Window, pixels: &pixels::Pixels) -> Self { pub fn new(window: &winit::window::Window, pixels: &pixels::Pixels) -> Self {
// Create Dear ImGui context // Create Dear ImGui context
let mut imgui = imgui::Context::create(); let mut imgui = imgui::Context::create();
imgui.set_ini_filename(None); imgui.set_ini_filename(None);
@@ -78,17 +82,16 @@ impl Gui {
renderer, renderer,
last_frame: Instant::now(), last_frame: Instant::now(),
last_cursor: None, last_cursor: None,
about_open: true, event: None,
filename: String::new(),
ray_num: RAYS_INIT, ray_num: RAYS_INIT,
buffer_proportion: BUFFER_PROPORTION_INIT, buffer_proportion: BUFFER_PROPORTION_INIT,
buffer_resize: false,
camera_eye: Point3::new(CAMERA_INIT, CAMERA_INIT, CAMERA_INIT), camera_eye: Point3::new(CAMERA_INIT, CAMERA_INIT, CAMERA_INIT),
camera_reposition: false,
} }
} }
/// Prepare Dear ImGui. /// Prepare Dear ImGuBi.
pub(crate) fn prepare( pub fn prepare(
&mut self, &mut self,
window: &winit::window::Window, window: &winit::window::Window,
) -> Result<(), winit::error::ExternalError> { ) -> Result<(), winit::error::ExternalError> {
@@ -100,7 +103,7 @@ impl Gui {
} }
/// Render Dear ImGui. /// Render Dear ImGui.
pub(crate) fn render( pub fn render(
&mut self, &mut self,
window: &winit::window::Window, window: &winit::window::Window,
encoder: &mut wgpu::CommandEncoder, encoder: &mut wgpu::CommandEncoder,
@@ -131,25 +134,27 @@ impl Gui {
BUFFER_PROPORTION_MAX, BUFFER_PROPORTION_MAX,
&mut self.buffer_proportion, &mut self.buffer_proportion,
); );
let mut buffer_resize = false;
if ui.button("Change Buffer") { if ui.button("Change Buffer") {
buffer_resize = true self.event = Some(GuiEvent::BufferResize);
}; };
self.buffer_resize = buffer_resize;
let mut camera_reposition = false;
ui.text("Vector3 Input:"); ui.text("Vector3 Input:");
// Create three input fields for x, y, and z components // Create three input fields for x, y, and z components
ui.slider("X", CAMERA_MIN, CAMERA_MAX, &mut self.camera_eye.coords[0]); ui.slider("X", CAMERA_MIN, CAMERA_MAX, &mut self.camera_eye.coords[0]);
ui.slider("Y", CAMERA_MIN, CAMERA_MAX, &mut self.camera_eye.coords[1]); ui.slider("Y", CAMERA_MIN, CAMERA_MAX, &mut self.camera_eye.coords[1]);
ui.slider("Z", CAMERA_MIN, CAMERA_MAX, &mut self.camera_eye.coords[2]); ui.slider("Z", CAMERA_MIN, CAMERA_MAX, &mut self.camera_eye.coords[2]);
// Check if any component of the Vector3 has changed // Check if any component of the Vector3 has changed
if ui.button("Apply") { if ui.button("Apply Camera") {
println!("Camera changed: {:?}", self.camera_eye); println!("Camera changed: {:?}", self.camera_eye);
self.camera_eye = Point3::from(self.camera_eye); self.camera_eye = Point3::from(self.camera_eye);
camera_reposition = true; self.event = Some(GuiEvent::CameraRelocate);
}
//Load file from
ui.input_text("Scene file", &mut self.filename).build();
if ui.button("Apply File") {
self.event = Some(GuiEvent::SceneLoad(self.filename.clone()));
} }
self.camera_reposition = camera_reposition;
// Render Dear ImGui with WGPU // Render Dear ImGui with WGPU
let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor { let mut rpass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
@@ -174,7 +179,7 @@ impl Gui {
} }
/// Handle any outstanding events. /// Handle any outstanding events.
pub(crate) fn handle_event( pub fn handle_event(
&mut self, &mut self,
window: &winit::window::Window, window: &winit::window::Window,
event: &winit::event::Event<()>, event: &winit::event::Event<()>,

View File

@@ -1,24 +1,13 @@
#![allow(dead_code)] use crate::state::run;
#![allow(unused_imports)] use error_iter::ErrorIter;
#![allow(unused_variables)]
//Use linear algebra module const EPSILON: f32 = 1e-6;
const INFINITY: f32 = f32::MAX;
const EPSILON_VECTOR: Vector3<f32> = Vector3::new(EPSILON, EPSILON, EPSILON);
use crate::primitive::*;
use crate::{camera::Camera, gui::Gui, light::Light, ray::Ray, scene::Scene};
use log::error; use log::error;
use std::env;
use std::rc::Rc; use std::error::Error;
use std::sync::{Arc, Mutex};
use std::{env, thread, thread::JoinHandle};
use error_iter::ErrorIter as _;
use nalgebra::{Point3, Vector3};
use pixels::{Error, Pixels, SurfaceTexture};
use winit::dpi::{LogicalSize, PhysicalSize};
use winit::event::{Event, KeyboardInput, MouseButton, VirtualKeyCode, WindowEvent};
use winit::event_loop::{ControlFlow, EventLoop};
use winit::window::{Window, WindowBuilder};
use winit_input_helper::WinitInputHelper;
mod camera; mod camera;
mod gui; mod gui;
@@ -27,274 +16,17 @@ mod primitive;
mod ray; mod ray;
mod raytracer; mod raytracer;
mod scene; mod scene;
mod state;
const START_WIDTH: i32 = 800; use nalgebra::Vector3;
const START_HEIGHT: i32 = 800;
const BOX_SIZE: i16 = 64;
const COLOUR_CLEAR: [u8; 4] = [0x22, 0x22, 0x11, 0xff];
const EPSILON: f32 = 1e-6; fn main() {
const INFINITY: f32 = f32::MAX;
const EPSILON_VECTOR: Vector3<f32> = Vector3::new(EPSILON, EPSILON, EPSILON);
const INFINITY_VECTOR: Vector3<f32> = Vector3::new(INFINITY, INFINITY, INFINITY);
struct State {
scene: Scene,
window: Window,
pixels: Arc<Mutex<Pixels>>,
gui: Gui,
index: usize,
rays: Arc<Vec<Ray>>,
}
impl State {
/// Create a new `World` instance that can draw a moving box.
fn new(window: Window, scene: Scene) -> Self {
let window_size = window.inner_size();
let pixels = {
let surface_texture =
SurfaceTexture::new(window_size.width, window_size.height, &window);
Pixels::new(
window_size.width as u32,
window_size.height as u32,
surface_texture,
)
.unwrap()
};
let gui = Gui::new(&window, &pixels);
let rays = scene
.camera
.cast_rays(window_size.width, window_size.height);
Self {
scene,
window,
pixels: Arc::new(Mutex::new(pixels)),
gui,
index: 0,
rays: Arc::new(rays),
}
}
/// Update the `World` internal state; bounce the box around the screen.
fn update(&mut self) -> bool {
if self.gui.buffer_resize || self.gui.camera_reposition {
let pixels = &self.pixels;
let size = self.window.inner_size();
let width_new = (size.width as f32 * self.gui.buffer_proportion) as u32;
let height_new = (size.height as f32 * self.gui.buffer_proportion) as u32;
self.clear();
let mut pixels = self.pixels.lock().unwrap();
if let Err(err) = pixels.resize_buffer(width_new, height_new) {
log_error("pixels.resize_surface", err);
return false;
}
self.index = 0;
self.scene.camera.set_position(self.gui.camera_eye);
self.rays = Arc::new(self.scene.camera.cast_rays(width_new, height_new));
}
true
}
/// Resize the world
fn resize(&mut self, size: &PhysicalSize<u32>) -> bool {
println!("RESIZING!");
let gui = &self.gui;
let mut pixels = self.pixels.lock().unwrap();
if let Err(err) = pixels.resize_surface(size.width, size.height) {
log_error("pixels.resize_surface", err);
return false;
}
true
}
fn keyboard_input(&mut self, key: &KeyboardInput) {
println!("KEYBOARD INPUT");
match key.virtual_keycode {
Some(key) => match key {
VirtualKeyCode::A => {}
_ => {}
},
None => {}
}
}
fn mouse_input(&mut self, button: &MouseButton) {
println!("MOUSE INPUT");
}
/// Draw the `World` state to the frame buffer.
///
/// Assumes the default texture format: `wgpu::TextureFormat::Rgba8UnormSrgb`
fn draw(&mut self) {
// We want to multithread this function
//let mut threads = vec![];
// threads.push(thread::spawn({
// let pixels = self.pixels.clone();
// move || {
// // let colour = {
// // let ray = &self.rays[i];
// // raytracer::shade_ray(&self.scene, &ray)
// // };
//
// // let rgba = match colour {
// // Some(colour) => [colour.x, colour.y, colour.z, 255],
// // None => COLOUR_CLEAR,
// // };
// let mut pixels = pixels.lock().unwrap();
// let frame = pixels.frame_mut().chunks_exact_mut(4).nth(i).unwrap();
// frame.copy_from_slice(&[200, 100, 100, 255]);
// }
// }));
for i in 0..self.gui.ray_num {
let i = self.index as usize;
let ray_num = self.gui.ray_num;
let pixels = self.pixels.clone();
let colour = {
let ray = &self.rays[i];
raytracer::shade_ray(&self.scene, &ray)
};
let rgba = match colour {
Some(colour) => [colour.x, colour.y, colour.z, 255],
None => COLOUR_CLEAR,
};
let mut pixels = self.pixels.lock().unwrap();
let frame = pixels.frame_mut();
frame[i * 4..(i + 1) * 4].copy_from_slice(&rgba);
self.index = (self.index + 1) % (frame.len() / 4);
}
}
fn clear(&mut self) {
let mut pixels = self.pixels.lock().unwrap();
let frame = pixels.frame_mut();
for (i, pixel) in frame.chunks_exact_mut(4).enumerate() {
let rgba = [0x00, 0x00, 0x00, 0xff];
pixel.copy_from_slice(&rgba);
}
}
fn render(&mut self) -> bool {
self.update(); //Update state
self.draw(); //Draw to pixels
let pixels = self.pixels.lock().unwrap();
self.gui
.prepare(&self.window)
.expect("gui.prepare() failed"); //Prepare imgui
let render_result = pixels.render_with(|encoder, render_target, context| {
context.scaling_renderer.render(encoder, render_target); // Render pixels
self.gui
.render(&self.window, encoder, render_target, context)?;
Ok(())
});
if let Err(err) = render_result {
log_error("pixels.render", err);
return false;
}
true
}
}
fn main() -> Result<(), Error> {
env_logger::init(); env_logger::init();
env::set_var("RUST_BACKTRACE", "1"); env::set_var("RUST_BACKTRACE", "1");
Scene::init("test.rhai").expect("Could not read lua file"); run();
//Window
let event_loop = EventLoop::new();
//SCENE
// //Camera
// let eye = Point3::new(10.0, 0.0, 10.0);
// let target = Point3::new(0.0, 0.0, 0.0);
// let up = Vector3::new(0.0, 1.0, 0.0);
// let camera = Camera::new(
// eye,
// target,
// up,
// 90.0,
// (START_WIDTH as f32 / START_HEIGHT as f32) as f32,
// );
// // SETUP MATERIALS
// let magenta = Arc::new(Material::magenta());
// let blue = Arc::new(Material::blue());
// let turquoise = Arc::new(Material::turquoise());
// let red = Arc::new(Material::red());
// // SETUP PRIMITIVES
// let mut primitives: Vec<Box<dyn Primitive>> = Vec::new();
// //let cube = Box::new(Cube::unit(turquoise.clone()));
// // primitives.push(cube);
// let sphere = Box::new(Sphere::new(Point3::new(0.0, -2.0, 0.0), 1.0, red.clone()));
// let sphere2 = Box::new(Sphere::new(Point3::new(0.0, 2.0, 0.0), 1.0, red.clone()));
// let cone = Box::new(Cone::new(1.0, 1.0, -1.0, magenta.clone()));
// primitives.push(sphere);
// primitives.push(sphere2);
// primitives.push(cone);
//
// // SETUP LIGHTS
// let light_pos = Point3::new(0.0, 12.0, 4.0);
// let light_colour = Vector3::new(0.4, 0.4, 0.6);
// let light_falloff = [1.0, 0.00, 0.00];
// let light = Light::new(light_colour, light_pos, light_falloff);
//
// let light_pos2 = Point3::new(10.0, 12.0, -4.0);
// let light_colour2 = Vector3::new(0.4, 0.0, 0.6);
// let light_falloff2 = [1.0, 0.00, 0.00];
// let light2 = Light::new(light_colour2, light_pos2, light_falloff2);
//
// let ambient_light = Vector3::new(0.0, 0.0, 0.2);
//
// let scene = Scene::new(
// primitives,
// vec![light, light2],
// vec![camera.clone()],
// ambient_light,
// );
//State
let window = {
let size = LogicalSize::new(START_WIDTH, START_HEIGHT);
WindowBuilder::new()
.with_title("Hello Pixels + Dear ImGui")
.with_inner_size(size)
.with_min_inner_size(size)
.build(&event_loop)
.unwrap()
};
let scene = Scene::empty();
let mut state = State::new(window, scene);
event_loop.run(move |event, _, control_flow| {
// Draw the current frame
state.gui.handle_event(&state.window, &event); //Let gui handle its events
match event {
Event::WindowEvent { event, .. } => match event {
WindowEvent::CloseRequested => {
*control_flow = ControlFlow::Exit;
return;
}
WindowEvent::Resized(size) => {
state.resize(&size);
}
WindowEvent::KeyboardInput { input, .. } => {
state.keyboard_input(&input);
}
WindowEvent::MouseInput { button, .. } => {
state.mouse_input(&button);
}
_ => {}
},
Event::RedrawRequested(_) => {
state.render();
}
_ => {}
}
state.window.request_redraw(); //Redraw window
});
} }
fn log_error<E: std::error::Error + 'static>(method_name: &str, err: E) { fn log_error<E: Error + 'static>(method_name: &str, err: E) {
error!("{method_name}() failed: {err}"); error!("{method_name}() failed: {err}");
for source in err.sources().skip(1) { for source in err.sources().skip(1) {
error!(" Caused by: {source}"); error!(" Caused by: {source}");

View File

@@ -1,10 +1,10 @@
#[warn(dead_code)]
use crate::ray::Ray; use crate::ray::Ray;
use crate::{EPSILON, EPSILON_VECTOR, INFINITY}; use crate::{EPSILON, EPSILON_VECTOR, INFINITY};
use nalgebra::{distance, Matrix4, Point3, Unit, Vector3}; use nalgebra::{distance, Point3, Unit, Vector3};
use roots::{find_roots_quadratic, Roots}; use roots::{find_roots_quadratic, Roots};
use std::fs::File; use std::fs::File;
use std::io::{BufRead, BufReader}; use std::io::{BufRead, BufReader};
use std::path::Path;
use std::sync::Arc; use std::sync::Arc;
// MATERIAL ----------------------------------------------------------------- // MATERIAL -----------------------------------------------------------------
@@ -510,7 +510,7 @@ pub struct Cube {
} }
impl Cube { impl Cube {
fn new(width: f32, height: f32, depth: f32, material: Arc<Material>) -> Arc<dyn Primitive> { pub fn new(width: f32, height: f32, depth: f32, material: Arc<Material>) -> Arc<dyn Primitive> {
let trf = Point3::new(width / 2.0, height / 2.0, depth / 2.0); let trf = Point3::new(width / 2.0, height / 2.0, depth / 2.0);
let bln = Point3::new(-width / 2.0, -height / 2.0, -depth / 2.0); let bln = Point3::new(-width / 2.0, -height / 2.0, -depth / 2.0);
Arc::new(Cube { Arc::new(Cube {

View File

@@ -1,6 +1,9 @@
use crate::{EPSILON, EPSILON_VECTOR}; #![allow(dead_code)]
#![allow(unused_imports)]
#![allow(unused_variables)]
use nalgebra::{Matrix4, Point3, Unit, Vector3}; use crate::EPSILON;
use nalgebra::{Point3, Unit, Vector3};
pub struct Ray { pub struct Ray {
pub a: Point3<f32>, pub a: Point3<f32>,

View File

@@ -1,17 +1,8 @@
use crate::{ use crate::{light::Light, primitive::Intersection, ray::Ray, scene::*, INFINITY};
light::Light,
primitive::{Intersection, Primitive},
ray::Ray,
scene::*,
INFINITY,
};
use std::collections::HashMap;
use std::sync::Arc;
use nalgebra::{distance, Matrix4, Point3, Unit, Vector3, Vector4}; use nalgebra::{Unit, Vector3};
static ZERO_VECTOR: Vector3<f32> = Vector3::new(0.0, 0.0, 0.0); static ZERO_VECTOR: Vector3<f32> = Vector3::new(0.0, 0.0, 0.0);
static ONE_VECTOR: Vector3<f32> = Vector3::new(1.0, 1.0, 1.0);
pub fn shade_rays(scene: &Scene, rays: &Vec<Ray>, width: i32, height: i32) -> Vec<Vector3<u8>> { pub fn shade_rays(scene: &Scene, rays: &Vec<Ray>, width: i32, height: i32) -> Vec<Vector3<u8>> {
let mut pixel_data = vec![Vector3::new(0, 0, 0); (width * height) as usize]; let mut pixel_data = vec![Vector3::new(0, 0, 0); (width * height) as usize];

View File

@@ -1,10 +1,14 @@
use crate::camera::Camera; #![allow(dead_code)]
#![allow(unused_imports)]
#![allow(unused_variables)]
use crate::light::Light; use crate::light::Light;
use crate::primitive::Primitive; use crate::primitive::Primitive;
use crate::primitive::*; use crate::primitive::*;
use crate::state::State;
use crate::{camera::Camera, state};
use nalgebra::{Matrix4, Point3, Vector3}; use nalgebra::{Matrix4, Point3, Vector3};
use rhai::{Engine, EvalAltResult}; use rhai::{Engine, EvalAltResult};
use std::collections::HashMap;
use std::sync::Arc; use std::sync::Arc;
const LIGHT_AMBIENT: f32 = 0.2; const LIGHT_AMBIENT: f32 = 0.2;
@@ -91,7 +95,8 @@ impl Scene {
fn get_ambient(&self) -> Arc<Vector3<f32>> { fn get_ambient(&self) -> Arc<Vector3<f32>> {
Arc::new(self.ambient_light) Arc::new(self.ambient_light)
} }
pub fn init(filename: &str) -> Result<(), Box<EvalAltResult>> {
pub fn from_script(filename: &str) -> Result<Scene, Box<EvalAltResult>> {
let mut engine = Engine::new(); let mut engine = Engine::new();
engine engine
@@ -104,6 +109,7 @@ impl Scene {
.register_type::<Scene>() .register_type::<Scene>()
.register_fn("Scene", Scene::empty) .register_fn("Scene", Scene::empty)
.register_fn("addNode", Scene::add_node); .register_fn("addNode", Scene::add_node);
engine engine
.register_type::<Node>() .register_type::<Node>()
.register_fn("Node", Node::new) .register_fn("Node", Node::new)
@@ -118,12 +124,34 @@ impl Scene {
.register_fn("Light", Light::new); .register_fn("Light", Light::new);
engine engine
.register_type::<Material>() .register_type::<Material>()
.register_fn("Material", Material::new); .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 engine
.register_type::<Sphere>() .register_type::<Sphere>()
.register_fn("Sphere", Sphere::new); .register_fn("Sphere", Sphere::new)
.register_fn("SphereUnit", Sphere::unit);
engine
.register_type::<Cube>()
.register_fn("Cube", Cube::new)
.register_fn("CubeUnit", Cube::unit);
engine
.register_type::<Cone>()
.register_fn("Cone", Cone::new)
.register_fn("ConeUnit", Cone::unit);
engine
.register_type::<Sphere>()
.register_fn("Sphere", Sphere::new)
.register_fn("SphereUnit", Sphere::unit);
engine
.register_type::<Sphere>()
.register_fn("Sphere", Sphere::new)
.register_fn("SphereUnit", Sphere::unit);
engine.run_file(filename.into())?; let scene: Scene = engine.eval_file(filename.into())?;
Ok(()) Ok(scene)
} }
} }