use memmap::MmapMut; use crate::color::Color; pub struct Buffer<'a> { buf: &'a mut MmapMut, dimensions: (u32, u32), subdimensions: Option<(u32, u32, u32, u32)>, } impl<'a> Buffer<'a> { pub fn new(buf: &'a mut MmapMut, dimensions: (u32, u32)) -> Buffer { Buffer { buf: buf, dimensions: dimensions, subdimensions: None, } } pub fn get_bounds(&self) -> (u32, u32, u32, u32) { if let Some(subdim) = self.subdimensions { subdim } else { (0, 0, self.dimensions.0, self.dimensions.1) } } pub fn get_signed_bounds(&self) -> (i32, i32, i32, i32) { if let Some(subdim) = self.subdimensions { ( subdim.0 as i32, subdim.1 as i32, subdim.2 as i32, subdim.3 as i32, ) } else { (0, 0, self.dimensions.0 as i32, self.dimensions.1 as i32) } } pub fn copy_to(&self, other: &mut Buffer, (x, y, width, height): (i32, i32, i32, i32)) { debug_assert!(self.dimensions == other.dimensions); debug_assert!(self.subdimensions.is_none() && other.subdimensions.is_none()); if x == 0 && width as u32 == self.dimensions.0 { // Full-width copy let offset = y as isize * self.dimensions.0 as isize; let n = height as usize * self.dimensions.0 as usize; unsafe { std::ptr::copy( (self.buf.as_ptr() as *const u32).offset(offset), (other.buf.as_mut_ptr() as *mut u32).offset(offset), n, ); } } else { // Row-by-row copy for cur_y in y as isize..(y + height) as isize { let offset = x as isize + cur_y as isize * self.dimensions.0 as isize; unsafe { std::ptr::copy( (self.buf.as_ptr() as *const u32).offset(offset), (other.buf.as_mut_ptr() as *mut u32).offset(offset), width as usize, ); } } } } pub fn subdimensions( &mut self, subdimensions: (u32, u32, u32, u32), ) -> Result { let bounds = self.get_bounds(); if subdimensions.0 + subdimensions.2 >= bounds.2 || subdimensions.1 + subdimensions.3 >= bounds.3 { return Err(::std::io::Error::new( ::std::io::ErrorKind::Other, format!( "cannot create subdimensions larger than buffer: {:?} > {:?}", subdimensions, bounds ), )); } Ok(Buffer { buf: self.buf, dimensions: self.dimensions, subdimensions: Some(( subdimensions.0 + bounds.0, subdimensions.1 + bounds.1, subdimensions.2, subdimensions.3, )), }) } pub fn offset(&mut self, offset: (u32, u32)) -> Result { let bounds = self.get_bounds(); if offset.0 > bounds.2 || offset.1 > bounds.3 { return Err(::std::io::Error::new( ::std::io::ErrorKind::Other, format!( "cannot create offset outside buffer: {:?} > {:?}", offset, bounds ), )); } Ok(Buffer { buf: self.buf, dimensions: self.dimensions, subdimensions: Some(( offset.0 + bounds.0, offset.1 + bounds.1, bounds.2 - offset.0, bounds.3 - offset.1, )), }) } pub fn memset(&mut self, c: &Color) { if let Some(subdim) = self.subdimensions { unsafe { let ptr = self.buf.as_mut_ptr(); for y in subdim.1..(subdim.1 + subdim.3) { for x in subdim.0..(subdim.0 + subdim.2) { *((ptr as *mut u32).offset((x + y * self.dimensions.0) as isize)) = c.as_argb8888(); } } } } else { unsafe { let ptr = self.buf.as_mut_ptr(); for p in 0..(self.dimensions.0 * self.dimensions.1) { *((ptr as *mut u32).offset(p as isize)) = c.as_argb8888(); } } } } pub fn put(&mut self, pos: (u32, u32), c: &Color) -> Result<(), ::std::io::Error> { let true_pos = if let Some(subdim) = self.subdimensions { if pos.0 >= subdim.2 || pos.1 >= subdim.3 { return Err(::std::io::Error::new( ::std::io::ErrorKind::Other, format!( "put({:?}) is not within subdimensions of buffer ({:?})", pos, subdim ), )); } (pos.0 + subdim.0, pos.1 + subdim.1) } else { if pos.0 >= self.dimensions.0 || pos.1 >= self.dimensions.1 { return Err(::std::io::Error::new( ::std::io::ErrorKind::Other, format!( "put({:?}) is not within dimensions of buffer ({:?})", pos, self.dimensions ), )); } pos }; unsafe { let ptr = self .buf .as_mut_ptr() .offset(4 * (true_pos.0 + (true_pos.1 * self.dimensions.0)) as isize); *(ptr as *mut u32) = c.as_argb8888(); }; Ok(()) } }