retro_pixel/
lib.rs

1//! This is a library for pushing pixels on the CPU.
2//!
3//! It uses SIMD where possible, so it's pretty fast. Run the benchmarks to
4//! decide if it's fast enough for your use-case. The intent is more for smaller
5//! resolution situations like a retro console would have, but you _can_ do
6//! 1080p if you want. Even _without_ SIMD the indexed color mode at least can
7//! run at basically any resolution you want.
8//!
9//! Note that this library _will not_ put your pixels on the screen itself. You
10//! still have to use a GPU library of some sort to get stuff displayed.
11//! Examples are provided of how you might do that with `glutin` and `gl`, but
12//! you're free to use anything else if you want.
13//!
14//! All of the real work is done via traits, and you can create image slices to
15//! wrap around your existing image data. This allows you to quickly connect the
16//! library onto your existing image types if you need to. If you don't have
17//! existing image types, there is a `VecImage` type provided. There's also an
18//! example of an array-backed type, allowing you to use the library in a
19//! `no_std` situation (requires nightly). In the future, it's hoped that this
20//! library will include feature flags to automatically support other crates,
21//! but not yet.
22
23#![cfg_attr(not(feature = "std"), no_std)]
24// we need this to sqrt without std (alternately, SIMD)
25#![cfg_attr(not(feature = "std"), feature(core_intrinsics))]
26#![forbid(missing_debug_implementations)]
27#![warn(missing_docs)]
28//#![allow(dead_code)]
29//#![allow(unused_imports)]
30
31#[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 // same ASM as `f.powi(2)`, i checked
60}
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
79/// Trait for anything that can be read as if it was an image.
80///
81/// An image is here defined as being a `height` long series of "pixel" slices
82/// (each `width` in length) that are evenly spaced out by a particular `pitch`
83/// value (the offset from the start of one slice to the start of the next
84/// slice). The type of data held in a pixel often doesn't matter, most
85/// operations don't examine the data itself. Things that do examine the data
86/// use "where" bounds so that they are always appropriate to the pixel type.
87pub trait ReadableImage<P>: Index<(usize, usize), Output = P> {
88  /// Can't exceed `isize::MAX`
89  fn width(&self) -> usize;
90
91  /// Can't exceed `isize::MAX`
92  fn height(&self) -> usize;
93
94  /// Offset from the start of one row to the start of the next row.
95  fn pitch(&self) -> isize;
96
97  /// Raw const pointer to the data.
98  fn as_ptr(&self) -> *const P;
99
100  /// Performs an optional indexing by reference, gives `None` for out of bounds.
101  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  /// Grabs out a sub-slice of the data.
110  ///
111  /// # Panics
112  ///
113  /// If either end of the requested portion is out of bounds.
114  ///
115  /// ```rust
116  /// use retro_pixel::*;
117  /// let vi: VecImage<u8> = VecImage::new(10,15);
118  ///
119  /// let whole_slice = vi.slice( (0,0) .. (vi.width(),vi.height()) );
120  /// assert_eq!(whole_slice.width(), vi.width());
121  /// assert_eq!(whole_slice.height(), vi.height());
122  /// assert_eq!(whole_slice.pitch(), vi.pitch());
123  /// assert_eq!(whole_slice.as_ptr(), vi.as_ptr());
124  ///
125  /// let partial_slice = whole_slice.slice( (3,3) .. (7,8) );
126  /// assert_eq!(partial_slice.width(), 4);
127  /// assert_eq!(partial_slice.height(), 5);
128  /// assert_eq!(partial_slice.pitch(), vi.pitch());
129  /// assert_eq!(partial_slice.as_ptr(), unsafe { vi.as_ptr().offset(3 + (3 * vi.pitch())) } );
130  /// ```
131  fn slice(&self, r: Range<(usize, usize)>) -> ImageSlice<P> {
132    // TODO: better explanation in the docs.
133    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  /// Lets you iterate any image by reference.
156  fn iter(&self) -> ImageRefIter<P> {
157    // TODO: split `iter` concept (pixels only) and `enumerate_pixels` (location + pixel)
158    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  /// This is like `to_owned`, you get your own version of the data.
170  ///
171  /// The actual `ToOwned` trait has some conflicts because we're not using
172  /// normal references, so we just have this instead.
173  ///
174  /// ```rust
175  /// use retro_pixel::*;
176  /// let mut source: VecImage<u8> = VecImage::new(5,5);
177  /// let a = source.to_vecimage();
178  /// let b = source.slice((0,0)..(5,5)).to_vecimage();
179  /// let c = source.slice_mut((0,0)..(5,5)).to_vecimage();
180  ///
181  /// assert_eq!(a, b);
182  /// assert_eq!(a, c);
183  /// ```
184  #[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  /// Scales up into a new `VecImage` by the given amount.
198  ///
199  /// ```rust
200  /// use retro_pixel::*;
201  /// let mut source = VecImage::new(2,2);
202  /// source[(0,1)] = 5u8;
203  ///
204  /// let scaled = source.upscale(2);
205  ///
206  /// for (x,y,&p) in scaled.iter() {
207  ///   match (x,y) {
208  ///     (0,2) | (0,3) | (1,2) | (1,3) => assert_eq!(p, 5),
209  ///     _ => assert_eq!(p, 0),
210  ///   }
211  /// }
212  /// ```
213  #[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  // TODO: iter_scanlines
230}
231
232/// The trait for anything that can be written to as if it was an image.
233pub trait WritableImage<P>: ReadableImage<P> + IndexMut<(usize, usize), Output = P> {
234  /// Raw mut pointer to the data.
235  fn as_mut_ptr(&mut self) -> *mut P;
236
237  /// Performs an optional indexing by mut reference, gives `None` for out of bounds.
238  fn get_mut(&mut self, loc: (usize, usize)) -> Option<&mut P> {
239    // TODO: doc-tests
240    if loc.0 < self.width() && loc.1 < self.height() {
241      Some(&mut self[loc])
242    } else {
243      None
244    }
245  }
246
247  /// Grabs out a mutable sub-slice of the data.
248  ///
249  /// # Panics
250  ///
251  /// If either end of the requested portion is out of bounds.
252  ///
253  /// ```rust
254  /// use retro_pixel::*;
255  /// let width = 10;
256  /// let height = 15;
257  /// let mut vi: VecImage<u8> = VecImage::new(width,height);
258  /// let base_ptr = vi.as_ptr();
259  /// let base_pitch = vi.pitch();
260  ///
261  /// let mut whole_slice = vi.slice_mut( (0,0) .. (width,height) );
262  /// assert_eq!(whole_slice.width(), width);
263  /// assert_eq!(whole_slice.height(), height);
264  /// assert_eq!(whole_slice.pitch(), base_pitch);
265  /// assert_eq!(whole_slice.as_ptr(), base_ptr);
266  ///
267  /// let partial_slice = whole_slice.slice_mut( (3,3) .. (7,8) );
268  /// assert_eq!(partial_slice.width(), 4);
269  /// assert_eq!(partial_slice.height(), 5);
270  /// assert_eq!(partial_slice.pitch(), base_pitch);
271  /// assert_eq!(partial_slice.as_ptr(), unsafe { base_ptr.offset(3 + (3 * base_pitch)) } );
272  /// ```
273  fn slice_mut(&mut self, r: Range<(usize, usize)>) -> ImageMutSlice<P> {
274    // TODO: better doc explanations
275    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  /// Lets you mutably iterate over any writable form of image.
298  fn iter_mut(&mut self) -> ImageMutRefIter<P> {
299    // TODO: split `iter_mut` concept from `enumerate_pixels_mut`
300    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  /// Assigns all locations to be the given pixel value.
312  fn set_all(&mut self, pixel: P)
313  where
314    P: Clone,
315  {
316    // TODO: doc-tests
317    for (_x, _y, mut_ref) in self.iter_mut() {
318      *mut_ref = pixel.clone();
319    }
320  }
321
322  /// Directly copies the data from the source image into this image.
323  ///
324  /// The source image is copied in at the offset given. The resulting region is
325  /// automatically clipped to stay within bounds, and you can even specify a
326  /// negative offset if you like.
327  ///
328  /// Because of rust's lifetime rules, and because absolutely no special
329  /// processing happens when moving the data between the two images, this just
330  /// does a byte-wise `copy_nonoverlapping` operation, so it's pretty zippy.
331  ///
332  /// ```rust
333  /// use retro_pixel::*;
334  /// let mut dest = VecImage::new(5,5);
335  /// let mut src = VecImage::new(2,3);
336  /// src.set_all(3u8);
337  /// src[(0,2)] = 5;
338  /// src[(1,2)] = 5;
339  ///
340  /// dest.direct_copy(&src, (1,-1));
341  ///
342  /// for y in 0 .. dest.height() {
343  ///   for x in 0 .. dest.width() {
344  ///     match (x,y) {
345  ///       (1,0) | (2,0) => assert_eq!(dest[(x,y)], 3),
346  ///       (1,1) | (2,1) => assert_eq!(dest[(x,y)], 5),
347  ///       _ => assert_eq!(dest[(x,y)], 0),
348  ///     }
349  ///   }
350  /// }
351  /// ```
352  fn direct_copy<S>(&mut self, src: &S, offset: (isize, isize))
353  where
354    S: ReadableImage<P>,
355    P: Copy,
356  {
357    // TODO: determine_overlay!
358    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    // establish that we should be drawing something at all
365    if offset_x < self_width && offset_y < self_height && -offset_x < src_width && -offset_y < src_height {
366      // determine where we'll be copying
367      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  /// Flips the image vertically.
394  ///
395  /// ```rust
396  /// use retro_pixel::*;
397  /// let mut im = VecImage::new(2,2);
398  /// im[(0,0)] = 5u8;
399  /// im[(1,0)] = 5;
400  ///
401  /// im.flip_vertical();
402  ///
403  /// assert_eq!(im[(0,0)], 0);
404  /// assert_eq!(im[(1,0)], 0);
405  /// assert_eq!(im[(0,1)], 5);
406  /// assert_eq!(im[(1,1)], 5);
407  /// ```
408  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  /// Flips the image horizontally.
434  ///
435  /// ```rust
436  /// use retro_pixel::*;
437  /// let mut im = VecImage::new(2,2);
438  /// im[(0,0)] = 5u8;
439  /// im[(0,1)] = 5;
440  ///
441  /// im.flip_horizontal();
442  ///
443  /// assert_eq!(im[(0,0)], 0);
444  /// assert_eq!(im[(1,0)], 5);
445  /// assert_eq!(im[(0,1)], 0);
446  /// assert_eq!(im[(1,1)], 5);
447  /// ```
448  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  /// Performs a 90 degrees counter-clockwise rotation, in place.
464  ///
465  /// # Failure
466  ///
467  /// The method simply fails with a `None` return if the image isn't square.
468  ///
469  /// ```rust
470  /// use retro_pixel::*;
471  /// let mut im = VecImage::new(3,3);
472  /// im[(0,0)] = 5u8;
473  /// im[(2,0)] = 6;
474  /// im[(2,2)] = 7;
475  /// im[(0,2)] = 8;
476  ///
477  /// assert!(im.inplace_counterclockwise90_square().is_some());
478  /// assert_eq!(im[(0,0)], 8);
479  /// assert_eq!(im[(2,0)], 5);
480  /// assert_eq!(im[(2,2)], 6);
481  /// assert_eq!(im[(0,2)], 7);
482  ///
483  /// assert!(im.slice_mut((0,0)..(3,2)).inplace_counterclockwise90_square().is_none());
484  /// ```
485  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            //
505            y += 1;
506          }
507          x += 1
508        }
509        Some(())
510      }
511    } else {
512      None
513    }
514  }
515
516  /// Modifies this image by overlaying the source image at the offset given.
517  ///
518  /// For each pixel of overlap between `src` and `dest`, the closure is called
519  /// with `|src, dest|` as parameters, and the closure should return the result
520  /// to write as the new value for `dest`.
521  ///
522  /// ```rust
523  /// use retro_pixel::*;
524  /// let mut dest = VecImage::new(5,5);
525  /// let mut src = VecImage::new(2,3);
526  /// dest.set_all(1u8);
527  /// src.set_all(3u8);
528  /// src[(0,2)] = 5;
529  /// src[(1,2)] = 5;
530  ///
531  /// dest.blit_generic(&src, (1,-1), |src,dest| src+dest );
532  ///
533  /// for y in 0 .. dest.height() {
534  ///   for x in 0 .. dest.width() {
535  ///     match (x,y) {
536  ///       (1,0) | (2,0) => assert_eq!(dest[(x,y)], 4),
537  ///       (1,1) | (2,1) => assert_eq!(dest[(x,y)], 6),
538  ///       _ => assert_eq!(dest[(x,y)], 1),
539  ///     }
540  ///   }
541  /// }
542  /// ```
543  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    // TODO: make this use the `determine_overlay!` macro.
550    // TODO: try and think about if we can relax the bounds on `P`
551    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    // establish that we should be drawing something at all
559    if offset_x < self_width && offset_y < self_height && -offset_x < src_width && -offset_y < src_height {
560      // determine where we'll be copying
561      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// // // // //
597// Slice Types
598// // // // //
599
600/// A shared view of some image data.
601#[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  /// Makes an image slice from the base parts.
612  ///
613  /// Absolutely no checks are performed, you must not lie to this method.
614  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  // TODO: From Slice
625}
626
627impl<'a, P: 'a> Index<(usize, usize)> for ImageSlice<'a, P> {
628  type Output = P;
629  // TODO: doc-tests
630  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/// A mutable sub-view of some image data.
653#[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  /// Makes a mutable image slice from the base parts.
664  ///
665  /// Absolutely no checks are performed, you must not lie to this method.
666  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  // TODO: From Mut Slice
677}
678
679impl<'a, P: 'a> Index<(usize, usize)> for ImageMutSlice<'a, P> {
680  type Output = P;
681  // TODO: doc-tests
682  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  // TODO: doc-tests
706  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// // // // //
722// Iterators
723// // // // //
724
725/// A struct that iterates over pixels of an `Image` by reference.
726#[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  /// (x, y, pixel_ref)
739  type Item = (usize, usize, &'a P);
740
741  /// Provides the output, once `None` is seen you'll never see more output.
742  ///
743  /// ```rust
744  /// use retro_pixel::*;
745  /// let image = VecImage::from_vec(2,2,vec![1,2,3,4]);
746  /// let mut iter = image.iter();
747  /// assert_eq!(iter.next(), Some((0,0,&1)));
748  /// assert_eq!(iter.next(), Some((1,0,&2)));
749  /// assert_eq!(iter.next(), Some((0,1,&3)));
750  /// assert_eq!(iter.next(), Some((1,1,&4)));
751  /// assert!(iter.next().is_none());
752  /// ```
753  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  /// Provides an accurate count of the remaining iterations.
770  ///
771  /// ```rust
772  /// use retro_pixel::*;
773  /// let image: VecImage<u8> = VecImage::new(2, 2);
774  /// let mut iter = image.iter();
775  /// assert_eq!(iter.size_hint(), (4,Some(4)));
776  /// iter.next();
777  /// assert_eq!(iter.size_hint(), (3,Some(3)));
778  /// iter.next();
779  /// assert_eq!(iter.size_hint(), (2,Some(2)));
780  /// iter.next();
781  /// assert_eq!(iter.size_hint(), (1,Some(1)));
782  /// iter.next();
783  /// assert_eq!(iter.size_hint(), (0,Some(0)));
784  /// ```
785  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  /// (x, y, pixel_ref)
795  type Item = (usize, usize, &'a P);
796
797  type IntoIter = ImageRefIter<'a, P>;
798
799  // TODO: doc-tests
800  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/// A struct that iterates over pixels of an `Image` by mutable reference.
814#[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  /// (x, y, pixel_mut_ref)
827  type Item = (usize, usize, &'a mut P);
828
829  /// Provides the output, once `None` is seen you'll never see more output.
830  ///
831  /// ```rust
832  /// use retro_pixel::*;
833  /// let mut image = VecImage::from_vec(2,2,vec![1,2,3,4]);
834  /// let mut iter_mut = image.iter_mut();
835  /// assert_eq!(iter_mut.next(), Some((0,0,&mut 1)));
836  /// assert_eq!(iter_mut.next(), Some((1,0,&mut 2)));
837  /// assert_eq!(iter_mut.next(), Some((0,1,&mut 3)));
838  /// assert_eq!(iter_mut.next(), Some((1,1,&mut 4)));
839  /// assert!(iter_mut.next().is_none());
840  /// ```
841  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  /// Provides an accurate count of the remaining iterations.
858  ///
859  /// ```rust
860  /// use retro_pixel::*;
861  /// let mut image: VecImage<u8> = VecImage::new(2, 2);
862  /// let mut iter_mut = image.iter_mut();
863  /// assert_eq!(iter_mut.size_hint(), (4,Some(4)));
864  /// iter_mut.next();
865  /// assert_eq!(iter_mut.size_hint(), (3,Some(3)));
866  /// iter_mut.next();
867  /// assert_eq!(iter_mut.size_hint(), (2,Some(2)));
868  /// iter_mut.next();
869  /// assert_eq!(iter_mut.size_hint(), (1,Some(1)));
870  /// iter_mut.next();
871  /// assert_eq!(iter_mut.size_hint(), (0,Some(0)));
872  /// ```
873  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  /// (x, y, pixel_mut_ref)
883  type Item = (usize, usize, &'a mut P);
884
885  type IntoIter = ImageMutRefIter<'a, P>;
886
887  // TODO: doc-tests
888  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// // // // //
902// Vector Images
903// // // // //
904
905/// An image backed by a `Vec`.
906///
907/// Not available in `no_std`, obviously.
908#[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// TODO: IntoIterator
917
918#[cfg(feature = "std")]
919impl<P> VecImage<P> {
920  /// Creates a VecImage of the given dimensions with the default value in all
921  /// positions.
922  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  /// Creates a VecImage from the given vector of pixels.
936  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  // TODO: doc-tests
956  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  // TODO: doc-tests
982  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// // // // //
1001// Array Images
1002// // // // //
1003
1004/// An image the size of an NES screen, backed by an array.
1005///
1006/// This is a fairly big thing to have on the stack (~61k), so go easy with it,
1007/// or stick it in a global somewhere.
1008#[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}