Files
wldash/src/buffer.rs
T

181 lines
5.7 KiB
Rust

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,
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<Buffer, ::std::io::Error> {
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<Buffer, ::std::io::Error> {
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(())
}
}