mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 08:11:33 +11:00
move display modes to own file
This commit is contained in:
parent
9b0bdb17e5
commit
cc48605f4a
192
src/display.rs
192
src/display.rs
|
@ -1,192 +0,0 @@
|
|||
use crate::{
|
||||
memory_mapped::{MemoryMapped, MemoryMapped1DArray, MemoryMapped2DArray},
|
||||
single::{Single, SingleToken},
|
||||
};
|
||||
use bitflags::bitflags;
|
||||
use core::convert::TryInto;
|
||||
|
||||
const DISPLAY_CONTROL: MemoryMapped<u16> = unsafe { MemoryMapped::new(0x0400_0000) };
|
||||
const DISPLAY_STATUS: MemoryMapped<u16> = unsafe { MemoryMapped::new(0x0400_0004) };
|
||||
const VCOUNT: MemoryMapped<u16> = unsafe { MemoryMapped::new(0x0400_0006) };
|
||||
|
||||
const PALETTE_BACKGROUND: MemoryMapped1DArray<u16, 256> =
|
||||
unsafe { MemoryMapped1DArray::new(0x0500_0000) };
|
||||
const PALETTE_SPRITE: MemoryMapped1DArray<u16, 256> =
|
||||
unsafe { MemoryMapped1DArray::new(0x0500_0200) };
|
||||
|
||||
const BITMAP_MODE_3: MemoryMapped2DArray<u16, { WIDTH as usize }, { HEIGHT as usize }> =
|
||||
unsafe { MemoryMapped2DArray::new(0x600_0000) };
|
||||
|
||||
const BITMAP_PAGE_FRONT_MODE_4: MemoryMapped2DArray<
|
||||
u16,
|
||||
{ (WIDTH / 2) as usize },
|
||||
{ HEIGHT as usize },
|
||||
> = unsafe { MemoryMapped2DArray::new(0x600_0000) };
|
||||
const BITMAP_PAGE_BACK_MODE_4: MemoryMapped2DArray<
|
||||
u16,
|
||||
{ (WIDTH / 2) as usize },
|
||||
{ HEIGHT as usize },
|
||||
> = unsafe { MemoryMapped2DArray::new(0x600_A000) };
|
||||
|
||||
pub const WIDTH: i32 = 240;
|
||||
pub const HEIGHT: i32 = 160;
|
||||
|
||||
pub enum DisplayMode {
|
||||
Tiled0 = 0,
|
||||
Tiled1 = 1,
|
||||
Tiled2 = 2,
|
||||
Bitmap3 = 3,
|
||||
Bitmap4 = 4,
|
||||
Bitmap5 = 5,
|
||||
}
|
||||
|
||||
pub enum Page {
|
||||
Front = 0,
|
||||
Back = 1,
|
||||
}
|
||||
|
||||
bitflags! {
|
||||
pub struct GraphicsSettings: u16 {
|
||||
const PAGE_SELECT = 1 << 0x4;
|
||||
const OAM_HBLANK = 1 << 0x5;
|
||||
const SPRITE1_D = 1 << 0x6;
|
||||
const SCREEN_BLANK = 1 << 0x7;
|
||||
const LAYER_BG0 = 1 << 0x8;
|
||||
const LAYER_BG1 = 1 << 0x9;
|
||||
const LAYER_BG2 = 1 << 0xA;
|
||||
const LAYER_BG3 = 1 << 0xB;
|
||||
const LAYER_OBJ = 1 << 0xC;
|
||||
const WINDOW0 = 1 << 0xD;
|
||||
const WINDOW1 = 1 << 0xE;
|
||||
const WINDOW_OBJECT = 1 << 0xF;
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Display {
|
||||
in_mode: Single,
|
||||
}
|
||||
|
||||
impl Display {
|
||||
pub(crate) const unsafe fn new() -> Self {
|
||||
Display {
|
||||
in_mode: Single::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bitmap3(&self) -> Bitmap3 {
|
||||
Bitmap3::new(
|
||||
self.in_mode
|
||||
.take()
|
||||
.expect("Cannot create new mode as mode already taken"),
|
||||
)
|
||||
}
|
||||
pub fn bitmap4(&self) -> Bitmap4 {
|
||||
Bitmap4::new(
|
||||
self.in_mode
|
||||
.take()
|
||||
.expect("Cannot create new mode as mode already taken"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Bitmap3<'a> {
|
||||
_in_mode: SingleToken<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Bitmap3<'a> {
|
||||
fn new(in_mode: SingleToken<'a>) -> Self {
|
||||
set_graphics_mode(DisplayMode::Bitmap3);
|
||||
set_graphics_settings(GraphicsSettings::LAYER_BG2);
|
||||
Bitmap3 { _in_mode: in_mode }
|
||||
}
|
||||
pub fn draw_point(&self, x: i32, y: i32, colour: u16) {
|
||||
let x = x.try_into().unwrap();
|
||||
let y = y.try_into().unwrap();
|
||||
BITMAP_MODE_3.set(x, y, colour)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Bitmap4<'a> {
|
||||
_in_mode: SingleToken<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Bitmap4<'a> {
|
||||
fn new(in_mode: SingleToken<'a>) -> Self {
|
||||
set_graphics_mode(DisplayMode::Bitmap4);
|
||||
set_graphics_settings(GraphicsSettings::LAYER_BG2);
|
||||
Bitmap4 { _in_mode: in_mode }
|
||||
}
|
||||
|
||||
pub fn draw_point_page(&self, x: i32, y: i32, colour: u8, page: Page) {
|
||||
let addr = match page {
|
||||
Page::Front => BITMAP_PAGE_FRONT_MODE_4,
|
||||
Page::Back => BITMAP_PAGE_BACK_MODE_4,
|
||||
};
|
||||
|
||||
let x_in_screen = (x / 2) as usize;
|
||||
let y_in_screen = y as usize;
|
||||
|
||||
let c = addr.get(x_in_screen, y_in_screen);
|
||||
if x & 0b1 != 0 {
|
||||
addr.set(x_in_screen, y_in_screen, c | (colour as u16) << 8);
|
||||
} else {
|
||||
addr.set(x_in_screen, y_in_screen, c | colour as u16);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_point(&self, x: i32, y: i32, colour: u8) {
|
||||
let disp = DISPLAY_CONTROL.get();
|
||||
|
||||
let page = if disp & GraphicsSettings::PAGE_SELECT.bits() != 0 {
|
||||
Page::Back
|
||||
} else {
|
||||
Page::Front
|
||||
};
|
||||
|
||||
self.draw_point_page(x, y, colour, page)
|
||||
}
|
||||
|
||||
pub fn set_palette_entry(&self, entry: u32, colour: u16) {
|
||||
PALETTE_BACKGROUND.set(entry as usize, colour);
|
||||
}
|
||||
|
||||
pub fn flip_page(&self) {
|
||||
let disp = DISPLAY_CONTROL.get();
|
||||
let swapped = disp ^ GraphicsSettings::PAGE_SELECT.bits();
|
||||
DISPLAY_CONTROL.set(swapped);
|
||||
}
|
||||
}
|
||||
|
||||
fn set_graphics_mode(mode: DisplayMode) {
|
||||
let current = DISPLAY_CONTROL.get();
|
||||
let current = current & (!0b111);
|
||||
let s = current | (mode as u16 & 0b111);
|
||||
|
||||
DISPLAY_CONTROL.set(s);
|
||||
}
|
||||
|
||||
pub fn set_graphics_settings(settings: GraphicsSettings) {
|
||||
let current = DISPLAY_CONTROL.get();
|
||||
// preserve display mode
|
||||
let current = current & 0b111;
|
||||
let s = settings.bits() | current;
|
||||
|
||||
DISPLAY_CONTROL.set(s);
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn busy_wait_for_VBlank() {
|
||||
while VCOUNT.get() >= 160 {}
|
||||
while VCOUNT.get() < 160 {}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn enable_VBlank_interrupt() {
|
||||
let status = DISPLAY_STATUS.get() | (1 << 3);
|
||||
DISPLAY_STATUS.set(status);
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn wait_for_VBlank() {
|
||||
crate::syscall::wait_for_VBlank();
|
||||
}
|
27
src/display/bitmap3.rs
Normal file
27
src/display/bitmap3.rs
Normal file
|
@ -0,0 +1,27 @@
|
|||
use crate::{memory_mapped::MemoryMapped2DArray, single::SingleToken};
|
||||
|
||||
use super::{
|
||||
set_graphics_mode, set_graphics_settings, DisplayMode, GraphicsSettings, HEIGHT, WIDTH,
|
||||
};
|
||||
|
||||
use core::convert::TryInto;
|
||||
|
||||
const BITMAP_MODE_3: MemoryMapped2DArray<u16, { WIDTH as usize }, { HEIGHT as usize }> =
|
||||
unsafe { MemoryMapped2DArray::new(0x600_0000) };
|
||||
|
||||
pub struct Bitmap3<'a> {
|
||||
_in_mode: SingleToken<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Bitmap3<'a> {
|
||||
pub(crate) fn new(in_mode: SingleToken<'a>) -> Self {
|
||||
set_graphics_mode(DisplayMode::Bitmap3);
|
||||
set_graphics_settings(GraphicsSettings::LAYER_BG2);
|
||||
Bitmap3 { _in_mode: in_mode }
|
||||
}
|
||||
pub fn draw_point(&self, x: i32, y: i32, colour: u16) {
|
||||
let x = x.try_into().unwrap();
|
||||
let y = y.try_into().unwrap();
|
||||
BITMAP_MODE_3.set(x, y, colour)
|
||||
}
|
||||
}
|
78
src/display/bitmap4.rs
Normal file
78
src/display/bitmap4.rs
Normal file
|
@ -0,0 +1,78 @@
|
|||
use crate::{
|
||||
memory_mapped::{MemoryMapped1DArray, MemoryMapped2DArray},
|
||||
single::SingleToken,
|
||||
};
|
||||
|
||||
use super::{
|
||||
set_graphics_mode, set_graphics_settings, DisplayMode, GraphicsSettings, DISPLAY_CONTROL,
|
||||
HEIGHT, WIDTH,
|
||||
};
|
||||
|
||||
const BITMAP_PAGE_FRONT_MODE_4: MemoryMapped2DArray<
|
||||
u16,
|
||||
{ (WIDTH / 2) as usize },
|
||||
{ HEIGHT as usize },
|
||||
> = unsafe { MemoryMapped2DArray::new(0x600_0000) };
|
||||
const BITMAP_PAGE_BACK_MODE_4: MemoryMapped2DArray<
|
||||
u16,
|
||||
{ (WIDTH / 2) as usize },
|
||||
{ HEIGHT as usize },
|
||||
> = unsafe { MemoryMapped2DArray::new(0x600_A000) };
|
||||
const PALETTE_BACKGROUND: MemoryMapped1DArray<u16, 256> =
|
||||
unsafe { MemoryMapped1DArray::new(0x0500_0000) };
|
||||
|
||||
pub enum Page {
|
||||
Front = 0,
|
||||
Back = 1,
|
||||
}
|
||||
|
||||
pub struct Bitmap4<'a> {
|
||||
_in_mode: SingleToken<'a>,
|
||||
}
|
||||
|
||||
impl<'a> Bitmap4<'a> {
|
||||
pub(crate) fn new(in_mode: SingleToken<'a>) -> Self {
|
||||
set_graphics_mode(DisplayMode::Bitmap4);
|
||||
set_graphics_settings(GraphicsSettings::LAYER_BG2);
|
||||
Bitmap4 { _in_mode: in_mode }
|
||||
}
|
||||
|
||||
pub fn draw_point_page(&self, x: i32, y: i32, colour: u8, page: Page) {
|
||||
let addr = match page {
|
||||
Page::Front => BITMAP_PAGE_FRONT_MODE_4,
|
||||
Page::Back => BITMAP_PAGE_BACK_MODE_4,
|
||||
};
|
||||
|
||||
let x_in_screen = (x / 2) as usize;
|
||||
let y_in_screen = y as usize;
|
||||
|
||||
let c = addr.get(x_in_screen, y_in_screen);
|
||||
if x & 0b1 != 0 {
|
||||
addr.set(x_in_screen, y_in_screen, c | (colour as u16) << 8);
|
||||
} else {
|
||||
addr.set(x_in_screen, y_in_screen, c | colour as u16);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn draw_point(&self, x: i32, y: i32, colour: u8) {
|
||||
let disp = DISPLAY_CONTROL.get();
|
||||
|
||||
let page = if disp & GraphicsSettings::PAGE_SELECT.bits() != 0 {
|
||||
Page::Back
|
||||
} else {
|
||||
Page::Front
|
||||
};
|
||||
|
||||
self.draw_point_page(x, y, colour, page)
|
||||
}
|
||||
|
||||
pub fn set_palette_entry(&self, entry: u32, colour: u16) {
|
||||
PALETTE_BACKGROUND.set(entry as usize, colour);
|
||||
}
|
||||
|
||||
pub fn flip_page(&self) {
|
||||
let disp = DISPLAY_CONTROL.get();
|
||||
let swapped = disp ^ GraphicsSettings::PAGE_SELECT.bits();
|
||||
DISPLAY_CONTROL.set(swapped);
|
||||
}
|
||||
}
|
102
src/display/mod.rs
Normal file
102
src/display/mod.rs
Normal file
|
@ -0,0 +1,102 @@
|
|||
use crate::{memory_mapped::MemoryMapped, single::Single};
|
||||
use bitflags::bitflags;
|
||||
|
||||
use bitmap3::Bitmap3;
|
||||
use bitmap4::Bitmap4;
|
||||
|
||||
mod bitmap3;
|
||||
mod bitmap4;
|
||||
|
||||
const DISPLAY_CONTROL: MemoryMapped<u16> = unsafe { MemoryMapped::new(0x0400_0000) };
|
||||
const DISPLAY_STATUS: MemoryMapped<u16> = unsafe { MemoryMapped::new(0x0400_0004) };
|
||||
const VCOUNT: MemoryMapped<u16> = unsafe { MemoryMapped::new(0x0400_0006) };
|
||||
|
||||
bitflags! {
|
||||
pub struct GraphicsSettings: u16 {
|
||||
const PAGE_SELECT = 1 << 0x4;
|
||||
const OAM_HBLANK = 1 << 0x5;
|
||||
const SPRITE1_D = 1 << 0x6;
|
||||
const SCREEN_BLANK = 1 << 0x7;
|
||||
const LAYER_BG0 = 1 << 0x8;
|
||||
const LAYER_BG1 = 1 << 0x9;
|
||||
const LAYER_BG2 = 1 << 0xA;
|
||||
const LAYER_BG3 = 1 << 0xB;
|
||||
const LAYER_OBJ = 1 << 0xC;
|
||||
const WINDOW0 = 1 << 0xD;
|
||||
const WINDOW1 = 1 << 0xE;
|
||||
const WINDOW_OBJECT = 1 << 0xF;
|
||||
}
|
||||
}
|
||||
|
||||
pub const WIDTH: i32 = 240;
|
||||
pub const HEIGHT: i32 = 160;
|
||||
|
||||
pub enum DisplayMode {
|
||||
Tiled0 = 0,
|
||||
Tiled1 = 1,
|
||||
Tiled2 = 2,
|
||||
Bitmap3 = 3,
|
||||
Bitmap4 = 4,
|
||||
Bitmap5 = 5,
|
||||
}
|
||||
|
||||
pub struct Display {
|
||||
in_mode: Single,
|
||||
}
|
||||
|
||||
impl Display {
|
||||
pub(crate) const unsafe fn new() -> Self {
|
||||
Display {
|
||||
in_mode: Single::new(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bitmap3(&self) -> Bitmap3 {
|
||||
Bitmap3::new(
|
||||
self.in_mode
|
||||
.take()
|
||||
.expect("Cannot create new mode as mode already taken"),
|
||||
)
|
||||
}
|
||||
pub fn bitmap4(&self) -> Bitmap4 {
|
||||
bitmap4::Bitmap4::new(
|
||||
self.in_mode
|
||||
.take()
|
||||
.expect("Cannot create new mode as mode already taken"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn set_graphics_mode(mode: DisplayMode) {
|
||||
let current = DISPLAY_CONTROL.get();
|
||||
let current = current & (!0b111);
|
||||
let s = current | (mode as u16 & 0b111);
|
||||
|
||||
DISPLAY_CONTROL.set(s);
|
||||
}
|
||||
|
||||
pub fn set_graphics_settings(settings: GraphicsSettings) {
|
||||
let current = DISPLAY_CONTROL.get();
|
||||
// preserve display mode
|
||||
let current = current & 0b111;
|
||||
let s = settings.bits() | current;
|
||||
|
||||
DISPLAY_CONTROL.set(s);
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn busy_wait_for_VBlank() {
|
||||
while VCOUNT.get() >= 160 {}
|
||||
while VCOUNT.get() < 160 {}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn enable_VBlank_interrupt() {
|
||||
let status = DISPLAY_STATUS.get() | (1 << 3);
|
||||
DISPLAY_STATUS.set(status);
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
pub fn wait_for_VBlank() {
|
||||
crate::syscall::wait_for_VBlank();
|
||||
}
|
Loading…
Reference in a new issue