Refactor main rendering loop to use TileIterator
This removes the old multithreading code, but will be using rayon soon.
This commit is contained in:
parent
d21d288013
commit
bdd05f3527
|
|
@ -12,8 +12,8 @@ use crate::Real;
|
|||
use std::sync::{Arc, Mutex};
|
||||
|
||||
struct ImageSampler<T: Real> {
|
||||
image_height_pixels: u32,
|
||||
image_width_pixels: u32,
|
||||
image_height_pixels: usize,
|
||||
image_width_pixels: usize,
|
||||
|
||||
film_width: T,
|
||||
film_height: T,
|
||||
|
|
@ -23,7 +23,7 @@ struct ImageSampler<T: Real> {
|
|||
}
|
||||
|
||||
impl<T: Real> ImageSampler<T> {
|
||||
pub fn new(width: u32, height: u32, camera_location: Point3<T>) -> ImageSampler<T> {
|
||||
pub fn new(width: usize, height: usize, camera_location: Point3<T>) -> ImageSampler<T> {
|
||||
let (film_width, film_height) = {
|
||||
let width: T = convert(width as f64);
|
||||
let height: T = convert(height as f64);
|
||||
|
|
@ -44,7 +44,7 @@ impl<T: Real> ImageSampler<T> {
|
|||
}
|
||||
}
|
||||
|
||||
fn scale(i: u32, n: u32, l: T) -> T {
|
||||
fn scale(i: usize, n: usize, l: T) -> T {
|
||||
let one: T = convert(1.0);
|
||||
let n: T = convert(n as f64);
|
||||
let i: T = convert(i as f64);
|
||||
|
|
@ -52,7 +52,7 @@ impl<T: Real> ImageSampler<T> {
|
|||
(i + convert(0.5)) * pixel_size
|
||||
}
|
||||
|
||||
fn ray_for_pixel(&self, row: u32, column: u32) -> Ray<T> {
|
||||
fn ray_for_pixel(&self, row: usize, column: usize) -> Ray<T> {
|
||||
Ray::new(
|
||||
self.camera_location,
|
||||
Vector3::new(
|
||||
|
|
@ -75,12 +75,12 @@ pub fn render_scene<T: Real>(output_image: Arc<Mutex<ImageRgbF<T>>>, scene: Arc<
|
|||
pub fn partial_render_scene<T: Real>(
|
||||
output_image: Arc<Mutex<ImageRgbF<T>>>,
|
||||
scene: Arc<Scene<T>>,
|
||||
row_start: u32,
|
||||
row_end: u32,
|
||||
column_start: u32,
|
||||
column_end: u32,
|
||||
height: u32,
|
||||
width: u32,
|
||||
row_start: usize,
|
||||
row_end: usize,
|
||||
column_start: usize,
|
||||
column_end: usize,
|
||||
height: usize,
|
||||
width: usize,
|
||||
) {
|
||||
let image_sampler = ImageSampler::new(width, height, scene.camera_location);
|
||||
let ambient_intensity: T = convert(0.0);
|
||||
|
|
|
|||
36
src/image.rs
36
src/image.rs
|
|
@ -8,12 +8,12 @@ use crate::Real;
|
|||
|
||||
pub struct ImageRgbU8 {
|
||||
pixel_data: Vec<u8>,
|
||||
width: u32,
|
||||
height: u32,
|
||||
width: usize,
|
||||
height: usize,
|
||||
}
|
||||
|
||||
impl ImageRgbU8 {
|
||||
pub fn new(width: u32, height: u32) -> ImageRgbU8 {
|
||||
pub fn new(width: usize, height: usize) -> ImageRgbU8 {
|
||||
ImageRgbU8 {
|
||||
width,
|
||||
height,
|
||||
|
|
@ -28,7 +28,7 @@ impl ImageRgbU8 {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn get_colour(&self, row: u32, column: u32) -> ColourRgbU8 {
|
||||
pub fn get_colour(&self, row: usize, column: usize) -> ColourRgbU8 {
|
||||
assert!(row < self.height && column < self.width);
|
||||
let index = self.calculate_index(row, column);
|
||||
ColourRgbU8 {
|
||||
|
|
@ -38,7 +38,7 @@ impl ImageRgbU8 {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_colour(&mut self, row: u32, column: u32, colour: ColourRgbU8) {
|
||||
pub fn set_colour(&mut self, row: usize, column: usize, colour: ColourRgbU8) {
|
||||
assert!(row < self.height && column < self.width);
|
||||
let index = self.calculate_index(row, column);
|
||||
self.pixel_data[index..index + 3].copy_from_slice(&colour.values[..]);
|
||||
|
|
@ -48,19 +48,19 @@ impl ImageRgbU8 {
|
|||
&self.pixel_data
|
||||
}
|
||||
|
||||
pub fn get_width(&self) -> u32 {
|
||||
pub fn get_width(&self) -> usize {
|
||||
self.width
|
||||
}
|
||||
|
||||
pub fn get_height(&self) -> u32 {
|
||||
pub fn get_height(&self) -> usize {
|
||||
self.height
|
||||
}
|
||||
|
||||
pub fn num_channels() -> u32 {
|
||||
pub fn num_channels() -> usize {
|
||||
3
|
||||
}
|
||||
|
||||
fn calculate_index(&self, row: u32, column: u32) -> usize {
|
||||
fn calculate_index(&self, row: usize, column: usize) -> usize {
|
||||
assert!(row < self.height && column < self.width);
|
||||
(((self.height - (row + 1)) * self.width + column) * Self::num_channels()) as usize
|
||||
}
|
||||
|
|
@ -68,12 +68,12 @@ impl ImageRgbU8 {
|
|||
|
||||
pub struct ImageRgbF<T: Real> {
|
||||
pixel_data: Vec<T>,
|
||||
width: u32,
|
||||
height: u32,
|
||||
width: usize,
|
||||
height: usize,
|
||||
}
|
||||
|
||||
impl<T: Real> ImageRgbF<T> {
|
||||
pub fn new(width: u32, height: u32) -> ImageRgbF<T> {
|
||||
pub fn new(width: usize, height: usize) -> ImageRgbF<T> {
|
||||
ImageRgbF {
|
||||
width,
|
||||
height,
|
||||
|
|
@ -88,13 +88,13 @@ impl<T: Real> ImageRgbF<T> {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn get_colour(&self, row: u32, column: u32) -> ColourRgbF<T> {
|
||||
pub fn get_colour(&self, row: usize, column: usize) -> ColourRgbF<T> {
|
||||
assert!(row < self.height && column < self.width);
|
||||
let index = self.calculate_index(row, column);
|
||||
ColourRgbF::from_vector3(&Vector3::from_row_slice(&self.pixel_data[index..index + 3]))
|
||||
}
|
||||
|
||||
pub fn set_colour(&mut self, row: u32, column: u32, colour: ColourRgbF<T>) {
|
||||
pub fn set_colour(&mut self, row: usize, column: usize, colour: ColourRgbF<T>) {
|
||||
assert!(row < self.height && column < self.width);
|
||||
let index = self.calculate_index(row, column);
|
||||
self.pixel_data[index..index + 3].copy_from_slice(&colour.as_vector3().as_slice());
|
||||
|
|
@ -104,19 +104,19 @@ impl<T: Real> ImageRgbF<T> {
|
|||
&self.pixel_data
|
||||
}
|
||||
|
||||
pub fn get_width(&self) -> u32 {
|
||||
pub fn get_width(&self) -> usize {
|
||||
self.width
|
||||
}
|
||||
|
||||
pub fn get_height(&self) -> u32 {
|
||||
pub fn get_height(&self) -> usize {
|
||||
self.height
|
||||
}
|
||||
|
||||
pub fn num_channels() -> u32 {
|
||||
pub fn num_channels() -> usize {
|
||||
3
|
||||
}
|
||||
|
||||
fn calculate_index(&self, row: u32, column: u32) -> usize {
|
||||
fn calculate_index(&self, row: usize, column: usize) -> usize {
|
||||
assert!(row < self.height && column < self.width);
|
||||
(((self.height - (row + 1)) * self.width + column) * Self::num_channels()) as usize
|
||||
}
|
||||
|
|
|
|||
60
src/main.rs
60
src/main.rs
|
|
@ -7,20 +7,17 @@ use std::time::Duration;
|
|||
|
||||
use nalgebra::{Point3, Vector3};
|
||||
|
||||
use itertools::iproduct;
|
||||
|
||||
use std::cmp::min;
|
||||
use std::path::Path;
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::thread;
|
||||
|
||||
use vanrijn::camera::partial_render_scene;
|
||||
use vanrijn::colour::{ColourRgbF, NamedColour};
|
||||
use vanrijn::image::{ClampingToneMapper, ImageRgbF, ImageRgbU8, ToneMapper};
|
||||
use vanrijn::materials::{LambertianMaterial, PhongMaterial, ReflectiveMaterial};
|
||||
use vanrijn::mesh::load_obj;
|
||||
use vanrijn::raycasting::{Primitive, Plane, Sphere};
|
||||
use vanrijn::raycasting::{Plane, Primitive, Sphere};
|
||||
use vanrijn::scene::Scene;
|
||||
use vanrijn::util::TileIterator;
|
||||
|
||||
fn update_texture(image: &ImageRgbU8, texture: &mut Texture) {
|
||||
texture
|
||||
|
|
@ -33,8 +30,8 @@ fn update_texture(image: &ImageRgbU8, texture: &mut Texture) {
|
|||
}
|
||||
|
||||
fn init_canvas(
|
||||
image_width: u32,
|
||||
image_height: u32,
|
||||
image_width: usize,
|
||||
image_height: usize,
|
||||
) -> Result<(Sdl, Canvas<sdl2::video::Window>), Box<dyn std::error::Error>> {
|
||||
let sdl_context = sdl2::init()?;
|
||||
let video_subsystem = sdl_context.video()?;
|
||||
|
|
@ -50,8 +47,8 @@ fn init_canvas(
|
|||
}
|
||||
|
||||
pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let image_width = 1200;
|
||||
let image_height = 900;
|
||||
let image_width = 320usize;
|
||||
let image_height = 240usize;
|
||||
|
||||
let (sdl_context, mut canvas) = init_canvas(image_width, image_height)?;
|
||||
|
||||
|
|
@ -117,48 +114,21 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
});
|
||||
|
||||
let mut event_pump = sdl_context.event_pump()?;
|
||||
let mut i = 0;
|
||||
'running: loop {
|
||||
let subtile_size = 16;
|
||||
let tile_divisions = 4;
|
||||
let tile_size = subtile_size * tile_divisions;
|
||||
for tile_row in 0..=(image_height + 1) / tile_size {
|
||||
for tile_column in 0..=(image_width + 1) / tile_size {
|
||||
//let row_start = tile_row * tile_size;
|
||||
//let row_end = min(tile_row * tile_size + tile_size, image_height);
|
||||
//let column_start = tile_column * tile_size;
|
||||
//let column_end = min(tile_column * tile_size + tile_size, image_width);
|
||||
let join_handles: Vec<_> = iproduct!(0..tile_divisions, 0..tile_divisions)
|
||||
.map(|(tile_i, tile_j)| {
|
||||
let start_i = tile_row * tile_size + tile_i * subtile_size;
|
||||
let start_j = tile_column * tile_size + tile_j * subtile_size;
|
||||
(
|
||||
start_i,
|
||||
min(start_i + subtile_size, image_height),
|
||||
start_j,
|
||||
min(start_j + subtile_size, image_width),
|
||||
)
|
||||
})
|
||||
.map(|(i_min, i_max, j_min, j_max)| {
|
||||
|
||||
'running: for tile in TileIterator::new(image_width as usize, image_height as usize, 16) {
|
||||
let image_ptr = output_image.clone();
|
||||
let scene_ptr = scene.clone();
|
||||
thread::spawn(move || {
|
||||
partial_render_scene(
|
||||
image_ptr,
|
||||
scene_ptr,
|
||||
i_min,
|
||||
i_max,
|
||||
j_min,
|
||||
j_max,
|
||||
tile.start_row,
|
||||
tile.end_row,
|
||||
tile.start_column,
|
||||
tile.end_column,
|
||||
image_height,
|
||||
image_width,
|
||||
);
|
||||
})
|
||||
})
|
||||
.collect();
|
||||
for h in join_handles {
|
||||
h.join();
|
||||
}
|
||||
|
||||
let locked_image = output_image.lock().unwrap();
|
||||
let mut output_image_rgbu8 = ImageRgbU8::new(image_width, image_height);
|
||||
ClampingToneMapper {}.apply_tone_mapping(&locked_image, &mut output_image_rgbu8);
|
||||
|
|
@ -177,7 +147,9 @@ pub fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
'running: loop {
|
||||
i = (i + 1) % 255;
|
||||
for event in event_pump.poll_iter() {
|
||||
match event {
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
use nalgebra::Point3;
|
||||
use nalgebra::{Point2, Point3};
|
||||
|
||||
use crate::Real;
|
||||
|
||||
|
|
|
|||
|
|
@ -1,28 +1,29 @@
|
|||
#[derive(Debug)]
|
||||
pub struct Tile {
|
||||
pub start_x: usize,
|
||||
pub end_x: usize,
|
||||
pub start_y: usize,
|
||||
pub end_y: usize,
|
||||
pub start_column: usize,
|
||||
pub end_column: usize,
|
||||
pub start_row: usize,
|
||||
pub end_row: usize,
|
||||
}
|
||||
|
||||
pub struct TileIterator {
|
||||
tile_size: usize,
|
||||
total_height: usize,
|
||||
total_width: usize,
|
||||
current_x: usize,
|
||||
current_y: usize,
|
||||
current_column: usize,
|
||||
current_row: usize,
|
||||
}
|
||||
|
||||
impl TileIterator {
|
||||
pub fn new(total_width: usize, total_height: usize, tile_size: usize) -> TileIterator {
|
||||
// If tile_size*2 is greater than usize::max_value(), increment would overflow
|
||||
assert!(tile_size > 0 && tile_size*2 < usize::max_value());
|
||||
assert!(tile_size > 0 && tile_size * 2 < usize::max_value());
|
||||
TileIterator {
|
||||
tile_size,
|
||||
total_width,
|
||||
total_height,
|
||||
current_x: 0,
|
||||
current_y: 0,
|
||||
current_column: 0,
|
||||
current_row: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -31,25 +32,25 @@ impl Iterator for TileIterator {
|
|||
type Item = Tile;
|
||||
|
||||
fn next(&mut self) -> Option<Tile> {
|
||||
if self.current_y >= self.total_height {
|
||||
if self.current_row >= self.total_height {
|
||||
None
|
||||
} else {
|
||||
let start_x = self.current_x;
|
||||
let end_x = self.total_width.min(start_x + self.tile_size);
|
||||
let start_y = self.current_y;
|
||||
let end_y = self.total_height.min(start_y + self.tile_size);
|
||||
let start_column = self.current_column;
|
||||
let end_column = self.total_width.min(start_column + self.tile_size);
|
||||
let start_row = self.current_row;
|
||||
let end_row = self.total_height.min(start_row + self.tile_size);
|
||||
|
||||
self.current_x += self.tile_size;
|
||||
if self.current_x >= self.total_width {
|
||||
self.current_y += self.tile_size;
|
||||
self.current_x = 0;
|
||||
self.current_column += self.tile_size;
|
||||
if self.current_column >= self.total_width {
|
||||
self.current_row += self.tile_size;
|
||||
self.current_column = 0;
|
||||
}
|
||||
|
||||
Some(Tile {
|
||||
start_x,
|
||||
end_x,
|
||||
start_y,
|
||||
end_y,
|
||||
start_column,
|
||||
end_column,
|
||||
start_row,
|
||||
end_row,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -95,7 +96,7 @@ mod tests {
|
|||
#[quickcheck]
|
||||
fn tiles_are_expected_size(width: usize, height: usize, tile_size: usize) -> TestResult {
|
||||
let max_size = 10000;
|
||||
// Check size of width and height first, since width*height my overflow.
|
||||
// Check size of width and height first, since width*height might overflow.
|
||||
if width > max_size || height > max_size || width * height > max_size {
|
||||
return TestResult::discard();
|
||||
}
|
||||
|
|
@ -105,7 +106,8 @@ mod tests {
|
|||
|
||||
let mut target = TileIterator::new(width, height, tile_size);
|
||||
TestResult::from_bool(target.all(|tile| {
|
||||
tile.end_x - tile.start_x <= tile_size && tile.end_y - tile.start_y <= tile_size
|
||||
tile.end_column - tile.start_column <= tile_size
|
||||
&& tile.end_row - tile.start_row <= tile_size
|
||||
}))
|
||||
}
|
||||
|
||||
|
|
@ -116,7 +118,7 @@ mod tests {
|
|||
tile_size: usize,
|
||||
) -> TestResult {
|
||||
let max_size = 10000;
|
||||
// Check size of width and height first, since width*height my overflow.
|
||||
// Check size of width and height first, since width*height might overflow.
|
||||
if width > max_size || height > max_size || width * height > max_size {
|
||||
return TestResult::discard();
|
||||
}
|
||||
|
|
@ -128,9 +130,9 @@ mod tests {
|
|||
let mut index_counts = vec![0; width * height];
|
||||
let mut total_count = 0;
|
||||
for tile in target {
|
||||
for x in tile.start_x..tile.end_x {
|
||||
for y in tile.start_y..tile.end_y {
|
||||
index_counts[y * width + x] += 1;
|
||||
for column in tile.start_column..tile.end_column {
|
||||
for row in tile.start_row..tile.end_row {
|
||||
index_counts[row * width + column] += 1;
|
||||
total_count += 1;
|
||||
if total_count > width * height {
|
||||
return TestResult::failed();
|
||||
|
|
|
|||
Loading…
Reference in New Issue