diff --git a/src/main.rs b/src/main.rs index cc736a4..41969ec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,4 +3,47 @@ extern crate justerror; mod tga; -fn main() {} +use tga::*; + +const WHITE: TGAColor = TGAColor { + bgra: [255, 255, 255, 255], +}; + +const GREEN: TGAColor = TGAColor { + bgra: [0, 255, 0, 255], +}; + +const RED: TGAColor = TGAColor { + bgra: [0, 0, 255, 255], +}; + +const BLUE: TGAColor = TGAColor { + bgra: [255, 128, 64, 255], +}; + +const YELLOW: TGAColor = TGAColor { + bgra: [0, 200, 255, 255], +}; + +fn main() { + let w = 64; + let h = 64; + let mut framebuffer = TGAImage::new(w, h, TGAFormat::RGB); + + let ax = 7; + let ay = 3; + let bx = 12; + let by = 37; + let cx = 62; + let cy = 53; + + framebuffer.set(ax, ay, &WHITE); + framebuffer.set(bx, by, &WHITE); + framebuffer.set(cx, cy, &WHITE); + + framebuffer + .write_file("framebuffer.tga", true, true) + .unwrap(); + + let new = TGAImage::from_file("framebuffer.tga").unwrap(); +} diff --git a/src/tga.rs b/src/tga.rs index f8f909a..f3c3f15 100644 --- a/src/tga.rs +++ b/src/tga.rs @@ -25,14 +25,14 @@ pub struct TGAHeader { #[derive(Debug, Default, Clone, Copy, PartialEq, Eq)] #[repr(u8)] -pub enum Format { +pub enum TGAFormat { Grayscale = 1, RGB = 3, #[default] RGBA = 4, } -impl TryFrom for Format { +impl TryFrom for TGAFormat { type Error = String; fn try_from(value: u8) -> Result { @@ -94,8 +94,8 @@ impl TGAColor { } #[derive(Debug, Default, Clone, PartialEq, Eq)] -struct TGAImage { - pub format: Format, +pub struct TGAImage { + pub format: TGAFormat, pub width: u16, pub height: u16, data: Vec, @@ -128,12 +128,13 @@ impl From for TGAError { } impl TGAImage { - pub fn new(width: u16, height: u16, format: Format) -> Self { + pub fn new(width: u16, height: u16, format: TGAFormat) -> Self { + let size = format as usize * (width * height) as usize; Self { format, width, height, - data: Vec::with_capacity((format as usize) * (width * height) as usize), + data: vec![0u8; size], } } @@ -158,7 +159,7 @@ impl TGAImage { self.height = header.height; let nbytes = self.format as usize * (self.width * self.height) as usize; - let mut image_data = Vec::with_capacity(nbytes); + let mut image_data = vec![0u8; nbytes]; match header.datatype_code { 2 | 3 => { file.read_to_end(&mut image_data)?; @@ -175,16 +176,6 @@ impl TGAImage { } pub fn write_file(&mut self, file: &str, do_vflip: bool, do_rle: bool) -> IoResult { - let mut developer_area = [0u8; 4]; - let mut extension_area = [0u8; 4]; - let mut footer: Vec = vec![ - 'T', 'R', 'U', 'E', 'V', 'I', 'S', 'I', 'O', 'N', '-', 'X', 'F', 'I', 'L', 'E', '.', - '\0', - ] - .into_iter() - .map(|b| b as u8) - .collect(); - let mut file = std::fs::File::create(file)?; let mut header = TGAHeader::default(); @@ -193,8 +184,8 @@ impl TGAImage { header.height = self.height; header.datatype_code = match self.format { - Format::Grayscale if do_rle => 11, - Format::Grayscale => 3, + TGAFormat::Grayscale if do_rle => 11, + TGAFormat::Grayscale => 3, _ if do_rle => 10, _ => 2, }; @@ -211,6 +202,18 @@ impl TGAImage { file.write_all(&mut self.data)?; } + file.flush()?; + + let mut developer_area = [0u8; 4]; + let mut extension_area = [0u8; 4]; + let mut footer: Vec = vec![ + 'T', 'R', 'U', 'E', 'V', 'I', 'S', 'I', 'O', 'N', '-', 'X', 'F', 'I', 'L', 'E', '.', + '\0', + ] + .into_iter() + .map(|b| b as u8) + .collect(); + file.write_all(&mut developer_area)?; file.write_all(&mut extension_area)?; file.write_all(&mut footer)?; @@ -228,12 +231,34 @@ impl TGAImage { todo!() } - pub fn set(&mut self, x: u32, y: u32, color: &TGAColor) { - todo!() + pub fn set(&mut self, x: u16, y: u16, color: &TGAColor) { + if self.data.is_empty() || x > self.width || y > self.height { + return; + } + + let bpp = self.bytes_per_pixel() as usize; + let start = (x + y * self.width) as usize * bpp; + let end = start + bpp; + for (i, b) in &mut self.data[start..end].iter_mut().enumerate() { + *b = color[i]; + } } - pub fn get(&self, x: u32, y: u32) -> Option { - todo!() + pub fn get(&self, x: u16, y: u16) -> Option { + if self.data.is_empty() || x >= self.width || y >= self.height { + return None; + } + + let bpp = self.bytes_per_pixel() as usize; + + let mut color = TGAColor::new(); + let start = (x + y * self.width) as usize; + let end = start + bpp; + let data = &self.data[start..end]; + for i in 0..bpp { + color[i] = data[i]; + } + Some(color) } pub fn bytes_per_pixel(&self) -> u8 { @@ -326,10 +351,12 @@ impl TGAImage { }; file.write_all(&mut out)?; - let chunk_end = if raw { run_length * bpp } else { bpp }; + let chunk_end = chunk_start + if raw { run_length * bpp } else { bpp }; file.write_all(&mut self.data[chunk_start..chunk_end])?; } + file.flush()?; + Ok(()) } }