mindustry logic execution, map- and schematic- parsing and rendering
Diffstat (limited to 'src/utils/image.rs')
| -rw-r--r-- | src/utils/image.rs | 80 |
1 files changed, 62 insertions, 18 deletions
diff --git a/src/utils/image.rs b/src/utils/image.rs index b968dc6..ee1ddea 100644 --- a/src/utils/image.rs +++ b/src/utils/image.rs @@ -1,4 +1,7 @@ use fast_image_resize as fr; +use std::simd::SimdInt; +use std::simd::SimdPartialOrd; +use std::simd::{simd_swizzle, Simd}; use std::{num::NonZeroU32, slice::SliceIndex}; pub trait Overlay<W> { @@ -74,25 +77,66 @@ impl Overlay<Image<&[u8], 3>> for Image<&mut [u8], 3> { } } +pub unsafe fn blit(rgb: &mut [u8], rgba: &[u8]) { + unsafe_assert!(rgba.len() % 4 == 0); + unsafe_assert!(rgba.len() / 4 * 3 == rgb.len()); + const LANES: usize = 16; + + let use_old_last4 = Simd::from_array([ + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, + ]); + + let mut srci = 0; + let mut dsti = 0; + while dsti + 16 <= rgb.len() { + let old: Simd<u8, LANES> = Simd::from_slice(unsafe { rgb.get_unchecked(dsti..dsti + 16) }); + let new: Simd<u8, LANES> = Simd::from_slice(rgba.get_unchecked(srci..srci + 16)); + + let threshold = new.simd_ge(Simd::splat(128)).to_int().cast::<u8>(); + let mut mask = simd_swizzle!( + threshold, + [3, 3, 3, 7, 7, 7, 11, 11, 11, 15, 15, 15, 0, 0, 0, 0] + ); + mask &= use_old_last4; + + let new_rgb = simd_swizzle!(new, [0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 0, 0, 0, 0]); + let blended = (new_rgb & mask) | (old & !mask); + blended.copy_to_slice(rgb.get_unchecked_mut(dsti..dsti + 16)); + + srci += 16; + dsti += 12; + } + + while dsti + 3 <= rgb.len() { + if *rgba.get_unchecked(srci + 3) >= 128 { + std::ptr::copy_nonoverlapping( + rgba.get_unchecked(srci..srci + 3).as_ptr(), + rgb.get_unchecked_mut(dsti..dsti + 3).as_mut_ptr(), + 3, + ); + } + + srci += 4; + dsti += 3; + } +} + impl Overlay<Image<&[u8], 4>> for Image<&mut [u8], 3> { unsafe fn overlay_at(&mut self, with: &Image<&[u8], 4>, x: u32, y: u32) -> &mut Self { + unsafe_assert!(x + with.width() <= self.width()); + unsafe_assert!(y + with.height() <= self.height()); for j in 0..with.height() { - for i in 0..with.width() { - let with_index = really_unsafe_index(i, j, with.width()).unchecked_mul(4); - // solidity - if *with.buffer.get_unchecked(with_index.unchecked_add(3)) > 128 { - let their_px = with - .buffer - .get_unchecked(with_index..with_index.unchecked_add(3)); - let our_index = - really_unsafe_index(i.unchecked_add(x), j.unchecked_add(y), self.width()) - .unchecked_mul(3); - let our_px = self - .buffer - .get_unchecked_mut(our_index..our_index.unchecked_add(3)); - std::ptr::copy_nonoverlapping(their_px.as_ptr(), our_px.as_mut_ptr(), 3); - } - } + let i_x = j as usize * with.width() as usize * 4 + ..(j as usize + 1) * with.width() as usize * 4; + let o_x = ((j as usize + y as usize) * self.width() as usize + x as usize) * 3 + ..((j as usize + y as usize) * self.width() as usize + + x as usize + + with.width() as usize) + * 3; + blit( + self.buffer.get_unchecked_mut(o_x), + with.buffer.get_unchecked(i_x), + ) } self } @@ -106,7 +150,7 @@ impl Overlay<Image<&[u8], 4>> for Image<&mut [u8], 4> { let their_px = with .buffer .get_unchecked(with_index..with_index.unchecked_add(4)); - if *their_px.get_unchecked(3) > 128 { + if *their_px.get_unchecked(3) >= 128 { let our_index = really_unsafe_index(i.unchecked_add(x), j.unchecked_add(y), self.width()) .unchecked_mul(4); @@ -263,7 +307,7 @@ impl ImageUtils for Image<&mut [u8], 4> { unsafe_assert!(self.width() == with.width()); unsafe_assert!(self.height() == with.height()); for (i, other_pixels) in with.chunked().enumerate() { - if other_pixels[3] > 128 { + if other_pixels[3] >= 128 { unsafe { let own_pixels = self .buffer |