summaryrefslogtreecommitdiff
path: root/racer-tracer/src
diff options
context:
space:
mode:
authorSakarias Johansson <sakarias.johansson@goodbyekansas.com>2023-03-03 19:57:51 +0100
committerSakarias Johansson <sakariasjohansson@hotmail.com>2023-03-03 20:12:05 +0100
commitc742933fbffbb5366a5f07c2b28c1a163a61b93e (patch)
tree1ec4e37b54bc08f105f9a5807544d86c95889308 /racer-tracer/src
parent548011ba6316e83c95b327768581d7d53d49a63e (diff)
downloadracer-tracer-c742933fbffbb5366a5f07c2b28c1a163a61b93e.tar.gz
racer-tracer-c742933fbffbb5366a5f07c2b28c1a163a61b93e.tar.xz
racer-tracer-c742933fbffbb5366a5f07c2b28c1a163a61b93e.zip
✨ Add image save support
Once the render is done it saves an PNG.
Diffstat (limited to 'racer-tracer/src')
-rw-r--r--racer-tracer/src/config.rs5
-rw-r--r--racer-tracer/src/error.rs8
-rw-r--r--racer-tracer/src/main.rs83
-rw-r--r--racer-tracer/src/vec3.rs3
4 files changed, 85 insertions, 14 deletions
diff --git a/racer-tracer/src/config.rs b/racer-tracer/src/config.rs
index cf747ec..7bd7887 100644
--- a/racer-tracer/src/config.rs
+++ b/racer-tracer/src/config.rs
@@ -1,3 +1,5 @@
+use std::path::PathBuf;
+
use config::File;
use serde::Deserialize;
use structopt::StructOpt;
@@ -59,6 +61,9 @@ pub struct Config {
#[serde(default)]
pub scene: Option<String>,
+
+ #[serde(default)]
+ pub image_output_dir: Option<PathBuf>,
}
impl Config {
diff --git a/racer-tracer/src/error.rs b/racer-tracer/src/error.rs
index 6e1b305..1725d1a 100644
--- a/racer-tracer/src/error.rs
+++ b/racer-tracer/src/error.rs
@@ -5,6 +5,9 @@ pub enum TracerError {
#[error("Unknown error: {message}")]
Unknown { message: String, exit_code: i32 },
+ #[error("Error: {0}")]
+ Generic(String),
+
#[error("Failed to create window: {0}")]
FailedToCreateWindow(String),
@@ -31,6 +34,9 @@ pub enum TracerError {
#[error("Cancel event")]
CancelEvent,
+
+ #[error("Image save error: {0}")]
+ ImageSave(String),
}
impl From<TracerError> for i32 {
@@ -49,6 +55,8 @@ impl From<TracerError> for i32 {
TracerError::FailedToAcquireLock(_) => 8,
TracerError::ExitEvent => 9,
TracerError::CancelEvent => 10,
+ TracerError::Generic(_) => 11,
+ TracerError::ImageSave(_) => 12,
}
}
}
diff --git a/racer-tracer/src/main.rs b/racer-tracer/src/main.rs
index 7d7510f..aa1d974 100644
--- a/racer-tracer/src/main.rs
+++ b/racer-tracer/src/main.rs
@@ -11,14 +11,18 @@ mod scene;
mod util;
mod vec3;
+extern crate image as img;
+
use std::{
convert::TryFrom,
+ path::PathBuf,
sync::RwLock,
time::{Duration, Instant},
vec::Vec,
};
use minifb::{Key, Window, WindowOptions};
+use sha2::{Digest, Sha256};
use synchronoise::SignalEvent;
use crate::{
@@ -70,7 +74,7 @@ fn run(config: Config) -> Result<(), TracerError> {
},
|_| {
let render_time = Instant::now();
- let res = render(
+ render(
&screen_buffer,
&camera,
&image,
@@ -78,21 +82,74 @@ fn run(config: Config) -> Result<(), TracerError> {
&config.render,
Some(&cancel_render),
None,
- );
- render_image.reset();
-
- println!(
- "It took {} seconds to render the image.",
- Instant::now().duration_since(render_time).as_secs()
- );
-
- // TODO: Output the image
-
- res
+ )
+ .and_then(|_| {
+ render_image.reset();
+
+ println!(
+ "It took {} seconds to render the image.",
+ Instant::now().duration_since(render_time).as_secs()
+ );
+ screen_buffer
+ .read()
+ .map_err(|e| {
+ TracerError::FailedToAcquireLock(e.to_string())
+ })
+ .map(|buf| {
+ // Convert ARGB8 to RGBA8
+ buf.iter()
+ .map(|v| {
+ let a: u32 = (v >> 24) & 0xff;
+ let r: u32 = (v >> 16) & 0xff;
+ let g: u32 = (v >> 8) & 0xff;
+ let b: u32 = v & 0xff;
+
+ (r << 24) | (g << 16) | (b << 8) | a
+ })
+ .flat_map(|val| val.to_be_bytes())
+ .collect::<Vec<u8>>()
+ })
+ })
+ .and_then(|buf| {
+ match &config.image_output_dir {
+ Some(image_dir) => {
+ println!("Saving image...");
+ let mut sha = Sha256::new();
+
+ sha.update(buf.as_slice());
+
+ let mut file_path = PathBuf::from(image_dir);
+ file_path.push(format!("{:X}.png", sha.finalize()));
+
+ img::save_buffer(
+ file_path.as_path(),
+ buf.as_slice(),
+ config.screen.width as u32,
+ config.screen.height as u32,
+ img::ColorType::Rgba8,
+ )
+ .map_err(|e| {
+ let error = e.to_string();
+ TracerError::ImageSave(error)
+ })
+ .map(|_| {
+ println!(
+ "Saved image to: {}",
+ file_path.to_string_lossy()
+ );
+ })
+ }
+ None => Ok(()),
+ }
+ })
},
)
});
}
+
+ if render_res.is_err() {
+ exit.signal();
+ }
});
s.spawn(|_| {
@@ -109,7 +166,7 @@ fn run(config: Config) -> Result<(), TracerError> {
})
.and_then(|mut window| {
let mut t = Instant::now();
- while window.is_open() && !window.is_key_down(Key::Escape) {
+ while window.is_open() && !window.is_key_down(Key::Escape) && !exit.status() {
let dt = t.elapsed().as_micros() as f64 / 1000000.0;
t = Instant::now();
// Sleep a bit to not hog the lock on the buffer all the time.
diff --git a/racer-tracer/src/vec3.rs b/racer-tracer/src/vec3.rs
index c5edf32..8530bfe 100644
--- a/racer-tracer/src/vec3.rs
+++ b/racer-tracer/src/vec3.rs
@@ -87,7 +87,8 @@ impl Vec3 {
let red: u32 = (self.data[0] * 255.0) as u32;
let green: u32 = (self.data[1] * 255.0) as u32;
let blue: u32 = (self.data[2] * 255.0) as u32;
- (red << 16) | green << 8 | blue
+ // ARGB
+ (255 << 24) | (red << 16) | green << 8 | blue
}
pub fn random() -> Self {