use crate::hw::gpu::GP0Command;
pub mod colors;
mod packet;
pub mod primitives;
mod vertex;
pub use packet::{link_list, ordering_table};
type Command = u8;
pub const GPU_BUFFER_SIZE: usize = 64;
#[repr(C)]
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Color {
pub red: u8,
pub green: u8,
pub blue: u8,
}
#[repr(C)]
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct TexColor {
pub red: u8,
pub green: u8,
pub blue: u8,
}
#[derive(Debug, PartialEq, Eq, Clone, Copy)]
pub enum VertexError {
InvalidX,
InvalidY,
}
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct Vertex(pub i16, pub i16);
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct PackedVertex<const N: usize, const X: usize, const Y: usize> {
data: [u8; N],
}
pub type Clut = PackedVertex<2, 6, 9>;
#[allow(missing_docs)]
#[repr(C)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct TexCoord {
pub x: u8,
pub y: u8,
}
pub type TexPage = PackedVertex<2, 4, 1>;
#[derive(Debug)]
pub enum DMAMode {
GP0 = 2,
GPUREAD,
}
#[allow(missing_docs)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum VideoMode {
NTSC = 0,
PAL,
}
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum Depth {
Bits15 = 0,
Bits24,
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub enum Bpp {
Bits4,
Bits8,
Bits15,
}
#[repr(C)]
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct PhysAddr([u8; 3]);
#[repr(C, align(4))]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Packet<T> {
next: PhysAddr,
size: u8,
pub contents: T,
}
pub struct DispEnv {
pub(crate) horizontal_range: PackedVertex<3, 12, 12>,
pub(crate) vertical_range: PackedVertex<3, 10, 10>,
pub(crate) offset: PackedVertex<3, 10, 9>,
}
impl DispEnv {
pub fn new(
offset: (i16, i16), size: (i16, i16), video_mode: VideoMode,
) -> Result<Self, VertexError> {
let offset = Vertex::new(offset);
let offset = PackedVertex::try_from(offset)?;
let (center, range) = if video_mode == VideoMode::NTSC {
(0x88, 240)
} else {
(0xA3, 256)
};
let ntsc_vrange = Vertex(center - (range / 2), center + (range / 2));
let hrange = Vertex(0x260, 0x260 + (320 * 8));
let horizontal_range = PackedVertex::try_from(hrange)?;
let vertical_range = PackedVertex::try_from(ntsc_vrange)?;
Ok(DispEnv {
horizontal_range,
vertical_range,
offset,
})
}
}
#[repr(C)]
#[derive(Debug)]
pub struct DrawEnv {
texpage: u16,
_pad: u8,
texpage_cmd: Command,
upper_left: PackedVertex<3, 10, 9>,
upper_left_cmd: Command,
lower_right: PackedVertex<3, 10, 9>,
lower_right_cmd: Command,
offset: PackedVertex<3, 11, 11>,
offset_cmd: Command,
pub bg_color: Color,
bg_color_cmd: Command,
bg_offset: Vertex,
bg_size: Vertex,
}
impl DrawEnv {
pub fn new(
offset: (i16, i16), size: (i16, i16), bg_color: Option<Color>,
) -> Result<Self, VertexError> {
let offset = Vertex::new(offset);
let size = Vertex::new(size);
let bg_color = bg_color.unwrap_or(colors::BLACK);
let upper_left = PackedVertex::try_from(offset)?;
let lower_right = PackedVertex::try_from(offset + size - Vertex::new((1, 1)))?;
Ok(DrawEnv {
texpage_cmd: 0xE1,
upper_left_cmd: 0xE3,
lower_right_cmd: 0xE4,
offset_cmd: 0xE5,
bg_color_cmd: 0x02,
texpage: (1 << 10) | 10,
upper_left,
lower_right,
offset: PackedVertex::try_from(offset)?,
bg_color,
bg_offset: offset,
bg_size: size,
_pad: 0,
})
}
}
impl GP0Command for DrawEnv {}