Use Array2D for storage in ImageRgbU8

This commit is contained in:
Matthew Gordon 2020-09-01 22:26:50 -04:00
parent 40d9bb0bb1
commit ef0fb96f9d
3 changed files with 50 additions and 48 deletions

View File

@ -53,8 +53,11 @@ impl ImageSampler {
Vec3::new( Vec3::new(
Self::scale(column, self.image_width_pixels, self.film_width) Self::scale(column, self.image_width_pixels, self.film_width)
- self.film_width * 0.5, - self.film_width * 0.5,
Self::scale(row, self.image_height_pixels, self.film_height) Self::scale(
- self.film_height * 0.5, self.image_height_pixels - (row + 1),
self.image_height_pixels,
self.film_height,
) - self.film_height * 0.5,
self.film_distance, self.film_distance,
), ),
) )
@ -176,7 +179,7 @@ mod tests {
ImageSampler::scale(200, 800, target.film_width) - target.film_width * 0.5; ImageSampler::scale(200, 800, target.film_width) - target.film_width * 0.5;
assert!((point_on_film_plane.x() - expected_x).abs() < 0.0000000001); assert!((point_on_film_plane.x() - expected_x).abs() < 0.0000000001);
let expected_y = let expected_y =
ImageSampler::scale(100, 600, target.film_height) - target.film_height * 0.5; -ImageSampler::scale(100, 600, target.film_height) + target.film_height * 0.5;
assert!((point_on_film_plane.y() - expected_y).abs() < 0.0000000001); assert!((point_on_film_plane.y() - expected_y).abs() < 0.0000000001);
} }
} }

View File

@ -5,55 +5,41 @@ use std::path::Path;
use crate::colour::{ColourRgbF, ColourRgbU8}; use crate::colour::{ColourRgbF, ColourRgbU8};
use crate::math::Vec3; use crate::math::Vec3;
use crate::util::Array2D;
pub struct ImageRgbU8 { pub struct ImageRgbU8 {
pixel_data: Vec<u8>, data: Array2D<[u8; 3]>,
width: usize,
height: usize,
} }
impl ImageRgbU8 { impl ImageRgbU8 {
pub fn new(width: usize, height: usize) -> ImageRgbU8 { pub fn new(width: usize, height: usize) -> ImageRgbU8 {
ImageRgbU8 { ImageRgbU8 {
width, data: Array2D::new(height, width),
height,
pixel_data: vec![0; (width * height * 3) as usize],
} }
} }
pub fn clear(&mut self) -> &mut ImageRgbU8 {
for byte in self.pixel_data.iter_mut() {
*byte = 0u8;
}
self
}
pub fn get_colour(&self, row: usize, column: usize) -> 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 { ColourRgbU8 {
values: self.pixel_data[index..index + 3] values: self.data[row][column].try_into().expect("Wrong length."),
.try_into()
.expect("Wrong length."),
} }
} }
pub fn set_colour(&mut self, row: usize, column: usize, colour: ColourRgbU8) { pub fn set_colour(&mut self, row: usize, column: usize, colour: ColourRgbU8) {
assert!(row < self.height && column < self.width); let slice = &mut self.data[row][column];
let index = self.calculate_index(row, column); slice.copy_from_slice(&colour.values[..]);
self.pixel_data[index..index + 3].copy_from_slice(&colour.values[..]);
} }
pub fn get_pixel_data(&self) -> &Vec<u8> { pub fn get_pixel_data(&self) -> &[u8] {
&self.pixel_data let data = self.data.as_slice();
unsafe { std::slice::from_raw_parts(data[0].as_ptr(), data.len() * 3) }
} }
pub fn get_width(&self) -> usize { pub fn get_width(&self) -> usize {
self.width self.data.get_width()
} }
pub fn get_height(&self) -> usize { pub fn get_height(&self) -> usize {
self.height self.data.get_height()
} }
pub fn num_channels() -> usize { pub fn num_channels() -> usize {
@ -61,35 +47,24 @@ impl ImageRgbU8 {
} }
pub fn update(&mut self, start_row: usize, start_column: usize, image: &ImageRgbU8) { pub fn update(&mut self, start_row: usize, start_column: usize, image: &ImageRgbU8) {
assert!(start_column + image.width <= self.width); self.data.update_block(start_row, start_column, &image.data);
assert!(start_row + image.height <= self.height);
for row in 0..image.height {
let source_start = image.calculate_index(row, 0);
let source_end = image.calculate_index(row, image.width - 1) + 3;
let destination_start = self.calculate_index(start_row + row, start_column);
let destination_end =
self.calculate_index(start_row + row, start_column + image.width - 1) + 3;
self.pixel_data[destination_start..destination_end]
.copy_from_slice(&image.pixel_data[source_start..source_end]);
}
} }
pub fn write_png(&self, filename: &Path) -> Result<(), std::io::Error> { pub fn write_png(&self, filename: &Path) -> Result<(), std::io::Error> {
let file = File::create(filename)?; let file = File::create(filename)?;
let ref mut file_buffer = BufWriter::new(file); let ref mut file_buffer = BufWriter::new(file);
let mut encoder = png::Encoder::new(file_buffer, self.width as u32, self.height as u32); let mut encoder = png::Encoder::new(
file_buffer,
self.get_width() as u32,
self.get_height() as u32,
);
encoder.set_color(png::ColorType::RGB); encoder.set_color(png::ColorType::RGB);
encoder.set_depth(png::BitDepth::Eight); encoder.set_depth(png::BitDepth::Eight);
let mut writer = encoder.write_header()?; let mut writer = encoder.write_header()?;
writer.write_image_data(self.pixel_data.as_slice())?; writer.write_image_data(self.get_pixel_data())?;
Ok(()) Ok(())
} }
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
}
} }
pub struct ImageRgbF { pub struct ImageRgbF {
@ -213,6 +188,30 @@ impl ToneMapper for ClampingToneMapper {
mod tests { mod tests {
use super::*; use super::*;
#[test]
fn get_pixel_data_returns_correct_values() {
let mut target = ImageRgbU8::new(4, 3);
for i in 0..3 {
for j in 0..4 {
target.set_colour(
i,
j,
ColourRgbU8 {
values: [i as u8, j as u8, i as u8],
},
)
}
}
for i in 0..3 {
for j in 0..4 {
let index = (i * 4 + j) * 3;
assert!(target.get_pixel_data()[index] == i as u8);
assert!(target.get_pixel_data()[index + 1] == j as u8);
assert!(target.get_pixel_data()[index + 2] == i as u8);
}
}
}
mod normalized_as_byte { mod normalized_as_byte {
use super::*; use super::*;

View File

@ -78,11 +78,11 @@ fn update_texture(tile: &Tile, image: &ImageRgbU8, texture: &mut Texture) {
.update( .update(
Rect::new( Rect::new(
tile.start_column as i32, tile.start_column as i32,
texture.query().height as i32 - (tile.start_row as i32 + tile.height() as i32), tile.start_row as i32,
tile.width() as u32, tile.width() as u32,
tile.height() as u32, tile.height() as u32,
), ),
image.get_pixel_data().as_slice(), image.get_pixel_data(),
(image.get_width() * ImageRgbU8::num_channels()) as usize, (image.get_width() * ImageRgbU8::num_channels()) as usize,
) )
.expect("Couldn't update texture."); .expect("Couldn't update texture.");