Browse Source

Address review comments, improve example

This fixes some glitchy rendering by redrawing everything every frame,
and using double buffering. Also fix double-borrowing issue with split
top screen.
pull/76/head
Ian Chamberlain 2 years ago
parent
commit
e02f7443b1
No known key found for this signature in database
GPG Key ID: AE5484D09405AA60
  1. 56
      ctru-rs/examples/gfx-3d-mode.rs
  2. 56
      ctru-rs/src/gfx.rs

56
ctru-rs/examples/gfx-3d-mode.rs

@ -1,4 +1,4 @@
use ctru::gfx::TopScreen3D; use ctru::gfx::{Screen, Side, TopScreen3D};
use ctru::prelude::*; use ctru::prelude::*;
/// See `graphics-bitmap.rs` for details on how the image is generated. /// See `graphics-bitmap.rs` for details on how the image is generated.
@ -16,24 +16,14 @@ fn main() {
let apt = Apt::init().expect("Couldn't obtain APT controller"); let apt = Apt::init().expect("Couldn't obtain APT controller");
let _console = Console::init(gfx.bottom_screen.borrow_mut()); let _console = Console::init(gfx.bottom_screen.borrow_mut());
println!("Press Start to exit.\nPress A to switch which side is drawn to."); println!("Press Start to exit.\nPress A to switch sides (be sure to have 3D mode enabled).");
let top_screen = TopScreen3D::from(&gfx.top_screen); gfx.top_screen.borrow_mut().set_double_buffering(true);
// TODO set double buffering for top screen
let mut left = top_screen.left_mut();
let left_buf = left.get_raw_framebuffer();
let mut right = top_screen.right_mut();
let right_buf = right.get_raw_framebuffer();
// We assume the image is the correct size already, so we ignore width + height. let top_screen = TopScreen3D::from(&gfx.top_screen);
let mut buf = left_buf.ptr; let (mut left, mut right) = top_screen.split_mut();
// Copy the image into the left-side frame buffer let mut current_side = Side::Left;
unsafe {
buf.copy_from(IMAGE.as_ptr(), IMAGE.len());
}
// Main loop // Main loop
while apt.main_loop() { while apt.main_loop() {
@ -44,22 +34,30 @@ fn main() {
break; break;
} }
let left_buf = left.get_raw_framebuffer();
let right_buf = right.get_raw_framebuffer();
// Clear both buffers every time, in case the user switches sides this loop
unsafe {
left_buf.ptr.copy_from(ZERO.as_ptr(), ZERO.len());
right_buf.ptr.copy_from(ZERO.as_ptr(), ZERO.len());
}
if hid.keys_down().contains(KeyPad::KEY_A) { if hid.keys_down().contains(KeyPad::KEY_A) {
// Clear the side we just drew to by zeroing it out // flip which buffer we're writing to
unsafe { current_side = match current_side {
buf.copy_from(ZERO.as_ptr(), ZERO.len()); Side::Left => Side::Right,
} Side::Right => Side::Left,
// flip which buffer we're writing to, and redraw the image
buf = if buf == left_buf.ptr {
right_buf.ptr
} else {
left_buf.ptr
}; };
}
let buf = match current_side {
Side::Left => left_buf.ptr,
Side::Right => right_buf.ptr,
};
unsafe { unsafe {
buf.copy_from(IMAGE.as_ptr(), IMAGE.len()); buf.copy_from(IMAGE.as_ptr(), IMAGE.len());
}
} }
// Flush and swap framebuffers // Flush and swap framebuffers

56
ctru-rs/src/gfx.rs

@ -35,8 +35,17 @@ pub trait Screen: private::Sealed {
/// Note that the pointer of the framebuffer returned by this function can /// Note that the pointer of the framebuffer returned by this function can
/// change after each call to this function if double buffering is enabled. /// change after each call to this function if double buffering is enabled.
fn get_raw_framebuffer(&mut self) -> RawFrameBuffer { fn get_raw_framebuffer(&mut self) -> RawFrameBuffer {
let side = self.side(); let mut width = 0;
RawFrameBuffer::for_screen_side(self, side) let mut height = 0;
let ptr = unsafe {
ctru_sys::gfxGetFramebuffer(self.as_raw(), self.side().into(), &mut width, &mut height)
};
RawFrameBuffer {
ptr,
width,
height,
screen: PhantomData,
}
} }
/// Sets whether to use double buffering. Enabled by default. /// Sets whether to use double buffering. Enabled by default.
@ -58,7 +67,6 @@ pub trait Screen: private::Sealed {
} }
} }
#[non_exhaustive]
/// The top screen. Mutable access to this struct is required to write to the top /// The top screen. Mutable access to this struct is required to write to the top
/// screen's frame buffer. To enable 3D mode, it can be converted into a [`TopScreen3D`]. /// screen's frame buffer. To enable 3D mode, it can be converted into a [`TopScreen3D`].
pub struct TopScreen { pub struct TopScreen {
@ -182,41 +190,19 @@ impl Gfx {
} }
} }
impl<'screen> RawFrameBuffer<'screen> {
fn for_screen_side(screen: &'screen mut (impl Screen + ?Sized), side: Side) -> Self {
let mut width = 0;
let mut height = 0;
let ptr = unsafe {
ctru_sys::gfxGetFramebuffer(screen.as_raw(), side.into(), &mut width, &mut height)
};
Self {
ptr,
width,
height,
screen: PhantomData,
}
}
}
impl TopScreen3D<'_> { impl TopScreen3D<'_> {
/// Immutably borrow the left side of the screen. /// Immutably borrow the two sides of the screen as `(left, right)`.
pub fn left(&self) -> Ref<dyn Screen> { pub fn split(&self) -> (Ref<dyn Screen>, Ref<dyn Screen>) {
Ref::map(self.screen.borrow(), |screen| &screen.left) Ref::map_split(self.screen.borrow(), |screen| {
} (&screen.left as _, &screen.right as _)
})
/// Mutably borrow the left side of the screen.
pub fn left_mut(&self) -> RefMut<dyn Screen> {
RefMut::map(self.screen.borrow_mut(), |screen| &mut screen.left)
}
/// Immutably borrow the right side of the screen.
pub fn right(&self) -> Ref<dyn Screen> {
Ref::map(self.screen.borrow(), |screen| &screen.right)
} }
/// Mutably borrow the right side of the screen. /// Mutably borrow the two sides of the screen as `(left, right)`.
pub fn right_mut(&self) -> RefMut<dyn Screen> { pub fn split_mut(&self) -> (RefMut<dyn Screen>, RefMut<dyn Screen>) {
RefMut::map(self.screen.borrow_mut(), |screen| &mut screen.right) RefMut::map_split(self.screen.borrow_mut(), |screen| {
(&mut screen.left as _, &mut screen.right as _)
})
} }
} }

Loading…
Cancel
Save