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. 48
      ctru-rs/examples/gfx-3d-mode.rs
  2. 56
      ctru-rs/src/gfx.rs

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

@ -1,4 +1,4 @@ @@ -1,4 +1,4 @@
use ctru::gfx::TopScreen3D;
use ctru::gfx::{Screen, Side, TopScreen3D};
use ctru::prelude::*;
/// See `graphics-bitmap.rs` for details on how the image is generated.
@ -16,24 +16,14 @@ fn main() { @@ -16,24 +16,14 @@ fn main() {
let apt = Apt::init().expect("Couldn't obtain APT controller");
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);
// 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();
gfx.top_screen.borrow_mut().set_double_buffering(true);
// We assume the image is the correct size already, so we ignore width + height.
let mut buf = left_buf.ptr;
let top_screen = TopScreen3D::from(&gfx.top_screen);
let (mut left, mut right) = top_screen.split_mut();
// Copy the image into the left-side frame buffer
unsafe {
buf.copy_from(IMAGE.as_ptr(), IMAGE.len());
}
let mut current_side = Side::Left;
// Main loop
while apt.main_loop() {
@ -44,23 +34,31 @@ fn main() { @@ -44,23 +34,31 @@ fn main() {
break;
}
if hid.keys_down().contains(KeyPad::KEY_A) {
// Clear the side we just drew to by zeroing it out
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 {
buf.copy_from(ZERO.as_ptr(), ZERO.len());
left_buf.ptr.copy_from(ZERO.as_ptr(), ZERO.len());
right_buf.ptr.copy_from(ZERO.as_ptr(), ZERO.len());
}
// flip which buffer we're writing to, and redraw the image
buf = if buf == left_buf.ptr {
right_buf.ptr
} else {
left_buf.ptr
if hid.keys_down().contains(KeyPad::KEY_A) {
// flip which buffer we're writing to
current_side = match current_side {
Side::Left => Side::Right,
Side::Right => Side::Left,
};
}
let buf = match current_side {
Side::Left => left_buf.ptr,
Side::Right => right_buf.ptr,
};
unsafe {
buf.copy_from(IMAGE.as_ptr(), IMAGE.len());
}
}
// Flush and swap framebuffers
gfx.flush_buffers();

56
ctru-rs/src/gfx.rs

@ -35,8 +35,17 @@ pub trait Screen: private::Sealed { @@ -35,8 +35,17 @@ pub trait Screen: private::Sealed {
/// Note that the pointer of the framebuffer returned by this function can
/// change after each call to this function if double buffering is enabled.
fn get_raw_framebuffer(&mut self) -> RawFrameBuffer {
let side = self.side();
RawFrameBuffer::for_screen_side(self, side)
let mut width = 0;
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.
@ -58,7 +67,6 @@ pub trait Screen: private::Sealed { @@ -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
/// screen's frame buffer. To enable 3D mode, it can be converted into a [`TopScreen3D`].
pub struct TopScreen {
@ -182,41 +190,19 @@ impl Gfx { @@ -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<'_> {
/// Immutably borrow the left side of the screen.
pub fn left(&self) -> Ref<dyn Screen> {
Ref::map(self.screen.borrow(), |screen| &screen.left)
}
/// 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)
/// Immutably borrow the two sides of the screen as `(left, right)`.
pub fn split(&self) -> (Ref<dyn Screen>, Ref<dyn Screen>) {
Ref::map_split(self.screen.borrow(), |screen| {
(&screen.left as _, &screen.right as _)
})
}
/// Mutably borrow the right side of the screen.
pub fn right_mut(&self) -> RefMut<dyn Screen> {
RefMut::map(self.screen.borrow_mut(), |screen| &mut screen.right)
/// Mutably borrow the two sides of the screen as `(left, right)`.
pub fn split_mut(&self) -> (RefMut<dyn Screen>, RefMut<dyn Screen>) {
RefMut::map_split(self.screen.borrow_mut(), |screen| {
(&mut screen.left as _, &mut screen.right as _)
})
}
}

Loading…
Cancel
Save