1use crate::{cloner::ImageCloner, uninit};
4
5use super::{Image, assert_unchecked};
6use crate::pixels::Blend;
7use std::{mem::transmute, simd::prelude::*};
8
9pub trait OverlayAt<W> {
11 unsafe fn overlay_at(&mut self, with: &W, x: u32, y: u32) -> &mut Self;
16}
17
18mod sealed {
20 pub trait Sealed {}
22}
23use sealed::Sealed;
24impl<const N: usize> Sealed for ImageCloner<'_, N> {}
25
26pub trait ClonerOverlayAt<const W: usize, const C: usize>: Sealed {
28 #[must_use = "function does not modify the original image"]
33 unsafe fn overlay_at(&self, with: &Image<&[u8], W>, x: u32, y: u32) -> Image<Vec<u8>, C>;
34}
35
36pub trait Overlay<W> {
39 unsafe fn overlay(&mut self, with: &W) -> &mut Self;
45}
46
47pub trait BlendingOverlay<W> {
49 unsafe fn overlay_blended(&mut self, with: &W) -> &mut Self;
55}
56pub trait BlendingOverlayAt<W> {
58 unsafe fn overlay_blended_at(&mut self, with: &W, x: u32, y: u32) -> &mut Self;
63}
64
65pub trait ClonerOverlay<const W: usize, const C: usize>: Sealed {
67 unsafe fn overlay(&self, with: &Image<&[u8], W>) -> Image<Vec<u8>, C>;
72}
73
74#[inline]
75unsafe fn blit(mut rgb: &mut [u8], mut rgba: &[u8]) {
83 while rgb.len() >= 16 {
84 let dst = rgb.first_chunk_mut::<16>().unwrap();
85 let src = rgba.first_chunk::<16>().unwrap();
86 let old = Simd::from_slice(dst);
87 let new: u8x16 = Simd::from_slice(src);
88
89 let threshold = new.simd_ge(Simd::splat(128)).to_int().cast::<u8>();
90 let mut mask = simd_swizzle!(
91 threshold,
92 [3, 3, 3, 7, 7, 7, 11, 11, 11, 15, 15, 15, 0, 0, 0, 0]
94 );
95 mask &= Simd::from_array([
96 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0,
97 ]);
98 let new_rgb = simd_swizzle!(new, [0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 0, 0, 0, 0]);
100 let blended = (new_rgb & mask) | (old & !mask);
101 blended.copy_to_slice(dst);
102 rgb = &mut rgb[12..];
103 rgba = &rgba[16..];
104 }
105 while rgb.len() >= 3 {
106 if unsafe { *rgba.get_unchecked(3) } >= 128 {
108 rgb[..3].copy_from_slice(&rgba[..3]);
109 }
110 rgba = &rgba[4..];
111 rgb = &mut rgb[3..];
112 }
113}
114
115impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> Overlay<Image<U, 4>> for Image<T, 4> {
116 #[inline]
117 #[cfg_attr(debug_assertions, track_caller)]
118 unsafe fn overlay(&mut self, with: &Image<U, 4>) -> &mut Self {
119 debug_assert!(self.width() == with.width());
120 debug_assert!(self.height() == with.height());
121 for (i, other_pixels) in with.chunked().enumerate() {
122 if other_pixels[3] >= 128 {
123 let own_pixels =
125 unsafe { self.buffer.as_mut().get_unchecked_mut(i * 4..i * 4 + 4) };
126 own_pixels.copy_from_slice(other_pixels);
127 }
128 }
129 self
130 }
131}
132
133impl<const A: usize, const B: usize, T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>>
134 BlendingOverlay<Image<U, B>> for Image<T, A>
135where
136 [u8; A]: Blend<B>,
137{
138 #[inline]
139 #[cfg_attr(debug_assertions, track_caller)]
140 unsafe fn overlay_blended(&mut self, with: &Image<U, B>) -> &mut Self {
141 debug_assert!(self.width() == with.width());
142 debug_assert!(self.height() == with.height());
143 for (other_pixels, own_pixels) in with.chunked().zip(self.chunked_mut()) {
144 own_pixels.blend(*other_pixels);
145 }
146 self
147 }
148}
149
150impl<const A: usize, const B: usize, T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>>
151 BlendingOverlayAt<Image<U, B>> for Image<T, A>
152where
153 [u8; A]: Blend<B>,
154{
155 #[inline]
156 unsafe fn overlay_blended_at(&mut self, with: &Image<U, B>, x: u32, y: u32) -> &mut Self {
157 for j in 0..with.height() {
158 for i in 0..with.width() {
159 let their_px = unsafe { &with.pixel(i, j) };
161 let our_px = unsafe { self.pixel_mut(i + x, j + y) };
162 our_px.blend(*their_px);
163 }
164 }
165 self
166 }
167}
168
169impl<T: AsMut<[u8]> + AsRef<[u8]>> Image<T, 3> {
170 #[doc(hidden)]
171 #[cfg_attr(debug_assertions, track_caller)]
172 pub unsafe fn blend_alpha_and_color_at(
173 &mut self,
174 with: &Image<&[u8], 1>,
175 color: [u8; 3],
176 x: u32,
177 y: u32,
178 ) {
179 for j in 0..with.height() {
180 for i in 0..with.width() {
181 let &[their_alpha] = unsafe { &with.pixel(i, j) };
182 let our_pixel = unsafe { self.pixel_mut(i + x, j + y) };
183 crate::pixels::blending::blend_alpha_and_color(their_alpha, color, our_pixel);
184 }
185 }
186 }
187}
188
189impl ClonerOverlay<4, 4> for ImageCloner<'_, 4> {
190 #[inline]
191 unsafe fn overlay(&self, with: &Image<&[u8], 4>) -> Image<Vec<u8>, 4> {
192 let mut out = self.dup();
193 unsafe { out.as_mut().overlay(with) };
195 out
196 }
197}
198
199impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> OverlayAt<Image<U, 4>> for Image<T, 3> {
200 #[inline]
201 #[cfg_attr(debug_assertions, track_caller)]
202 unsafe fn overlay_at(&mut self, with: &Image<U, 4>, x: u32, y: u32) -> &mut Self {
203 unsafe { assert_unchecked(x + with.width() <= self.width()) };
205 debug_assert!(y + with.height() <= self.height());
206 for j in 0..with.height() {
207 let i_x = j as usize * with.width() as usize * 4
208 ..(j as usize + 1) * with.width() as usize * 4;
209 let o_x = ((j as usize + y as usize) * self.width() as usize + x as usize) * 3
210 ..((j as usize + y as usize) * self.width() as usize
211 + x as usize
212 + with.width() as usize)
213 * 3;
214 let rgb = unsafe { self.buffer.as_mut().get_unchecked_mut(o_x) };
216 let rgba = unsafe { with.buffer.as_ref().get_unchecked(i_x) };
218 unsafe { blit(rgb, rgba) }
220 }
221 self
222 }
223}
224
225impl<U: AsRef<[u8]>> OverlayAt<Image<U, 4>> for uninit::Image<u8, 3> {
226 #[cfg_attr(debug_assertions, track_caller)]
227 unsafe fn overlay_at(&mut self, with: &Image<U, 4>, x: u32, y: u32) -> &mut Self {
228 unsafe { assert_unchecked(x + with.width() <= self.width()) };
230 debug_assert!(y + with.height() <= self.height());
231 for j in 0..with.height() {
232 let i_x = j as usize * with.width() as usize * 4
233 ..(j as usize + 1) * with.width() as usize * 4;
234 let o_x = ((j as usize + y as usize) * self.width() as usize + x as usize) * 3
235 ..((j as usize + y as usize) * self.width() as usize
236 + x as usize
237 + with.width() as usize)
238 * 3;
239 let rgb = unsafe { transmute(self.buf().get_unchecked_mut(o_x)) };
241 let rgba = unsafe { with.buffer.as_ref().get_unchecked(i_x) };
243 unsafe { blit(rgb, rgba) }
245 }
246 self
247 }
248}
249
250impl ClonerOverlayAt<4, 3> for ImageCloner<'_, 3> {
251 #[inline]
252 unsafe fn overlay_at(&self, with: &Image<&[u8], 4>, x: u32, y: u32) -> Image<Vec<u8>, 3> {
253 let mut new = self.dup();
254 unsafe { new.as_mut().overlay_at(with, x, y) };
256 new
257 }
258}
259
260impl<U: AsRef<[u8]>> OverlayAt<Image<U, 3>> for uninit::Image<u8, 3> {
261 #[inline]
262 #[cfg_attr(debug_assertions, track_caller)]
263 unsafe fn overlay_at(&mut self, with: &Image<U, 3>, x: u32, y: u32) -> &mut Self {
264 for j in 0..(with.width() as usize) {
265 let i_x = j * (with.width() as usize) * 3..(j + 1) * (with.width() as usize) * 3;
266 let o_x = ((j + y as usize) * self.width() as usize + x as usize) * 3
267 ..((j + y as usize) * self.width() as usize + x as usize + (with.width() as usize))
268 * 3;
269 debug_assert!(i_x.end <= with.buffer().as_ref().len());
272 let b = unsafe { with.buffer.as_ref().get_unchecked(i_x) };
274 unsafe { self.write(b, o_x) };
276 }
277 self
278 }
279}
280
281impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> OverlayAt<Image<U, 3>> for Image<T, 3> {
282 #[inline]
290 #[cfg_attr(debug_assertions, track_caller)]
291 unsafe fn overlay_at(&mut self, with: &Image<U, 3>, x: u32, y: u32) -> &mut Self {
292 macro_rules! o3x3 {
294 ($n:expr) => {{
295 for j in 0..($n as usize) {
296 let i_x = j * ($n as usize) * 3..(j + 1) * ($n as usize) * 3;
297 let o_x = ((j + y as usize) * self.width() as usize + x as usize) * 3
298 ..((j + y as usize) * self.width() as usize + x as usize + ($n as usize))
299 * 3;
300 debug_assert!(o_x.end <= self.buffer().as_ref().len());
302 debug_assert!(i_x.end <= with.buffer().as_ref().len());
303 let a = unsafe { self.buffer.as_mut().get_unchecked_mut(o_x) };
305 let b = unsafe { with.buffer.as_ref().get_unchecked(i_x) };
307 a.copy_from_slice(b);
308 }
309 }};
310 }
311 match with.width() {
313 8 => o3x3!(8),
314 16 => o3x3!(16), _ => o3x3!(with.width()),
316 }
317 self
318 }
319}
320
321impl ClonerOverlayAt<3, 3> for ImageCloner<'_, 3> {
322 #[inline]
330 unsafe fn overlay_at(&self, with: &Image<&[u8], 3>, x: u32, y: u32) -> Image<Vec<u8>, 3> {
331 let mut out = self.dup();
332 unsafe { out.as_mut().overlay_at(with, x, y) };
334 out
335 }
336}
337
338impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> Overlay<Image<U, 4>> for Image<T, 3> {
339 #[inline]
340 #[cfg_attr(debug_assertions, track_caller)]
341 unsafe fn overlay(&mut self, with: &Image<U, 4>) -> &mut Self {
342 debug_assert!(self.width() == with.width());
343 debug_assert!(self.height() == with.height());
344 for (i, chunk) in with
345 .buffer
346 .as_ref()
347 .chunks_exact(with.width() as usize * 4)
348 .enumerate()
349 {
350 let rgb = unsafe {
352 self.buffer.as_mut().get_unchecked_mut(
353 i * with.width() as usize * 3..(i + 1) * with.width() as usize * 3,
354 )
355 };
356 unsafe { blit(rgb, chunk) };
358 }
359 self
360 }
361}
362
363impl ClonerOverlay<4, 3> for ImageCloner<'_, 3> {
364 #[inline]
365 unsafe fn overlay(&self, with: &Image<&[u8], 4>) -> Image<Vec<u8>, 3> {
366 let mut out = self.dup();
367 unsafe { out.as_mut().overlay(with) };
369 out
370 }
371}
372
373impl<T: AsMut<[u8]> + AsRef<[u8]>, U: AsRef<[u8]>> OverlayAt<Image<U, 4>> for Image<T, 4> {
374 #[inline]
375 unsafe fn overlay_at(&mut self, with: &Image<U, 4>, x: u32, y: u32) -> &mut Self {
376 for j in 0..with.height() {
377 for i in 0..with.width() {
378 let their_px = unsafe { &with.pixel(i, j) };
380 if their_px[3] >= 128 {
381 let our_px = unsafe { self.pixel_mut(i + x, j + y) };
383 our_px.copy_from_slice(their_px);
384 }
385 }
386 }
387
388 self
389 }
390}
391
392impl ClonerOverlayAt<4, 4> for ImageCloner<'_, 4> {
393 #[inline]
394 unsafe fn overlay_at(&self, with: &Image<&[u8], 4>, x: u32, y: u32) -> Image<Vec<u8>, 4> {
395 let mut out = self.dup();
396 unsafe { out.as_mut().overlay_at(with, x, y) };
398 out
399 }
400}