mirror of
https://github.com/italicsjenga/agb.git
synced 2024-12-23 16:21:33 +11:00
disallow multiple video contexts at compile time
This commit is contained in:
parent
195004e8b2
commit
0dc5d620c7
|
@ -12,9 +12,9 @@ struct Vector2D {
|
|||
|
||||
#[start]
|
||||
fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
let gba = gba::Gba::new();
|
||||
let bitmap = gba.display.bitmap3();
|
||||
let vblank = gba.display.get_vblank();
|
||||
let mut gba = gba::Gba::new();
|
||||
let mut bitmap = gba.display.video.bitmap3();
|
||||
let vblank = gba.display.vblank.get();
|
||||
|
||||
let mut input = gba::input::ButtonController::new();
|
||||
let mut pos = Vector2D {
|
||||
|
|
|
@ -7,9 +7,9 @@ use gba::display;
|
|||
|
||||
#[start]
|
||||
fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
let gba = gba::Gba::new();
|
||||
let bitmap = gba.display.bitmap4();
|
||||
let vblank = gba.display.get_vblank();
|
||||
let mut gba = gba::Gba::new();
|
||||
let mut bitmap = gba.display.video.bitmap4();
|
||||
let vblank = gba.display.vblank.get();
|
||||
|
||||
bitmap.set_palette_entry(1, 0x001F);
|
||||
bitmap.set_palette_entry(2, 0x03E0);
|
||||
|
|
87
examples/multiple_video.rs
Normal file
87
examples/multiple_video.rs
Normal file
|
@ -0,0 +1,87 @@
|
|||
#![no_std]
|
||||
#![feature(start)]
|
||||
|
||||
extern crate gba;
|
||||
|
||||
use gba::display;
|
||||
|
||||
struct Vector2D {
|
||||
x: i32,
|
||||
y: i32,
|
||||
}
|
||||
|
||||
#[start]
|
||||
fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
let mut gba = gba::Gba::new();
|
||||
let mut vblank = gba.display.vblank.get();
|
||||
let mut input = gba::input::ButtonController::new();
|
||||
|
||||
loop {
|
||||
bitmap3_mode(&mut gba.display.video.bitmap3(), &mut vblank, &mut input);
|
||||
bitmap4_mode(&mut gba.display.video.bitmap4(), &mut vblank, &mut input);
|
||||
}
|
||||
}
|
||||
|
||||
fn bitmap3_mode(
|
||||
bitmap: &mut display::bitmap3::Bitmap3,
|
||||
vblank: &mut display::VBlank,
|
||||
input: &mut gba::input::ButtonController,
|
||||
) {
|
||||
let mut pos = Vector2D {
|
||||
x: display::WIDTH / 2,
|
||||
y: display::HEIGHT / 2,
|
||||
};
|
||||
|
||||
loop {
|
||||
vblank.wait_for_VBlank();
|
||||
|
||||
input.update();
|
||||
if input.is_just_pressed(gba::input::Button::B) {
|
||||
break;
|
||||
}
|
||||
|
||||
pos.x += input.x_tri() as i32;
|
||||
pos.y += input.y_tri() as i32;
|
||||
|
||||
pos.x = pos.x.clamp(0, display::WIDTH - 1);
|
||||
pos.y = pos.y.clamp(0, display::HEIGHT - 1);
|
||||
bitmap.draw_point(pos.x, pos.y, 0x001F);
|
||||
}
|
||||
}
|
||||
|
||||
fn bitmap4_mode(
|
||||
bitmap: &mut display::bitmap4::Bitmap4,
|
||||
vblank: &mut display::VBlank,
|
||||
input: &mut gba::input::ButtonController,
|
||||
) {
|
||||
bitmap.set_palette_entry(1, 0x001F);
|
||||
bitmap.set_palette_entry(2, 0x03E0);
|
||||
|
||||
bitmap.draw_point_page(
|
||||
display::WIDTH / 2,
|
||||
display::HEIGHT / 2,
|
||||
1,
|
||||
display::bitmap4::Page::Front,
|
||||
);
|
||||
bitmap.draw_point_page(
|
||||
display::WIDTH / 2 + 5,
|
||||
display::HEIGHT / 2,
|
||||
2,
|
||||
display::bitmap4::Page::Back,
|
||||
);
|
||||
|
||||
let mut count = 0;
|
||||
loop {
|
||||
vblank.wait_for_VBlank();
|
||||
|
||||
input.update();
|
||||
if input.is_just_pressed(gba::input::Button::B) {
|
||||
break;
|
||||
}
|
||||
|
||||
count += 1;
|
||||
if count % 6 == 0 {
|
||||
bitmap.flip_page();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -7,9 +7,9 @@ use gba::display;
|
|||
|
||||
#[start]
|
||||
fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
let gba = gba::Gba::new();
|
||||
let bitmap = gba.display.bitmap3();
|
||||
let mut gba = gba::Gba::new();
|
||||
|
||||
let mut bitmap = gba.display.bitmap3();
|
||||
let mut input = gba::input::ButtonController::new();
|
||||
|
||||
loop {
|
||||
|
@ -18,9 +18,5 @@ fn main(_argc: isize, _argv: *const *const u8) -> isize {
|
|||
if input.is_just_pressed(gba::input::Button::A) {
|
||||
bitmap.draw_point(display::WIDTH, 0, 0x05);
|
||||
}
|
||||
// if B is pressed, try take another bitmap
|
||||
if input.is_just_pressed(gba::input::Button::B) {
|
||||
gba.display.bitmap4();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use crate::{memory_mapped::MemoryMapped2DArray, single::SingleToken};
|
||||
use crate::memory_mapped::MemoryMapped2DArray;
|
||||
|
||||
use super::{
|
||||
set_graphics_mode, set_graphics_settings, DisplayMode, GraphicsSettings, HEIGHT, WIDTH,
|
||||
|
@ -9,20 +9,18 @@ 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>,
|
||||
}
|
||||
pub struct Bitmap3 {}
|
||||
|
||||
impl<'a> Bitmap3<'a> {
|
||||
pub(crate) unsafe fn new(in_mode: SingleToken<'a>) -> Self {
|
||||
impl Bitmap3 {
|
||||
pub(crate) unsafe fn new() -> Self {
|
||||
set_graphics_mode(DisplayMode::Bitmap3);
|
||||
set_graphics_settings(GraphicsSettings::LAYER_BG2);
|
||||
Bitmap3 { _in_mode: in_mode }
|
||||
Bitmap3 {}
|
||||
}
|
||||
|
||||
/// Draws point to screen at (x, y) coordinates with colour and panics if
|
||||
/// (x, y) is out of the bounds of the screen.
|
||||
pub fn draw_point(&self, x: i32, y: i32, colour: u16) {
|
||||
pub fn draw_point(&mut 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)
|
||||
|
|
|
@ -1,7 +1,4 @@
|
|||
use crate::{
|
||||
memory_mapped::{MemoryMapped1DArray, MemoryMapped2DArray},
|
||||
single::SingleToken,
|
||||
};
|
||||
use crate::memory_mapped::{MemoryMapped1DArray, MemoryMapped2DArray};
|
||||
|
||||
use super::{
|
||||
set_graphics_mode, set_graphics_settings, DisplayMode, GraphicsSettings, DISPLAY_CONTROL,
|
||||
|
@ -26,21 +23,19 @@ pub enum Page {
|
|||
Back = 1,
|
||||
}
|
||||
|
||||
pub struct Bitmap4<'a> {
|
||||
_in_mode: SingleToken<'a>,
|
||||
}
|
||||
pub struct Bitmap4 {}
|
||||
|
||||
impl<'a> Bitmap4<'a> {
|
||||
pub(crate) unsafe fn new(in_mode: SingleToken<'a>) -> Self {
|
||||
impl Bitmap4 {
|
||||
pub(crate) unsafe fn new() -> Self {
|
||||
set_graphics_mode(DisplayMode::Bitmap4);
|
||||
set_graphics_settings(GraphicsSettings::LAYER_BG2);
|
||||
Bitmap4 { _in_mode: in_mode }
|
||||
Bitmap4 {}
|
||||
}
|
||||
|
||||
/// Draws point on specified page at (x, y) coordinates with colour index
|
||||
/// whose colour is specified in the background palette. Panics if (x, y) is
|
||||
/// out of the bounds of the screen.
|
||||
pub fn draw_point_page(&self, x: i32, y: i32, colour: u8, page: Page) {
|
||||
pub fn draw_point_page(&mut 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,
|
||||
|
@ -60,7 +55,7 @@ impl<'a> Bitmap4<'a> {
|
|||
/// Draws point on the non-current page at (x, y) coordinates with colour
|
||||
/// index whose colour is specified in the background palette. Panics if (x,
|
||||
/// y) is out of the bounds of the screen.
|
||||
pub fn draw_point(&self, x: i32, y: i32, colour: u8) {
|
||||
pub fn draw_point(&mut self, x: i32, y: i32, colour: u8) {
|
||||
let disp = DISPLAY_CONTROL.get();
|
||||
|
||||
// get other page
|
||||
|
@ -74,13 +69,13 @@ impl<'a> Bitmap4<'a> {
|
|||
}
|
||||
|
||||
/// Sets the colour of colour index in the background palette.
|
||||
pub fn set_palette_entry(&self, entry: u32, colour: u16) {
|
||||
pub fn set_palette_entry(&mut self, entry: u32, colour: u16) {
|
||||
PALETTE_BACKGROUND.set(entry as usize, colour);
|
||||
}
|
||||
|
||||
/// Flips page, changing the Gameboy advance to draw the contents of the
|
||||
/// other page
|
||||
pub fn flip_page(&self) {
|
||||
pub fn flip_page(&mut self) {
|
||||
let disp = DISPLAY_CONTROL.get();
|
||||
let swapped = disp ^ GraphicsSettings::PAGE_SELECT.bits();
|
||||
DISPLAY_CONTROL.set(swapped);
|
||||
|
|
|
@ -9,6 +9,7 @@ use bitmap4::Bitmap4;
|
|||
|
||||
pub mod bitmap3;
|
||||
pub mod bitmap4;
|
||||
pub mod tiled0;
|
||||
|
||||
const DISPLAY_CONTROL: MemoryMapped<u16> = unsafe { MemoryMapped::new(0x0400_0000) };
|
||||
const DISPLAY_STATUS: MemoryMapped<u16> = unsafe { MemoryMapped::new(0x0400_0004) };
|
||||
|
@ -45,50 +46,42 @@ enum DisplayMode {
|
|||
Bitmap5 = 5,
|
||||
}
|
||||
|
||||
#[non_exhaustive]
|
||||
/// Manages distribution of display modes, obtained from the gba struct
|
||||
pub struct Display {
|
||||
in_mode: Single,
|
||||
vblank: Single,
|
||||
pub video: Video,
|
||||
pub vblank: VBlankGiver,
|
||||
}
|
||||
#[non_exhaustive]
|
||||
pub struct Video {}
|
||||
|
||||
#[non_exhaustive]
|
||||
pub struct VBlankGiver {}
|
||||
|
||||
impl Video {
|
||||
/// Bitmap mode that provides a 16-bit colour framebuffer
|
||||
pub fn bitmap3(&mut self) -> Bitmap3 {
|
||||
unsafe { Bitmap3::new() }
|
||||
}
|
||||
|
||||
/// Bitmap 4 provides two 8-bit paletted framebuffers with page switching
|
||||
pub fn bitmap4(&mut self) -> Bitmap4 {
|
||||
unsafe { bitmap4::Bitmap4::new() }
|
||||
}
|
||||
}
|
||||
|
||||
impl VBlankGiver {
|
||||
/// Gets a vblank handle where only one can be obtained at a time
|
||||
pub fn get(&mut self) -> VBlank {
|
||||
unsafe { VBlank::new() }
|
||||
}
|
||||
}
|
||||
|
||||
impl Display {
|
||||
pub(crate) const unsafe fn new() -> Self {
|
||||
Display {
|
||||
in_mode: Single::new(),
|
||||
vblank: Single::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Bitmap mode that provides a 16-bit colour framebuffer
|
||||
pub fn bitmap3(&self) -> Bitmap3 {
|
||||
unsafe {
|
||||
Bitmap3::new(
|
||||
self.in_mode
|
||||
.take()
|
||||
.expect("Cannot create new mode as mode already taken"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Bitmap 4 provides two 8-bit paletted framebuffers with page switching
|
||||
pub fn bitmap4(&self) -> Bitmap4 {
|
||||
unsafe {
|
||||
bitmap4::Bitmap4::new(
|
||||
self.in_mode
|
||||
.take()
|
||||
.expect("Cannot create new mode as mode already taken"),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets a vblank handle where only one can be obtained at a time
|
||||
pub fn get_vblank(&self) -> VBlank {
|
||||
unsafe {
|
||||
VBlank::new(
|
||||
self.vblank
|
||||
.take()
|
||||
.expect("Cannot create another vblank handler"),
|
||||
)
|
||||
video: Video {},
|
||||
vblank: VBlankGiver {},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -121,16 +114,14 @@ pub fn busy_wait_for_VBlank() {
|
|||
|
||||
/// Once obtained, this guarentees that interrupts are enabled and set up to
|
||||
/// allow for waiting for vblank
|
||||
pub struct VBlank<'a> {
|
||||
_got: SingleToken<'a>,
|
||||
}
|
||||
pub struct VBlank {}
|
||||
|
||||
impl<'a> VBlank<'a> {
|
||||
unsafe fn new(a: SingleToken<'a>) -> Self {
|
||||
impl VBlank {
|
||||
unsafe fn new() -> Self {
|
||||
crate::interrupt::enable_interrupts();
|
||||
crate::interrupt::enable(crate::interrupt::Interrupt::VBlank);
|
||||
enable_VBlank_interrupt();
|
||||
VBlank { _got: a }
|
||||
VBlank {}
|
||||
}
|
||||
|
||||
#[allow(non_snake_case)]
|
||||
|
@ -141,7 +132,7 @@ impl<'a> VBlank<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> Drop for VBlank<'a> {
|
||||
impl Drop for VBlank {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
disable_VBlank_interrupt();
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use core::cell::Cell;
|
||||
|
||||
pub struct Singleton<T> {
|
||||
single: Option<T>,
|
||||
}
|
||||
|
@ -15,27 +13,25 @@ impl<T> Singleton<T> {
|
|||
}
|
||||
|
||||
pub struct Single {
|
||||
is_taken: Cell<bool>,
|
||||
is_taken: bool,
|
||||
}
|
||||
|
||||
pub struct SingleToken<'a> {
|
||||
cell: &'a Cell<bool>,
|
||||
cell: &'a mut bool,
|
||||
}
|
||||
|
||||
impl Single {
|
||||
pub const fn new() -> Self {
|
||||
Single {
|
||||
is_taken: Cell::new(false),
|
||||
}
|
||||
Single { is_taken: false }
|
||||
}
|
||||
|
||||
pub fn take(&self) -> Result<SingleToken, &'static str> {
|
||||
if self.is_taken.get() {
|
||||
pub fn take(&mut self) -> Result<SingleToken, &'static str> {
|
||||
if self.is_taken {
|
||||
Err("Already taken")
|
||||
} else {
|
||||
self.is_taken.set(true);
|
||||
self.is_taken = true;
|
||||
Ok(SingleToken {
|
||||
cell: &self.is_taken,
|
||||
cell: &mut self.is_taken,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -43,6 +39,6 @@ impl Single {
|
|||
|
||||
impl Drop for SingleToken<'_> {
|
||||
fn drop(&mut self) {
|
||||
self.cell.set(false);
|
||||
(*self.cell) = false;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue