1#![cfg_attr(not(feature = "std"), no_std)]
24#![cfg_attr(not(feature = "std"), feature(core_intrinsics))]
26#![forbid(missing_debug_implementations)]
27#![warn(missing_docs)]
28#[cfg(feature = "std")]
32extern crate core;
33use core::marker::PhantomData;
34use core::mem::swap;
35pub(crate) use core::ops::*;
36
37#[cfg(target_arch = "x86")]
38use core::arch::x86::*;
39#[cfg(target_arch = "x86_64")]
40use core::arch::x86_64::*;
41
42pub(crate) const SSE_LANE_WIDTH: usize = 4;
43pub(crate) const SSE_LANE_WIDTH_I: isize = SSE_LANE_WIDTH as isize;
44
45pub(crate) const AVX_LANE_WIDTH: usize = 8;
46pub(crate) const AVX_LANE_WIDTH_I: isize = AVX_LANE_WIDTH as isize;
47
48#[cfg(not(feature = "std"))]
49pub(crate) fn sqrt(f: f32) -> f32 {
50 unsafe { ::core::intrinsics::sqrtf32(f) }
51}
52#[cfg(feature = "std")]
53pub(crate) fn sqrt(f: f32) -> f32 {
54 f.sqrt()
55}
56
57#[cfg(not(feature = "std"))]
58pub(crate) fn square(f: f32) -> f32 {
59 f * f }
61#[cfg(feature = "std")]
62pub(crate) fn square(f: f32) -> f32 {
63 f.powi(2)
64}
65
66#[macro_use]
67pub mod macros;
68pub use macros::*;
69
70pub mod palettes;
71pub use palettes::*;
72
73pub mod u16_ext;
74pub use u16_ext::*;
75
76pub mod u32_ext;
77pub use u32_ext::*;
78
79pub trait ReadableImage<P>: Index<(usize, usize), Output = P> {
88 fn width(&self) -> usize;
90
91 fn height(&self) -> usize;
93
94 fn pitch(&self) -> isize;
96
97 fn as_ptr(&self) -> *const P;
99
100 fn get(&self, loc: (usize, usize)) -> Option<&P> {
102 if loc.0 < self.width() && loc.1 < self.height() {
103 Some(&self[loc])
104 } else {
105 None
106 }
107 }
108
109 fn slice(&self, r: Range<(usize, usize)>) -> ImageSlice<P> {
132 let r = (r.start.0.min(r.end.0), r.start.1.min(r.end.1))..(r.start.0.max(r.end.0), r.start.1.max(r.end.1));
134 if r.end.0 <= self.width() && r.end.1 <= self.height() && r.start.0 < r.end.0 && r.start.1 < r.end.1 {
135 let width = r.end.0 - r.start.0;
136 let height = r.end.1 - r.start.1;
137 let ptr = unsafe { self.as_ptr().offset(r.start.0 as isize + (r.start.1 as isize * self.pitch())) };
138 let pitch = self.pitch();
139 ImageSlice {
140 width,
141 height,
142 ptr,
143 pitch,
144 _marker: PhantomData,
145 }
146 } else {
147 panic!(
148 "ReadableImage::slice Out Of Bounds: Requested: {:?}, Actual: {:?}",
149 r,
150 (self.width(), self.height())
151 );
152 }
153 }
154
155 fn iter(&self) -> ImageRefIter<P> {
157 ImageRefIter {
159 ptr: self.as_ptr(),
160 next_x: 0,
161 next_y: 0,
162 width: self.width(),
163 height: self.height(),
164 pitch: self.pitch(),
165 _marker: PhantomData,
166 }
167 }
168
169 #[cfg(feature = "std")]
185 fn to_vecimage(&self) -> VecImage<P>
186 where
187 Self: Sized,
188 P: Default + Clone,
189 {
190 let mut output = VecImage::new(self.width(), self.height());
191 for (x, y, r) in self.iter() {
192 output[(x, y)] = (*r).clone();
193 }
194 output
195 }
196
197 #[cfg(feature = "std")]
214 fn upscale(&self, scale: usize) -> VecImage<P>
215 where
216 P: Copy + Default,
217 {
218 let mut output = VecImage::new(self.width() * scale, self.height() * scale);
219 for (x, y, &p) in self.iter() {
220 for y_sub in 0..scale {
221 for x_sub in 0..scale {
222 output[(x * scale + x_sub, y * scale + y_sub)] = p;
223 }
224 }
225 }
226 output
227 }
228
229 }
231
232pub trait WritableImage<P>: ReadableImage<P> + IndexMut<(usize, usize), Output = P> {
234 fn as_mut_ptr(&mut self) -> *mut P;
236
237 fn get_mut(&mut self, loc: (usize, usize)) -> Option<&mut P> {
239 if loc.0 < self.width() && loc.1 < self.height() {
241 Some(&mut self[loc])
242 } else {
243 None
244 }
245 }
246
247 fn slice_mut(&mut self, r: Range<(usize, usize)>) -> ImageMutSlice<P> {
274 let r = (r.start.0.min(r.end.0), r.start.1.min(r.end.1))..(r.start.0.max(r.end.0), r.start.1.max(r.end.1));
276 if r.end.0 <= self.width() && r.end.1 <= self.height() && r.start.0 < r.end.0 && r.start.1 < r.end.1 {
277 let width = r.end.0 - r.start.0;
278 let height = r.end.1 - r.start.1;
279 let ptr = unsafe { self.as_mut_ptr().offset(r.start.0 as isize + (r.start.1 as isize * self.pitch())) };
280 let pitch = self.pitch();
281 ImageMutSlice {
282 width,
283 height,
284 ptr,
285 pitch,
286 _marker: PhantomData,
287 }
288 } else {
289 panic!(
290 "WritableImage::slice_mut Out Of Bounds: Requested: {:?}, Actual: {:?}",
291 r,
292 (self.width(), self.height())
293 );
294 }
295 }
296
297 fn iter_mut(&mut self) -> ImageMutRefIter<P> {
299 ImageMutRefIter {
301 ptr: self.as_mut_ptr(),
302 next_x: 0,
303 next_y: 0,
304 width: self.width(),
305 height: self.height(),
306 pitch: self.pitch(),
307 _marker: PhantomData,
308 }
309 }
310
311 fn set_all(&mut self, pixel: P)
313 where
314 P: Clone,
315 {
316 for (_x, _y, mut_ref) in self.iter_mut() {
318 *mut_ref = pixel.clone();
319 }
320 }
321
322 fn direct_copy<S>(&mut self, src: &S, offset: (isize, isize))
353 where
354 S: ReadableImage<P>,
355 P: Copy,
356 {
357 let offset_x = offset.0;
359 let offset_y = offset.1;
360 let self_width = self.width() as isize;
361 let self_height = self.height() as isize;
362 let src_width = src.width() as isize;
363 let src_height = src.height() as isize;
364 if offset_x < self_width && offset_y < self_height && -offset_x < src_width && -offset_y < src_height {
366 let dest_start_x = (offset_x).max(0);
368 let dest_start_y = (offset_y).max(0);
369 let src_start_x = (-offset_x).max(0);
370 let src_start_y = (-offset_y).max(0);
371 let clip_width = (self_width - dest_start_x).min(src_width - src_start_x);
372 let clip_height = (self_height - dest_start_y).min(src_height - src_start_y);
373 if clip_width > 0 && clip_height > 0 {
374 unsafe {
375 let dest_pitch = self.pitch();
376 let mut dest_ptr = self.as_mut_ptr().offset(dest_start_y * dest_pitch + dest_start_x);
377 let src_pitch = src.pitch();
378 let mut src_ptr = src.as_ptr().offset(src_start_y * src_pitch + src_start_x);
379 let clip_width = clip_width as usize;
380 let clip_height = clip_height as usize;
381 let mut y = 0;
382 while y < clip_height {
383 ::core::ptr::copy_nonoverlapping(src_ptr, dest_ptr, clip_width);
384 src_ptr = src_ptr.offset(src_pitch);
385 dest_ptr = dest_ptr.offset(dest_pitch);
386 y += 1;
387 }
388 }
389 }
390 }
391 }
392
393 fn flip_vertical(&mut self) {
409 unsafe {
410 let swap_count = self.height() / 2;
411 let pitch = self.pitch();
412 let width = self.width();
413 let mut low_ptr = self.as_mut_ptr();
414 let mut high_ptr = self.as_mut_ptr().offset(pitch * (self.height() as isize - 1));
415 let mut y = 0;
416 while y < swap_count {
417 let mut x = 0;
418 let mut low_ptr_row = low_ptr;
419 let mut high_ptr_row = high_ptr;
420 while x < width {
421 swap(&mut *low_ptr_row, &mut *high_ptr_row);
422 low_ptr_row = low_ptr_row.offset(1);
423 high_ptr_row = high_ptr_row.offset(1);
424 x += 1;
425 }
426 y += 1;
427 low_ptr = low_ptr.offset(pitch);
428 high_ptr = high_ptr.offset(-pitch);
429 }
430 }
431 }
432
433 fn flip_horizontal(&mut self) {
449 unsafe {
450 let pitch = self.pitch();
451 let width = self.width();
452 let height = self.height();
453 let mut ptr = self.as_mut_ptr();
454 let mut y = 0;
455 while y < height {
456 ::core::slice::from_raw_parts_mut(ptr, width).reverse();
457 y += 1;
458 ptr = ptr.offset(pitch);
459 }
460 }
461 }
462
463 fn inplace_counterclockwise90_square(&mut self) -> Option<()> {
486 if self.width() == self.height() {
487 unsafe {
488 let base_ptr = self.as_mut_ptr();
489 let n = self.width() as isize;
490 let mut x = 0isize;
491 while x < n / 2 {
492 let mut y = x;
493 while y < n - x - 1 {
494 let a = base_ptr.offset((x) as isize + ((y) as isize * self.pitch())).as_mut().unwrap();
495 let b = base_ptr.offset((y) as isize + ((n - 1 - x) as isize * self.pitch())).as_mut().unwrap();
496 let c = base_ptr
497 .offset((n - 1 - x) as isize + ((n - 1 - y) as isize * self.pitch()))
498 .as_mut()
499 .unwrap();
500 let d = base_ptr.offset((n - 1 - y) as isize + ((x) as isize * self.pitch())).as_mut().unwrap();
501 ::core::mem::swap(a, b);
502 ::core::mem::swap(b, d);
503 ::core::mem::swap(c, b);
504 y += 1;
506 }
507 x += 1
508 }
509 Some(())
510 }
511 } else {
512 None
513 }
514 }
515
516 fn blit_generic<RI, F>(&mut self, src: &RI, offset: (isize, isize), op: F)
544 where
545 RI: ReadableImage<P>,
546 F: FnMut(P, P) -> P,
547 P: Copy,
548 {
549 let mut op = op;
552 let offset_x = offset.0;
553 let offset_y = offset.1;
554 let self_width = self.width() as isize;
555 let self_height = self.height() as isize;
556 let src_width = src.width() as isize;
557 let src_height = src.height() as isize;
558 if offset_x < self_width && offset_y < self_height && -offset_x < src_width && -offset_y < src_height {
560 let dest_start_x = (offset_x).max(0);
562 let dest_start_y = (offset_y).max(0);
563 let src_start_x = (-offset_x).max(0);
564 let src_start_y = (-offset_y).max(0);
565 let clip_width = (self_width - dest_start_x).min(src_width - src_start_x);
566 let clip_height = (self_height - dest_start_y).min(src_height - src_start_y);
567 if clip_width > 0 && clip_height > 0 {
568 unsafe {
569 let dest_pitch = self.pitch();
570 let mut dest_ptr = self.as_mut_ptr().offset(dest_start_y * dest_pitch + dest_start_x);
571 let src_pitch = src.pitch();
572 let mut src_ptr = src.as_ptr().offset(src_start_y * src_pitch + src_start_x);
573 let clip_width = clip_width as usize;
574 let clip_height = clip_height as usize;
575 let mut y = 0;
576 while y < clip_height {
577 let mut x = 0;
578 let mut src_ptr_this_row = src_ptr;
579 let mut dest_ptr_this_row = dest_ptr;
580 while x < clip_width {
581 *dest_ptr_this_row = op(*src_ptr_this_row, *dest_ptr_this_row);
582 src_ptr_this_row = src_ptr_this_row.offset(1);
583 dest_ptr_this_row = dest_ptr_this_row.offset(1);
584 x += 1;
585 }
586 src_ptr = src_ptr.offset(src_pitch);
587 dest_ptr = dest_ptr.offset(dest_pitch);
588 y += 1;
589 }
590 }
591 }
592 }
593 }
594}
595
596#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
602pub struct ImageSlice<'a, P: 'a> {
603 width: usize,
604 height: usize,
605 pitch: isize,
606 ptr: *const P,
607 _marker: PhantomData<&'a P>,
608}
609
610impl<'a, P: 'a> ImageSlice<'a, P> {
611 pub unsafe fn from_raw_parts(width: usize, height: usize, pitch: isize, ptr: *const P) -> Self {
615 ImageSlice {
616 width,
617 height,
618 pitch,
619 ptr,
620 _marker: PhantomData,
621 }
622 }
623
624 }
626
627impl<'a, P: 'a> Index<(usize, usize)> for ImageSlice<'a, P> {
628 type Output = P;
629 fn index(&self, (x, y): (usize, usize)) -> &Self::Output {
631 assert!(x < self.width);
632 assert!(y < self.height);
633 unsafe { self.ptr.offset(x as isize + (y as isize * self.pitch())).as_ref().unwrap() }
634 }
635}
636
637impl<'a, P: 'a> ReadableImage<P> for ImageSlice<'a, P> {
638 fn width(&self) -> usize {
639 self.width
640 }
641 fn height(&self) -> usize {
642 self.height
643 }
644 fn pitch(&self) -> isize {
645 self.pitch
646 }
647 fn as_ptr(&self) -> *const P {
648 self.ptr
649 }
650}
651
652#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
654pub struct ImageMutSlice<'a, P: 'a> {
655 width: usize,
656 height: usize,
657 pitch: isize,
658 ptr: *mut P,
659 _marker: PhantomData<&'a mut P>,
660}
661
662impl<'a, P: 'a> ImageMutSlice<'a, P> {
663 pub unsafe fn from_raw_parts(width: usize, height: usize, pitch: isize, ptr: *mut P) -> Self {
667 ImageMutSlice {
668 width,
669 height,
670 pitch,
671 ptr,
672 _marker: PhantomData,
673 }
674 }
675
676 }
678
679impl<'a, P: 'a> Index<(usize, usize)> for ImageMutSlice<'a, P> {
680 type Output = P;
681 fn index(&self, (x, y): (usize, usize)) -> &Self::Output {
683 assert!(x < self.width);
684 assert!(y < self.height);
685 unsafe { self.ptr.offset(x as isize + (y as isize * self.pitch())).as_ref().unwrap() }
686 }
687}
688
689impl<'a, P: 'a> ReadableImage<P> for ImageMutSlice<'a, P> {
690 fn width(&self) -> usize {
691 self.width
692 }
693 fn height(&self) -> usize {
694 self.height
695 }
696 fn pitch(&self) -> isize {
697 self.pitch
698 }
699 fn as_ptr(&self) -> *const P {
700 self.ptr
701 }
702}
703
704impl<'a, P: 'a> IndexMut<(usize, usize)> for ImageMutSlice<'a, P> {
705 fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut Self::Output {
707 assert!(x < self.width);
708 assert!(y < self.height);
709 unsafe { self.ptr.offset(x as isize + (y as isize * self.pitch())).as_mut().unwrap() }
710 }
711}
712
713impl<'a, P: 'a> WritableImage<P> for ImageMutSlice<'a, P> {
714 fn as_mut_ptr(&mut self) -> *mut P {
715 self.ptr
716 }
717}
718impl<'a> WritableImageU16Ext for ImageMutSlice<'a, u16> {}
719impl<'a> WritableImageU32Ext for ImageMutSlice<'a, u32> {}
720
721#[derive(Debug, PartialEq, Eq, Hash)]
727pub struct ImageRefIter<'a, P: 'a> {
728 ptr: *const P,
729 next_x: usize,
730 next_y: usize,
731 width: usize,
732 height: usize,
733 pitch: isize,
734 _marker: PhantomData<&'a P>,
735}
736
737impl<'a, P: 'a> Iterator for ImageRefIter<'a, P> {
738 type Item = (usize, usize, &'a P);
740
741 fn next(&mut self) -> Option<Self::Item> {
754 if self.next_y < self.height {
755 let out = Some((self.next_x, self.next_y, unsafe { self.ptr.as_ref().unwrap() }));
756 self.ptr = unsafe { self.ptr.offset(1) };
757 self.next_x += 1;
758 if self.next_x == self.width {
759 self.ptr = unsafe { self.ptr.offset(self.pitch - (self.width as isize)) };
760 self.next_x = 0;
761 self.next_y += 1;
762 }
763 out
764 } else {
765 None
766 }
767 }
768
769 fn size_hint(&self) -> (usize, Option<usize>) {
786 let total = self.width * self.height;
787 let used = self.next_y * self.width + self.next_x;
788 let remaining = total.saturating_sub(used);
789 (remaining, Some(remaining))
790 }
791}
792
793impl<'a, P: 'a> IntoIterator for ImageSlice<'a, P> {
794 type Item = (usize, usize, &'a P);
796
797 type IntoIter = ImageRefIter<'a, P>;
798
799 fn into_iter(self) -> Self::IntoIter {
801 ImageRefIter {
802 ptr: self.ptr,
803 next_x: 0,
804 next_y: 0,
805 width: self.width,
806 height: self.height,
807 pitch: self.pitch,
808 _marker: PhantomData,
809 }
810 }
811}
812
813#[derive(Debug, PartialEq, Eq)]
815pub struct ImageMutRefIter<'a, P: 'a> {
816 ptr: *mut P,
817 next_x: usize,
818 next_y: usize,
819 width: usize,
820 height: usize,
821 pitch: isize,
822 _marker: PhantomData<&'a mut P>,
823}
824
825impl<'a, P: 'a> Iterator for ImageMutRefIter<'a, P> {
826 type Item = (usize, usize, &'a mut P);
828
829 fn next(&mut self) -> Option<Self::Item> {
842 if self.next_y < self.height {
843 let out = Some((self.next_x, self.next_y, unsafe { self.ptr.as_mut().unwrap() }));
844 self.ptr = unsafe { self.ptr.offset(1) };
845 self.next_x += 1;
846 if self.next_x == self.width {
847 self.ptr = unsafe { self.ptr.offset(self.pitch - (self.width as isize)) };
848 self.next_x = 0;
849 self.next_y += 1;
850 }
851 out
852 } else {
853 None
854 }
855 }
856
857 fn size_hint(&self) -> (usize, Option<usize>) {
874 let total = self.width * self.height;
875 let used = self.next_y * self.width + self.next_x;
876 let remaining = total.saturating_sub(used);
877 (remaining, Some(remaining))
878 }
879}
880
881impl<'a, P: 'a> IntoIterator for ImageMutSlice<'a, P> {
882 type Item = (usize, usize, &'a mut P);
884
885 type IntoIter = ImageMutRefIter<'a, P>;
886
887 fn into_iter(self) -> Self::IntoIter {
889 ImageMutRefIter {
890 ptr: self.ptr,
891 next_x: 0,
892 next_y: 0,
893 width: self.width,
894 height: self.height,
895 pitch: self.pitch,
896 _marker: PhantomData,
897 }
898 }
899}
900
901#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
909#[cfg(feature = "std")]
910pub struct VecImage<P> {
911 width: usize,
912 height: usize,
913 data: Vec<P>,
914}
915
916#[cfg(feature = "std")]
919impl<P> VecImage<P> {
920 pub fn new(width: usize, height: usize) -> Self
923 where
924 P: Default + Clone,
925 {
926 assert!(width < ::core::isize::MAX as usize);
927 assert!(height < ::core::isize::MAX as usize);
928 VecImage {
929 width,
930 height,
931 data: vec![P::default(); width * height],
932 }
933 }
934
935 pub fn from_vec(width: usize, height: usize, vec: Vec<P>) -> Self {
937 assert!(width < ::core::isize::MAX as usize);
938 assert!(height < ::core::isize::MAX as usize);
939 assert!(width * height == vec.len());
940 VecImage { width, height, data: vec }
941 }
942}
943
944impl<P> Deref for VecImage<P> {
945 type Target = [P];
946
947 fn deref(&self) -> &Self::Target {
948 &self.data
949 }
950}
951
952#[cfg(feature = "std")]
953impl<P> Index<(usize, usize)> for VecImage<P> {
954 type Output = P;
955 fn index(&self, (x, y): (usize, usize)) -> &Self::Output {
957 assert!(x < self.width);
958 assert!(y < self.height);
959 &self.data[x + (y * self.width)]
960 }
961}
962
963#[cfg(feature = "std")]
964impl<P> ReadableImage<P> for VecImage<P> {
965 fn width(&self) -> usize {
966 self.width
967 }
968 fn height(&self) -> usize {
969 self.height
970 }
971 fn pitch(&self) -> isize {
972 self.width as isize
973 }
974 fn as_ptr(&self) -> *const P {
975 self.data.as_ptr()
976 }
977}
978
979#[cfg(feature = "std")]
980impl<P> IndexMut<(usize, usize)> for VecImage<P> {
981 fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut Self::Output {
983 assert!(x < self.width);
984 assert!(y < self.height);
985 &mut self.data[x + (y * self.width)]
986 }
987}
988
989#[cfg(feature = "std")]
990impl<P> WritableImage<P> for VecImage<P> {
991 fn as_mut_ptr(&mut self) -> *mut P {
992 self.data.as_mut_ptr()
993 }
994}
995#[cfg(feature = "std")]
996impl WritableImageU16Ext for VecImage<u16> {}
997#[cfg(feature = "std")]
998impl WritableImageU32Ext for VecImage<u32> {}
999
1000#[derive(Clone)]
1009pub struct NESImage {
1010 data: [u8; NESImage::WIDTH * NESImage::HEIGHT],
1011}
1012impl ::core::fmt::Debug for NESImage {
1013 fn fmt(&self, f: &mut ::core::fmt::Formatter) -> ::core::fmt::Result {
1014 write!(f, "NESImage{{}}")
1015 }
1016}
1017impl NESImage {
1018 const WIDTH: usize = 256;
1019 const HEIGHT: usize = 240;
1020}
1021impl Default for NESImage {
1022 fn default() -> Self {
1023 NESImage {
1024 data: [0; NESImage::WIDTH * NESImage::HEIGHT],
1025 }
1026 }
1027}
1028
1029impl Index<(usize, usize)> for NESImage {
1030 type Output = u8;
1031 fn index(&self, (x, y): (usize, usize)) -> &Self::Output {
1032 assert!(x < NESImage::WIDTH);
1033 assert!(y < NESImage::HEIGHT);
1034 &self.data[x + (y * NESImage::WIDTH)]
1035 }
1036}
1037
1038impl ReadableImage<u8> for NESImage {
1039 fn width(&self) -> usize {
1040 NESImage::WIDTH
1041 }
1042 fn height(&self) -> usize {
1043 NESImage::HEIGHT
1044 }
1045 fn pitch(&self) -> isize {
1046 NESImage::WIDTH as isize
1047 }
1048 fn as_ptr(&self) -> *const u8 {
1049 self.data.as_ptr()
1050 }
1051}
1052
1053impl IndexMut<(usize, usize)> for NESImage {
1054 fn index_mut(&mut self, (x, y): (usize, usize)) -> &mut Self::Output {
1055 assert!(x < NESImage::WIDTH);
1056 assert!(y < NESImage::HEIGHT);
1057 &mut self.data[x + (y * NESImage::WIDTH)]
1058 }
1059}
1060
1061impl WritableImage<u8> for NESImage {
1062 fn as_mut_ptr(&mut self) -> *mut u8 {
1063 self.data.as_mut_ptr()
1064 }
1065}