|
@@ -1,34 +1,248 @@
|
|
|
+use std::fs::File;
|
|
|
+use std::io::BufReader;
|
|
|
+use std::io::Read;
|
|
|
|
|
|
-mod random {
|
|
|
- use std::fs::File;
|
|
|
- use std::io::Read;
|
|
|
+// ┏━┓┏━┓┏┓╻╺┳┓┏━┓┏┳┓ ┏┓╻╻ ╻┏┳┓┏┓ ┏━╸┏━┓ ┏━╸┏━╸┏┓╻┏━╸┏━┓┏━┓╺┳╸╻┏━┓┏┓╻
|
|
|
+// ┣┳┛┣━┫┃┗┫ ┃┃┃ ┃┃┃┃ ┃┗┫┃ ┃┃┃┃┣┻┓┣╸ ┣┳┛ ┃╺┓┣╸ ┃┗┫┣╸ ┣┳┛┣━┫ ┃ ┃┃ ┃┃┗┫
|
|
|
+// ╹┗╸╹ ╹╹ ╹╺┻┛┗━┛╹ ╹ ╹ ╹┗━┛╹ ╹┗━┛┗━╸╹┗╸ ┗━┛┗━╸╹ ╹┗━╸╹┗╸╹ ╹ ╹ ╹┗━┛╹ ╹
|
|
|
|
|
|
- pub struct RNG {
|
|
|
- random_device: File
|
|
|
+pub struct RNG {
|
|
|
+ random_device: BufReader<File>,
|
|
|
+}
|
|
|
+
|
|
|
+impl RNG {
|
|
|
+ pub fn next_float(&mut self) -> f32 {
|
|
|
+ let mut buf: [u8; 4] = [0, 0, 0, 0];
|
|
|
+
|
|
|
+ self.random_device
|
|
|
+ .read(&mut buf)
|
|
|
+ .expect("Read from /dev/random failed");
|
|
|
+
|
|
|
+ let val: f32 = u32::from_be_bytes(buf) as f32;
|
|
|
+ val as f32 / u32::max_value() as f32
|
|
|
}
|
|
|
|
|
|
- impl RNG {
|
|
|
- pub fn next_float(&mut self) -> f32 {
|
|
|
- let mut buf: [u8; 4] = [0, 0, 0, 0];
|
|
|
+ pub fn create() -> RNG {
|
|
|
+ let f = File::open("/dev/urandom").expect("Did not find source of randomness");
|
|
|
+ let reader: BufReader<File> = BufReader::new(f);
|
|
|
+
|
|
|
+ return RNG {
|
|
|
+ random_device: reader,
|
|
|
+ };
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// ┏━╸┏━╸┏━┓┏┳┓┏━╸╺┳╸┏━┓╻ ╻
|
|
|
+// ┃╺┓┣╸ ┃ ┃┃┃┃┣╸ ┃ ┣┳┛┗┳┛
|
|
|
+// ┗━┛┗━╸┗━┛╹ ╹┗━╸ ╹ ╹┗╸ ╹
|
|
|
|
|
|
- self.random_device.read(&mut buf).expect("Read from /dev/random failed");
|
|
|
+#[derive(Copy, Clone)]
|
|
|
+pub struct Vec3 {
|
|
|
+ x: f32,
|
|
|
+ y: f32,
|
|
|
+ z: f32,
|
|
|
+}
|
|
|
+
|
|
|
+// ╻┏┳┓┏━┓┏━╸┏━╸ ╻┏━┓
|
|
|
+// ┃┃┃┃┣━┫┃╺┓┣╸ ┃┃ ┃
|
|
|
+// ╹╹ ╹╹ ╹┗━┛┗━╸ ╹┗━┛
|
|
|
+use std::convert::From;
|
|
|
+use std::io::BufWriter;
|
|
|
+use std::io::Write;
|
|
|
+use std::path::Path;
|
|
|
+
|
|
|
+pub struct Image {
|
|
|
+ width: u16,
|
|
|
+ height: u16,
|
|
|
+ data: Vec<Vec3>,
|
|
|
+}
|
|
|
+
|
|
|
+impl Image {
|
|
|
+ fn get_pixel(&self, x: usize, y: usize) -> &Vec3 {
|
|
|
+ &self.data[y * self.width as usize + x]
|
|
|
+ }
|
|
|
+
|
|
|
+ fn mod_pixel(&mut self, x: usize, y: usize) -> &mut Vec3 {
|
|
|
+ &mut self.data[y * self.width as usize + x]
|
|
|
+ }
|
|
|
|
|
|
- let val : f32 = u32::from_be_bytes(buf) as f32;
|
|
|
+ fn new(width: u16, height: u16) -> Image {
|
|
|
+ let mut data: Vec<Vec3> = Vec::new();
|
|
|
+ data.resize(
|
|
|
+ usize::from(width) * usize::from(height),
|
|
|
+ Vec3 {
|
|
|
+ x: 0.0,
|
|
|
+ y: 0.0,
|
|
|
+ z: 0.0,
|
|
|
+ },
|
|
|
+ );
|
|
|
|
|
|
- val as f32 / u32::max_value() as f32
|
|
|
+ Image {
|
|
|
+ width: width,
|
|
|
+ height: height,
|
|
|
+ data: data,
|
|
|
}
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+fn read_int(v: &[u8]) -> u32 {
|
|
|
+ let mut result = 0;
|
|
|
+
|
|
|
+ for i in 0..3 {
|
|
|
+ result |= (v[i] as u32) << (i * 8);
|
|
|
+ }
|
|
|
+
|
|
|
+ result
|
|
|
+}
|
|
|
+
|
|
|
+fn read_int16(v: &[u8]) -> u16 {
|
|
|
+ v[1] as u16 >> 8 | v[0] as u16
|
|
|
+}
|
|
|
+
|
|
|
+fn read_vec3(v: &[u8]) -> Vec3 {
|
|
|
+ Vec3 {
|
|
|
+ x: v[2] as f32,
|
|
|
+ y: v[1] as f32,
|
|
|
+ z: v[0] as f32,
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+fn round_row_size(width: u32) -> u32 {
|
|
|
+ ((24 * width + 31) / 32) * 4
|
|
|
+}
|
|
|
+
|
|
|
+pub fn load_bmp(path: &Path) -> Image {
|
|
|
+ // See https://en.wikipedia.org/wiki/BMP_file_format for more information.
|
|
|
+ // BMP is little-endian (least-significant bytes first)
|
|
|
+ // Some limitations here:
|
|
|
+ // - we only support bottom-up bitmaps
|
|
|
+ // - without compression
|
|
|
+ // - and a depth of 24 bits per pixel
|
|
|
+
|
|
|
+ let mut buf = Vec::new();
|
|
|
+ let mut f = BufReader::new(File::open(path).expect("Could not find image file"));
|
|
|
+ f.read_to_end(&mut buf).expect("Could not read image file");
|
|
|
|
|
|
- pub fn create() -> RNG {
|
|
|
- return RNG {
|
|
|
- random_device: File::open("/dev/urandom").expect("Did not find source of randomness")
|
|
|
- }
|
|
|
+ assert!(
|
|
|
+ buf[0] == 'B' as u8 && buf[1] == 'M' as u8,
|
|
|
+ "File is not a bitmap file"
|
|
|
+ );
|
|
|
+
|
|
|
+ let width = read_int(&buf[18..22]);
|
|
|
+ let height = read_int(&buf[22..26]);
|
|
|
+
|
|
|
+ let compression = read_int(&buf[30..34]);
|
|
|
+ assert!(compression == 0, "Only uncompressed BMPs are supported");
|
|
|
+
|
|
|
+ let depth = read_int16(&buf[28..30]);
|
|
|
+ assert!(depth == 24, "Only 24 bits per pixel are supported");
|
|
|
+
|
|
|
+ let offset = read_int(&buf[10..14]);
|
|
|
+
|
|
|
+ let row_size = round_row_size(width);
|
|
|
+
|
|
|
+ let mut image_data = Vec::new();
|
|
|
+
|
|
|
+ for row in 0..height {
|
|
|
+ for col in 0..width {
|
|
|
+ let y = height - row - 1;
|
|
|
+ let x = 3 * col;
|
|
|
+ let idx = (offset + y * row_size + x) as usize;
|
|
|
+ let pixel = read_vec3(&buf[idx..(idx + 3)]);
|
|
|
+ image_data.push(pixel);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ assert!(image_data.len() == (width * height) as usize);
|
|
|
+
|
|
|
+ Image {
|
|
|
+ width: width as u16,
|
|
|
+ height: height as u16,
|
|
|
+ data: image_data,
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+fn write_int(f: &mut dyn Write, v: u32) -> std::io::Result<()> {
|
|
|
+ let bytes = [v as u8, (v >> 8) as u8, (v >> 16) as u8, (v >> 24) as u8];
|
|
|
+ f.write_all(&bytes)?;
|
|
|
+
|
|
|
+ Ok(())
|
|
|
}
|
|
|
|
|
|
+fn write_int16(f: &mut dyn Write, v: u16) -> std::io::Result<()> {
|
|
|
+ let bytes = [v as u8, (v >> 8) as u8];
|
|
|
+ f.write_all(&bytes)?;
|
|
|
+
|
|
|
+ Ok(())
|
|
|
+}
|
|
|
+
|
|
|
+fn write_vec3(f: &mut dyn Write, v: &Vec3) -> std::io::Result<()> {
|
|
|
+ let bytes = [v.z as u8, v.y as u8, v.x as u8];
|
|
|
+ f.write_all(&bytes)?;
|
|
|
+
|
|
|
+ Ok(())
|
|
|
+}
|
|
|
+
|
|
|
+fn save_bmp(p: &Path, i: &Image) -> std::io::Result<()> {
|
|
|
+ let f: File = File::create(p)?;
|
|
|
+ let mut w = BufWriter::new(f);
|
|
|
+
|
|
|
+ // File header
|
|
|
+ w.write_all(&['B' as u8, 'M' as u8])?;
|
|
|
+ write_int(&mut w, 0)?; // size, left blank for now
|
|
|
+ write_int(&mut w, 0)?; // reserved bytes
|
|
|
+ write_int(&mut w, 54)?; // offset
|
|
|
+
|
|
|
+ // Bitmap info header
|
|
|
+ write_int(&mut w, 40)?; // header size in bytes
|
|
|
+ write_int(&mut w, i.width as u32)?;
|
|
|
+ write_int(&mut w, i.height as u32)?;
|
|
|
+ write_int16(&mut w, 1)?; // number of color planes
|
|
|
+ write_int16(&mut w, 24)?; // bits per pixel
|
|
|
+ write_int(&mut w, 0)?; // no compression
|
|
|
+ write_int(&mut w, 0)?; // image size
|
|
|
+ write_int(&mut w, 1000)?; // horizontal resolution in pixels per metre
|
|
|
+ write_int(&mut w, 1000)?; // vertical resolution
|
|
|
+ write_int(&mut w, 0)?; // number of colors
|
|
|
+ write_int(&mut w, 0)?; // number of important colors
|
|
|
+
|
|
|
+ // Pixel data
|
|
|
+ for y in (0..i.height).rev() {
|
|
|
+ for x in 0..i.width {
|
|
|
+ write_vec3(&mut w, i.get_pixel(x.into(), y.into()))?;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ Ok(())
|
|
|
+}
|
|
|
|
|
|
fn main() {
|
|
|
- let mut rng : random::RNG = random::RNG::create();
|
|
|
+ let mut rng = RNG::create();
|
|
|
println!("{}", rng.next_float());
|
|
|
+
|
|
|
+ let path = Path::new("skymap.bmp");
|
|
|
+ let image = load_bmp(&path);
|
|
|
+ println!(
|
|
|
+ "Image length: {}, {}x{}",
|
|
|
+ image.data.len(),
|
|
|
+ image.width,
|
|
|
+ image.height
|
|
|
+ );
|
|
|
+
|
|
|
+ let pix = image.get_pixel(0, 0);
|
|
|
+ println!("RGB Val: ({}, {}, {})", pix.x, pix.y, pix.z);
|
|
|
+
|
|
|
+ // Create a new pixel from scratch
|
|
|
+ let mut rand_bitmap = Image::new(1024, 1024);
|
|
|
+ for x in 0..1024 {
|
|
|
+ for y in 0..1024 {
|
|
|
+ let mut p = rand_bitmap.mod_pixel(x, y);
|
|
|
+ p.x = rng.next_float() * 255.0;
|
|
|
+ p.y = rng.next_float() * 255.0;
|
|
|
+ p.z = rng.next_float() * 255.0;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ let outpath = Path::new("random.bmp");
|
|
|
+ save_bmp(&outpath, &rand_bitmap).expect("Could not save bitmap :(");
|
|
|
}
|