summaryrefslogtreecommitdiff
path: root/racer-tracer
diff options
context:
space:
mode:
Diffstat (limited to 'racer-tracer')
-rw-r--r--racer-tracer/Cargo.toml1
-rw-r--r--racer-tracer/src/camera.rs55
-rw-r--r--racer-tracer/src/key_inputs.rs81
-rw-r--r--racer-tracer/src/main.rs12
-rw-r--r--racer-tracer/src/scene_controller.rs13
-rw-r--r--racer-tracer/src/scene_controller/interactive.rs56
-rw-r--r--racer-tracer/src/vec3.rs19
7 files changed, 202 insertions, 35 deletions
diff --git a/racer-tracer/Cargo.toml b/racer-tracer/Cargo.toml
index ee5bbc8..c9b8ac6 100644
--- a/racer-tracer/Cargo.toml
+++ b/racer-tracer/Cargo.toml
@@ -20,4 +20,5 @@ slog-term = "2"
slog = "2"
slog-async = "2"
console = "0.15"
+glam = "0.23.0"
serde = { version = "1", features = ["derive"] }
diff --git a/racer-tracer/src/camera.rs b/racer-tracer/src/camera.rs
index e6396e8..1ac2396 100644
--- a/racer-tracer/src/camera.rs
+++ b/racer-tracer/src/camera.rs
@@ -1,3 +1,5 @@
+use glam::{f32::Vec3 as FVec3, Quat};
+
use crate::image::Image;
use crate::ray::Ray;
use crate::util::{degrees_to_radians, random_in_unit_disk};
@@ -14,6 +16,7 @@ pub struct Camera {
pub forward: Vec3,
pub right: Vec3,
pub up: Vec3,
+ pub scene_up: Vec3,
pub lens_radius: f64,
pub focus_distance: f64,
}
@@ -22,7 +25,7 @@ impl Camera {
pub fn new(
look_from: Vec3,
look_at: Vec3,
- up: Vec3,
+ scene_up: Vec3,
vfov: f64,
image: &Image,
aperture: f64,
@@ -33,7 +36,7 @@ impl Camera {
let viewport_width = image.aspect_ratio * viewport_height;
let forward = (look_from - look_at).unit_vector();
- let right = up.cross(&forward).unit_vector();
+ let right = scene_up.cross(&forward).unit_vector();
let up = forward.cross(&right);
let horizontal = focus_distance * viewport_width * right;
@@ -50,6 +53,7 @@ impl Camera {
forward,
right,
up,
+ scene_up,
lens_radius: aperture * 0.5,
focus_distance,
}
@@ -66,17 +70,56 @@ impl Camera {
pub fn go_forward(&mut self, go: f64) {
self.origin += self.forward * go;
-
- self.upper_left_corner = self.origin + self.vertical / 2.0
- - self.horizontal / 2.0
- - self.focus_distance * self.forward;
+ self.update_corner()
}
pub fn go_right(&mut self, go: f64) {
self.origin += self.right * go;
+ self.update_corner()
+ }
+ fn update_corner(&mut self) {
self.upper_left_corner = self.origin + self.vertical / 2.0
- self.horizontal / 2.0
- self.focus_distance * self.forward;
}
+
+ fn update_directions(&mut self) {
+ self.forward.unit_vector();
+ self.right = self.scene_up.cross(&self.forward).unit_vector();
+ self.up = self.forward.cross(&self.right);
+ self.horizontal = self.focus_distance * self.viewport_width * self.right;
+ self.vertical = self.focus_distance * self.viewport_height * self.up;
+ }
+
+ pub fn rotate(&mut self, up: f64, right: f64) {
+ self.forward = (Quat::from_axis_angle(self.right.into(), right as f32)
+ * Quat::from_axis_angle(self.scene_up.into(), up as f32)
+ * FVec3::from(self.forward))
+ .into();
+
+ self.forward.unit_vector();
+ self.update_directions();
+ self.update_corner();
+ }
+
+ pub fn rotate_up(&mut self, go: f64) {
+ self.forward = (Quat::from_axis_angle(self.right.into(), go as f32)
+ * FVec3::from(self.forward))
+ .into();
+
+ self.forward.unit_vector();
+ self.update_directions();
+ self.update_corner();
+ }
+
+ pub fn rotate_right(&mut self, go: f64) {
+ self.forward = (Quat::from_axis_angle(self.scene_up.into(), -go as f32)
+ * FVec3::from(self.forward))
+ .into();
+
+ self.forward.unit_vector();
+ self.update_directions();
+ self.update_corner();
+ }
}
diff --git a/racer-tracer/src/key_inputs.rs b/racer-tracer/src/key_inputs.rs
index 9a7bde5..b815250 100644
--- a/racer-tracer/src/key_inputs.rs
+++ b/racer-tracer/src/key_inputs.rs
@@ -1,6 +1,6 @@
use std::collections::HashMap;
-use minifb::{Key, Window};
+use minifb::{Key, MouseButton, MouseMode, Window};
use slog::Logger;
use crate::error::TracerError;
@@ -11,11 +11,17 @@ pub enum KeyEvent {
}
type Callback<'func> = Box<dyn Fn(f64) -> Result<(), TracerError> + Send + Sync + 'func>;
+pub type MouseCallback<'func> =
+ Box<dyn Fn(f32, f32) -> Result<(), TracerError> + Send + Sync + 'func>;
pub type KeyCallback<'func> = (KeyEvent, Key, Callback<'func>);
pub struct KeyInputs<'func> {
is_down_callbacks: HashMap<Key, Vec<Callback<'func>>>,
is_released_callbacks: HashMap<Key, Vec<Callback<'func>>>,
+ mouse_move_callbacks: Vec<MouseCallback<'func>>,
log: Logger,
+ mouse_x: f32,
+ mouse_y: f32,
+ mouse_down: bool,
}
impl<'func, 'window> KeyInputs<'func> {
@@ -23,10 +29,21 @@ impl<'func, 'window> KeyInputs<'func> {
KeyInputs {
is_down_callbacks: HashMap::new(),
is_released_callbacks: HashMap::new(),
+ mouse_move_callbacks: Vec::new(),
log,
+ mouse_x: 0.0,
+ mouse_y: 0.0,
+ mouse_down: false,
}
}
+ pub fn mouse_move(
+ &mut self,
+ callback: impl Fn(f32, f32) -> Result<(), TracerError> + Send + Sync + 'func,
+ ) {
+ self.mouse_move_callbacks.push(Box::new(callback));
+ }
+
pub fn input(
event: KeyEvent,
key: Key,
@@ -74,26 +91,48 @@ impl<'func, 'window> KeyInputs<'func> {
callbacks.push(Box::new(closure));
}
- pub fn update(&self, window: &'window Window, dt: f64) {
- self.is_down_callbacks
- .iter()
- .filter(|(key, _callbacks)| window.is_key_down(**key))
- .for_each(|(_key, callbacks)| {
- callbacks.iter().for_each(|callback| {
- if let Err(e) = callback(dt) {
- error!(self.log, "Key callback error: {}", e);
- }
- })
- });
- self.is_released_callbacks
- .iter()
- .filter(|(key, _callbacks)| window.is_key_released(**key))
- .for_each(|(_key, callbacks)| {
- callbacks.iter().for_each(|callback| {
- if let Err(e) = callback(dt) {
- error!(self.log, "Key callback error: {}", e);
+ pub fn update(&mut self, window: &'window mut Window, dt: f64) {
+ if window.is_active() {
+ if window.get_mouse_down(MouseButton::Left) {
+ if let Some((x, y)) = window.get_mouse_pos(MouseMode::Pass) {
+ if !self.mouse_down {
+ self.mouse_x = x;
+ self.mouse_y = y;
}
- })
- });
+ self.mouse_move_callbacks.iter().for_each(|cb| {
+ if let Err(e) = cb(self.mouse_x - x, self.mouse_y - y) {
+ error!(self.log, "Mouse callback error: {}", e);
+ }
+ });
+ self.mouse_x = x;
+ self.mouse_y = y;
+ }
+
+ self.mouse_down = true;
+ } else {
+ self.mouse_down = false;
+ }
+
+ self.is_down_callbacks
+ .iter()
+ .filter(|(key, _callbacks)| window.is_key_down(**key))
+ .for_each(|(_key, callbacks)| {
+ callbacks.iter().for_each(|callback| {
+ if let Err(e) = callback(dt) {
+ error!(self.log, "Key callback error: {}", e);
+ }
+ })
+ });
+ self.is_released_callbacks
+ .iter()
+ .filter(|(key, _callbacks)| window.is_key_released(**key))
+ .for_each(|(_key, callbacks)| {
+ callbacks.iter().for_each(|callback| {
+ if let Err(e) = callback(dt) {
+ error!(self.log, "Key callback error: {}", e);
+ }
+ })
+ });
+ }
}
}
diff --git a/racer-tracer/src/main.rs b/racer-tracer/src/main.rs
index c31f09b..afdc919 100644
--- a/racer-tracer/src/main.rs
+++ b/racer-tracer/src/main.rs
@@ -53,6 +53,9 @@ fn run(config: Config, log: Logger, term: Terminal) -> Result<(), TracerError> {
let image = image::Image::new(config.screen.width, config.screen.height);
let look_from = Vec3::new(13.0, 2.0, 3.0);
let look_at = Vec3::new(0.0, 0.0, 0.0);
+ // TODO: Make camera configurable.
+ // pos, look_at, fov, aperture, focus distance.
+ // Also ensure those can be changed during runtime.
let camera = Camera::new(
look_from,
look_at,
@@ -71,6 +74,7 @@ fn run(config: Config, log: Logger, term: Terminal) -> Result<(), TracerError> {
match &config.scene_controller {
config::ConfigSceneController::Interactive => {
let camera_speed = 0.000002;
+ let camera_sensitivity = 0.001;
InteractiveScene::new(
SceneData {
log: log.new(o!("scope" => "scene-controller")),
@@ -81,13 +85,17 @@ fn run(config: Config, log: Logger, term: Terminal) -> Result<(), TracerError> {
image: image.clone(),
},
camera_speed,
+ camera_sensitivity,
)
}
}
};
let mut inputs = KeyInputs::new(log.new(o!("scope" => "key-inputs")));
- inputs.register_inputs(scene_controller.get_inputs());
+ inputs.register_inputs(scene_controller.key_inputs());
+ if let Some(mouse_cb) = scene_controller.mouse_input() {
+ inputs.mouse_move(mouse_cb);
+ }
rayon::scope(|s| {
// Render
@@ -126,7 +134,7 @@ fn run(config: Config, log: Logger, term: Terminal) -> Result<(), TracerError> {
{
let dt = t.elapsed().as_micros() as f64;
t = Instant::now();
- inputs.update(&window, dt);
+ inputs.update(&mut window, dt);
window_res =
scene_controller
diff --git a/racer-tracer/src/scene_controller.rs b/racer-tracer/src/scene_controller.rs
index 4a867f5..3ca5b70 100644
--- a/racer-tracer/src/scene_controller.rs
+++ b/racer-tracer/src/scene_controller.rs
@@ -3,8 +3,13 @@ pub mod interactive;
use slog::Logger;
use crate::{
- camera::Camera, config::Config, error::TracerError, image::Image, key_inputs::KeyCallback,
- scene::Scene, terminal::Terminal,
+ camera::Camera,
+ config::Config,
+ error::TracerError,
+ image::Image,
+ key_inputs::{KeyCallback, MouseCallback},
+ scene::Scene,
+ terminal::Terminal,
};
pub fn create_screen_buffer(image: &Image) -> Vec<u32> {
@@ -23,7 +28,9 @@ pub struct SceneData {
pub trait SceneController: Send + Sync {
// Return a vector of key callbacks. The provided closure will be
// called when the corresponding key is release/pressed.
- fn get_inputs(&self) -> Vec<KeyCallback>;
+ fn key_inputs(&self) -> Vec<KeyCallback>;
+
+ fn mouse_input(&self) -> Option<MouseCallback>;
// Render function
fn render(&self) -> Result<(), TracerError>;
diff --git a/racer-tracer/src/scene_controller/interactive.rs b/racer-tracer/src/scene_controller/interactive.rs
index 4624ba1..5fdecfc 100644
--- a/racer-tracer/src/scene_controller/interactive.rs
+++ b/racer-tracer/src/scene_controller/interactive.rs
@@ -13,7 +13,7 @@ use crate::{
error::TracerError,
image::Image,
image_action::ImageAction,
- key_inputs::{KeyCallback, KeyEvent, KeyInputs},
+ key_inputs::{KeyCallback, KeyEvent, KeyInputs, MouseCallback},
renderer::{RenderData, Renderer},
scene::Scene,
terminal::Terminal,
@@ -25,6 +25,8 @@ pub struct InteractiveScene<'renderer, 'action> {
screen_buffer: RwLock<Vec<u32>>,
preview_buffer: RwLock<Vec<u32>>,
camera_speed: f64,
+ camera_sensitivity: f32,
+ camera_key_sensitivity: f32,
render_image_event: SignalEvent,
buffer_updated: SignalEvent,
stop_event: SignalEvent,
@@ -41,11 +43,13 @@ pub struct InteractiveScene<'renderer, 'action> {
}
impl<'renderer, 'action> InteractiveScene<'renderer, 'action> {
- pub fn new(scene_data: SceneData, camera_speed: f64) -> Self {
+ pub fn new(scene_data: SceneData, camera_speed: f64, camera_sensitivity: f32) -> Self {
Self {
screen_buffer: RwLock::new(create_screen_buffer(&scene_data.image)),
preview_buffer: RwLock::new(create_screen_buffer(&scene_data.image)),
camera_speed,
+ camera_sensitivity,
+ camera_key_sensitivity: camera_sensitivity * 0.0005, // Just scale it for now.
render_image_event: SignalEvent::manual(false),
buffer_updated: SignalEvent::manual(false),
stop_event: SignalEvent::manual(false),
@@ -64,8 +68,40 @@ impl<'renderer, 'action> InteractiveScene<'renderer, 'action> {
}
impl<'renderer, 'action> SceneController for InteractiveScene<'renderer, 'action> {
- fn get_inputs(&self) -> Vec<KeyCallback> {
+ fn key_inputs(&self) -> Vec<KeyCallback> {
vec![
+ KeyInputs::input(KeyEvent::Down, Key::Left, |dt| {
+ self.camera
+ .write()
+ .map_err(|e| TracerError::KeyError(e.to_string()))
+ .map(|mut cam| {
+ cam.rotate_right(-dt * self.camera_key_sensitivity as f64);
+ })
+ }),
+ KeyInputs::input(KeyEvent::Down, Key::Right, |dt| {
+ self.camera
+ .write()
+ .map_err(|e| TracerError::KeyError(e.to_string()))
+ .map(|mut cam| {
+ cam.rotate_right(dt * self.camera_key_sensitivity as f64);
+ })
+ }),
+ KeyInputs::input(KeyEvent::Down, Key::Up, |dt| {
+ self.camera
+ .write()
+ .map_err(|e| TracerError::KeyError(e.to_string()))
+ .map(|mut cam| {
+ cam.rotate_up(dt * self.camera_key_sensitivity as f64);
+ })
+ }),
+ KeyInputs::input(KeyEvent::Down, Key::Down, |dt| {
+ self.camera
+ .write()
+ .map_err(|e| TracerError::KeyError(e.to_string()))
+ .map(|mut cam| {
+ cam.rotate_up(-dt * self.camera_key_sensitivity as f64);
+ })
+ }),
KeyInputs::input(KeyEvent::Release, Key::R, |_| {
self.render_image_event.signal();
Ok(())
@@ -105,6 +141,20 @@ impl<'renderer, 'action> SceneController for InteractiveScene<'renderer, 'action
]
}
+ fn mouse_input(&self) -> Option<MouseCallback> {
+ Some(Box::new(|x, y| {
+ self.camera
+ .write()
+ .map_err(|e| TracerError::KeyError(e.to_string()))
+ .map(|mut cam| {
+ cam.rotate(
+ (x * self.camera_sensitivity) as f64,
+ (y * self.camera_sensitivity) as f64,
+ )
+ })
+ }))
+ }
+
fn get_buffer(&self) -> Result<Option<Vec<u32>>, TracerError> {
self.buffer_updated
.wait_timeout(Duration::from_secs(0))
diff --git a/racer-tracer/src/vec3.rs b/racer-tracer/src/vec3.rs
index 9d04cb4..6877eea 100644
--- a/racer-tracer/src/vec3.rs
+++ b/racer-tracer/src/vec3.rs
@@ -1,3 +1,6 @@
+//TODO: Replace this with glam.
+use glam::f32::Vec3 as FVec3;
+
use std::{fmt, ops};
use serde::Deserialize;
@@ -326,6 +329,22 @@ impl fmt::Display for Vec3 {
}
}
+impl From<FVec3> for Vec3 {
+ fn from(v: FVec3) -> Self {
+ Vec3::new(v.x as f64, v.y as f64, v.z as f64)
+ }
+}
+
+impl From<Vec3> for FVec3 {
+ fn from(v: Vec3) -> Self {
+ FVec3 {
+ x: v.data[0] as f32,
+ y: v.data[1] as f32,
+ z: v.data[2] as f32,
+ }
+ }
+}
+
impl std::fmt::Debug for Vec3 {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Vec3").field("data", &self.data).finish()