mindustry logic execution, map- and schematic- parsing and rendering
Diffstat (limited to 'src/utils/image.rs')
-rw-r--r--src/utils/image.rs80
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