mindustry logic execution, map- and schematic- parsing and rendering
Diffstat (limited to 'src/utils/image/affine.rs')
| -rw-r--r-- | src/utils/image/affine.rs | 194 |
1 files changed, 194 insertions, 0 deletions
diff --git a/src/utils/image/affine.rs b/src/utils/image/affine.rs new file mode 100644 index 0000000..04a6180 --- /dev/null +++ b/src/utils/image/affine.rs @@ -0,0 +1,194 @@ +use super::Image; + +/// Rotate a image 180 degrees clockwise. +pub fn rot_180<const CHANNELS: usize>(img: &mut Image<&mut [u8], CHANNELS>) { + for y in 0..img.height() / 2 { + for x in 0..img.width() { + // SAFETY: this is safe because it cannot be out of bounds + unsafe { + let p = img.pixel(x, y); + let x2 = img.width() - x - 1; + let y2 = img.height() - y - 1; + let p2 = img.pixel(x2, y2); + img.set_pixel(x, y, p2); + img.set_pixel(x2, y2, p); + } + } + } + + if img.height() % 2 != 0 { + let middle = img.height() / 2; + + for x in 0..img.width() / 2 { + // SAFETY: this is safe because it cannot be out of bounds + unsafe { + let p = img.pixel(x, middle); + let x2 = img.width() - x - 1; + + let p2 = img.pixel(x2, middle); + img.set_pixel(x, middle, p2); + img.set_pixel(x2, middle, p); + } + } + } +} + +/// # Safety +/// +/// UB if supplied image rectangular +unsafe fn transpose<const CHANNELS: usize>(img: &mut Image<&mut [u8], CHANNELS>) { + debug_assert_eq!(img.width(), img.height()); + let size = img.width(); + for i in 0..size { + for j in i..size { + for c in 0..CHANNELS { + img.buffer.swap_unchecked( + (i * size + j) as usize * CHANNELS + c, + (j * size + i) as usize * CHANNELS + c, + ); + } + } + } +} + +/// Rotate a image 90 degrees clockwise. +/// This is done by first [flipping vertically](flip_v), then [transposing](transpose) the image, to save allocations. +/// +/// # Safety +/// +/// UB if the image is not square +#[inline] +pub unsafe fn rot_90<const CHANNELS: usize>(img: &mut Image<&mut [u8], CHANNELS>) { + flip_v(img); + transpose(img); +} + +/// Rotate a image 270 degrees clockwise, or 90 degrees anti clockwise. +/// [horizontal flip](flip_h), then [transpose]. +/// +/// # Safety +/// +/// UB if the image is not square +#[inline] +pub unsafe fn rot_270<const CHANNELS: usize>(img: &mut Image<&mut [u8], CHANNELS>) { + flip_h(img); + transpose(img); +} + +/// Flip a image vertically. +pub fn flip_v<const CHANNELS: usize>(img: &mut Image<&mut [u8], CHANNELS>) { + for y in 0..img.height() / 2 { + for x in 0..img.width() { + // SAFETY: cant overflow + unsafe { + let y2 = img.height().unchecked_sub(y).unchecked_sub(1); + // SAFETY: within bounds + let p2 = img.pixel(x, y2); + let p = img.pixel(x, y); + img.set_pixel(x, y2, p); + img.set_pixel(x, y, p2); + } + } + } +} + +/// Flip a image horizontally. +pub fn flip_h<const CHANNELS: usize>(img: &mut Image<&mut [u8], CHANNELS>) { + for y in 0..img.height() { + for x in 0..img.width() / 2 { + // SAFETY: This cannot be out of bounds + unsafe { + let x2 = img.width().unchecked_sub(x).unchecked_sub(1); + let p2 = img.pixel(x2, y); + let p = img.pixel(x, y); + img.set_pixel(x2, y, p); + img.set_pixel(x, y, p2); + } + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::utils::image::img; + + #[test] + fn rotate_90() { + let mut from = img![ + [00, 01] + [02, 10] + ]; + unsafe { rot_90(&mut from.as_mut()) }; + assert_eq!( + from, + img![ + [02, 00] + [10, 01] + ] + ); + } + + #[test] + fn rotate_180() { + let mut from = img![ + [00, 01] + [02, 10] + ]; + rot_180(&mut from.as_mut()); + assert_eq!( + from, + img![ + [10, 02] + [01, 00] + ] + ); + } + + #[test] + fn rotate_270() { + let mut from = img![ + [00, 01] + [20, 10] + ]; + unsafe { rot_270(&mut from.as_mut()) }; + assert_eq!( + from, + img![ + [01, 10] + [00, 20] + ] + ); + } + + #[test] + fn flip_vertical() { + let mut from = img![ + [90, 01] + [21, 42] + ]; + flip_v(&mut from.as_mut()); + assert_eq!( + from, + img![ + [21, 42] + [90, 01] + ] + ) + } + #[test] + fn flip_horizontal() { + let mut from = img![ + [90, 01] + [21, 42] + ]; + flip_h(&mut from.as_mut()); + assert_eq!( + from, + img![ + [01, 90] + [42, 21] + ] + ) + } +} |