1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#![cfg(feature = "unsafe_addresses")]

use super::*;

/// A ZST for namespacing VideoMode4 stuff into one place.
///
/// In Mode 5 the majority of VRAM is occupied with two bitmaps, frame 0 and
/// frame 1, which are each somewhat smaller than the full size of the GBA's
/// physical display.
///
/// Each position contains a [`Color`] to display at that location.
///
/// You can access the address of a location by `row` and then `col` or by `x`
/// and then `y`. It will give equivalent results.
///
/// ```rust
/// # use rubidium::*;
/// let p = Mode5.frame(0).row(8).col(5);
/// let q = Mode5.frame(0).x(5).y(8);
/// assert_eq!(p, q);
/// ```
///
/// See Also: [`VideoMode`]
#[derive(Debug, Clone, Copy)]
pub struct Mode5;

impl Mode5 {
  /// In Mode5 each frame is 160 pixels wide.
  pub const WIDTH: usize = 160;

  /// In Mode5 each frame is 128 pixels tall.
  pub const HEIGHT: usize = 128;

  /// Selects frame 0 or frame 1.
  /// ## Panics
  /// If the input is greater than 1.
  #[must_use]
  #[inline(always)]
  pub fn frame(self, frame: usize) -> Mode5Frame {
    assert!(frame < 2);
    let addr = VRAM + 0xA000 * frame;
    Mode5Frame { addr }
  }
}

/// One of the two bitmap frames available in Mode 5.
///
/// See [`Mode5`]
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
#[repr(transparent)]
pub struct Mode5Frame {
  addr: usize,
}

impl Mode5Frame {
  /// Indexes by `row` to get a row out of this frame.
  /// ## Panics
  /// If the index is out of bounds.
  #[must_use]
  #[inline(always)]
  pub fn row(self, row: usize) -> Mode5Row {
    assert!(row < Mode5::HEIGHT);
    let addr = self.addr + (row * Mode5::WIDTH * size_of::<Color>());
    Mode5Row { addr }
  }

  /// Indexes by `x` to get a column out of this frame.
  /// ## Panics
  /// If the index is out of bounds.
  #[must_use]
  #[inline(always)]
  pub fn x(self, x: usize) -> Mode5Col {
    assert!(x < Mode5::WIDTH);
    let addr = self.addr + (x * size_of::<Color>());
    Mode5Col { addr }
  }
}

/// A row within one of the Mode 5 frames.
///
/// See [`Mode5`]
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
#[repr(transparent)]
pub struct Mode5Row {
  addr: usize,
}

impl Mode5Row {
  /// Index by `col` to get a particular pixel in this row.
  /// ## Panics
  /// If the index is out of bounds.
  #[must_use]
  #[inline(always)]
  pub fn col(self, col: usize) -> SimpleVolAddr<Color> {
    assert!(col < Mode5::WIDTH);
    unsafe { SimpleVolAddr::new(self.addr + col * size_of::<Color>()) }
  }
}

/// A column of one of the two Mode 5 bitmaps.
///
/// See [`Mode5`]
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
#[repr(transparent)]
pub struct Mode5Col {
  addr: usize,
}

impl Mode5Col {
  /// Index by `y` to get a particular pixel in this column.
  /// ## Panics
  /// If the index is out of bounds.
  #[must_use]
  #[inline(always)]
  pub fn y(self, y: usize) -> SimpleVolAddr<Color> {
    assert!(y < Mode5::HEIGHT);
    unsafe {
      SimpleVolAddr::new(self.addr + (y * Mode5::WIDTH * size_of::<Color>()))
    }
  }
}