Browse Source

First attempt at splitting top screen types

pull/76/head
Ian Chamberlain 2 years ago
parent
commit
223ade4543
No known key found for this signature in database
GPG Key ID: AE5484D09405AA60
  1. 5
      ctru-rs/examples/file-explorer.rs
  2. 3
      ctru-rs/examples/hello-world.rs
  3. 118
      ctru-rs/src/gfx.rs

5
ctru-rs/examples/file-explorer.rs

@ -32,8 +32,9 @@ struct FileExplorer<'a> {
impl<'a> FileExplorer<'a> { impl<'a> FileExplorer<'a> {
fn init(apt: &'a Apt, hid: &'a Hid, gfx: &'a Gfx) -> Self { fn init(apt: &'a Apt, hid: &'a Hid, gfx: &'a Gfx) -> Self {
gfx.top_screen.borrow_mut().set_wide_mode(true); let mut top_screen = gfx.top_screen.borrow_mut();
let console = Console::init(gfx.top_screen.borrow_mut()); top_screen.set_wide_mode(true);
let console = Console::init(top_screen);
FileExplorer { FileExplorer {
apt, apt,

3
ctru-rs/examples/hello-world.rs

@ -1,3 +1,4 @@
use ctru::gfx::Side;
use ctru::prelude::*; use ctru::prelude::*;
use std::io::BufWriter; use std::io::BufWriter;
@ -7,7 +8,7 @@ fn main() {
let gfx = Gfx::init().expect("Couldn't obtain GFX controller"); let gfx = Gfx::init().expect("Couldn't obtain GFX controller");
let hid = Hid::init().expect("Couldn't obtain HID controller"); let hid = Hid::init().expect("Couldn't obtain HID controller");
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.top_screen.borrow_mut()); let _console = Console::init(gfx.top_screen.borrow_side_mut(Side::Left));
let out = b"Hello fellow Rustaceans, I'm on the Nintendo 3DS!"; let out = b"Hello fellow Rustaceans, I'm on the Nintendo 3DS!";
let width = 24; let width = 24;

118
ctru-rs/src/gfx.rs

@ -1,7 +1,7 @@
//! LCD screens manipulation helper //! LCD screens manipulation helper
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use std::cell::RefCell; use std::cell::{Ref, RefCell, RefMut};
use std::marker::PhantomData; use std::marker::PhantomData;
use std::sync::Mutex; use std::sync::Mutex;
@ -9,11 +9,19 @@ use crate::error::Result;
use crate::services::gspgpu::{self, FramebufferFormat}; use crate::services::gspgpu::{self, FramebufferFormat};
use crate::services::ServiceReference; use crate::services::ServiceReference;
/// Trait implemented by TopScreen and BottomScreen for common methods /// This trait is implemented by the screen structs for working with frame buffers and
/// drawing to the screens. Graphics-related code can be made generic over this
/// trait to work with any of the given screens.
pub trait Screen { pub trait Screen {
/// Returns the libctru value for the Screen kind /// Returns the libctru value for the Screen kind
fn as_raw(&self) -> ctru_sys::gfxScreen_t; fn as_raw(&self) -> ctru_sys::gfxScreen_t;
/// Returns a [`RawFrameBuffer`] for the screen.
///
/// 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;
/// Sets whether to use double buffering. Enabled by default. /// Sets whether to use double buffering. Enabled by default.
/// ///
/// Note that even when double buffering is disabled, one should still use the `swap_buffers` /// Note that even when double buffering is disabled, one should still use the `swap_buffers`
@ -33,8 +41,23 @@ pub trait Screen {
} }
} }
// TODO: it might be nice to do `TopScreen<const SIDE: Side>` but it requires
// #![feature(adt_const_params)] which is unstable, and doesn't seem worth it
// just for this.
#[non_exhaustive]
pub struct TopLeftScreen;
#[non_exhaustive]
pub struct TopRightScreen;
/// A helper container for both sides of the top screen.
pub struct TopScreenInner {
left: TopLeftScreen,
right: TopRightScreen,
}
#[non_exhaustive] #[non_exhaustive]
pub struct TopScreen; pub struct TopScreen(RefCell<TopScreenInner>);
#[non_exhaustive] #[non_exhaustive]
pub struct BottomScreen; pub struct BottomScreen;
@ -71,7 +94,7 @@ pub enum Side {
/// The service exits when this struct is dropped. /// The service exits when this struct is dropped.
#[non_exhaustive] #[non_exhaustive]
pub struct Gfx { pub struct Gfx {
pub top_screen: RefCell<TopScreen>, pub top_screen: TopScreen,
pub bottom_screen: RefCell<BottomScreen>, pub bottom_screen: RefCell<BottomScreen>,
_service_handler: ServiceReference, _service_handler: ServiceReference,
} }
@ -100,14 +123,15 @@ impl Gfx {
)?; )?;
Ok(Self { Ok(Self {
top_screen: RefCell::new(TopScreen), top_screen: TopScreen::new(TopLeftScreen, TopRightScreen),
bottom_screen: RefCell::new(BottomScreen), bottom_screen: RefCell::new(BottomScreen),
_service_handler, _service_handler,
}) })
} }
/// Creates a new Gfx instance with default init values /// Creates a new [Gfx] instance with default init values
/// It's the same as calling: `Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false) /// It's the same as calling:
/// `Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false)`
pub fn init() -> Result<Self> { pub fn init() -> Result<Self> {
Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false) Gfx::with_formats(FramebufferFormat::Bgr8, FramebufferFormat::Bgr8, false)
} }
@ -140,6 +164,36 @@ impl Gfx {
} }
impl TopScreen { impl TopScreen {
fn new(left: TopLeftScreen, right: TopRightScreen) -> Self {
Self(RefCell::new(TopScreenInner { left, right }))
}
pub fn borrow(&self) -> Ref<'_, TopScreenInner> {
self.0.borrow()
}
pub fn borrow_mut(&self) -> RefMut<'_, TopScreenInner> {
self.0.borrow_mut()
}
pub fn borrow_side(&self, side: Side) -> Ref<'_, dyn Screen> {
let borrow = self.0.borrow();
match side {
Side::Left => Ref::map(borrow, |top| &top.left),
Side::Right => Ref::map(borrow, |top| &top.right),
}
}
pub fn borrow_side_mut(&self, side: Side) -> RefMut<'_, dyn Screen> {
let borrow = self.0.borrow_mut();
match side {
Side::Left => RefMut::map(borrow, |top| &mut top.left),
Side::Right => RefMut::map(borrow, |top| &mut top.right),
}
}
}
impl TopScreenInner {
/// Enable or disable the 3D stereoscopic effect /// Enable or disable the 3D stereoscopic effect
pub fn set_3d_enabled(&mut self, enabled: bool) { pub fn set_3d_enabled(&mut self, enabled: bool) {
unsafe { unsafe {
@ -159,24 +213,6 @@ impl TopScreen {
pub fn get_wide_mode(&self) -> bool { pub fn get_wide_mode(&self) -> bool {
unsafe { ctru_sys::gfxIsWide() } unsafe { ctru_sys::gfxIsWide() }
} }
/// Returns a [`RawFrameBuffer`] for the given [`Side`] of the top screen.
///
/// Note that the pointer of the framebuffer returned by this function can
/// change after each call to this function if double buffering is enabled.
pub fn get_raw_framebuffer(&mut self, side: Side) -> RawFrameBuffer {
RawFrameBuffer::for_screen_side(self, side)
}
}
impl BottomScreen {
/// Returns a [`RawFrameBuffer`] for the bottom screen.
///
/// Note that the pointer of the framebuffer returned by this function can
/// change after each call to this function if double buffering is enabled.
pub fn get_raw_framebuffer(&mut self) -> RawFrameBuffer {
RawFrameBuffer::for_screen_side(self, Side::Left)
}
} }
impl<'screen> RawFrameBuffer<'screen> { impl<'screen> RawFrameBuffer<'screen> {
@ -195,16 +231,46 @@ impl<'screen> RawFrameBuffer<'screen> {
} }
} }
impl Screen for TopScreen { impl Screen for TopScreenInner {
fn as_raw(&self) -> ctru_sys::gfxScreen_t {
self.left.as_raw()
}
fn get_raw_framebuffer(&mut self) -> RawFrameBuffer {
// When dealing with the "whole" top screen, the left framebuffer is the
// one used for writing pixel data.
self.left.get_raw_framebuffer()
}
}
impl Screen for TopLeftScreen {
fn as_raw(&self) -> ctru_sys::gfxScreen_t { fn as_raw(&self) -> ctru_sys::gfxScreen_t {
ctru_sys::GFX_TOP ctru_sys::GFX_TOP
} }
fn get_raw_framebuffer(&mut self) -> RawFrameBuffer {
RawFrameBuffer::for_screen_side(self, Side::Left)
}
}
impl Screen for TopRightScreen {
fn as_raw(&self) -> ctru_sys::gfxScreen_t {
ctru_sys::GFX_TOP
}
fn get_raw_framebuffer(&mut self) -> RawFrameBuffer {
RawFrameBuffer::for_screen_side(self, Side::Right)
}
} }
impl Screen for BottomScreen { impl Screen for BottomScreen {
fn as_raw(&self) -> ctru_sys::gfxScreen_t { fn as_raw(&self) -> ctru_sys::gfxScreen_t {
ctru_sys::GFX_BOTTOM ctru_sys::GFX_BOTTOM
} }
fn get_raw_framebuffer(&mut self) -> RawFrameBuffer {
RawFrameBuffer::for_screen_side(self, Side::Left)
}
} }
impl From<Side> for ctru_sys::gfx3dSide_t { impl From<Side> for ctru_sys::gfx3dSide_t {

Loading…
Cancel
Save