|
|
@ -11,19 +11,39 @@ use crate::services::gspgpu::{self, FramebufferFormat}; |
|
|
|
///
|
|
|
|
///
|
|
|
|
/// The service exits when this struct is dropped.
|
|
|
|
/// The service exits when this struct is dropped.
|
|
|
|
pub struct Gfx { |
|
|
|
pub struct Gfx { |
|
|
|
top_screen: RefCell<Screen>, |
|
|
|
top_screen: RefCell<TopScreen>, |
|
|
|
bottom_screen: RefCell<Screen>, |
|
|
|
bottom_screen: RefCell<BottomScreen>, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Available screens on the 3DS
|
|
|
|
/// Trait implemented by TopScreen and BottomScreen for common methods
|
|
|
|
#[derive(Copy, Clone, Debug)] |
|
|
|
pub trait Screen { |
|
|
|
pub enum Screen { |
|
|
|
/// Returns the libctru value for the Screen kind
|
|
|
|
/// The top screen
|
|
|
|
fn into_raw(&self) -> ctru_sys::gfxScreen_t; |
|
|
|
Top, |
|
|
|
|
|
|
|
/// The bottom screen
|
|
|
|
/// Sets whether to use double buffering. Enabled by default.
|
|
|
|
Bottom, |
|
|
|
///
|
|
|
|
|
|
|
|
/// Note that even when double buffering is disabled, one should still use the `swap_buffers`
|
|
|
|
|
|
|
|
/// method on each frame to keep the gsp configuration up to date
|
|
|
|
|
|
|
|
fn set_double_buffering(&mut self, enabled: bool); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Gets the framebuffer format
|
|
|
|
|
|
|
|
fn get_framebuffer_format(&self) -> FramebufferFormat; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Change the framebuffer format
|
|
|
|
|
|
|
|
fn set_framebuffer_format(&mut self, fmt: FramebufferFormat); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Returns a tuple containing a pointer to the specifified framebuffer (as determined by the
|
|
|
|
|
|
|
|
/// calling screen and `Side`), the width of the framebuffer in pixels, and the height of
|
|
|
|
|
|
|
|
/// the framebuffer in pixels
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// Note that the pointer returned by this function can change after each call to this function
|
|
|
|
|
|
|
|
/// if double buffering is enabled
|
|
|
|
|
|
|
|
fn get_raw_framebuffer(&self, side: Side) -> (*mut u8, u16, u16); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
pub struct TopScreen; |
|
|
|
|
|
|
|
pub struct BottomScreen; |
|
|
|
|
|
|
|
|
|
|
|
#[derive(Copy, Clone, Debug)] |
|
|
|
#[derive(Copy, Clone, Debug)] |
|
|
|
/// Side of top screen framebuffer
|
|
|
|
/// Side of top screen framebuffer
|
|
|
|
///
|
|
|
|
///
|
|
|
@ -49,28 +69,28 @@ impl Gfx { |
|
|
|
ctru_sys::gfxInit(top_fb_fmt.into(), bottom_fb_fmt.into(), use_vram_buffers); |
|
|
|
ctru_sys::gfxInit(top_fb_fmt.into(), bottom_fb_fmt.into(), use_vram_buffers); |
|
|
|
} |
|
|
|
} |
|
|
|
Gfx { |
|
|
|
Gfx { |
|
|
|
top_screen: RefCell::new(Screen::Top), |
|
|
|
top_screen: RefCell::new(TopScreen), |
|
|
|
bottom_screen: RefCell::new(Screen::Bottom), |
|
|
|
bottom_screen: RefCell::new(BottomScreen), |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Try to get an immutable reference to the Top screen
|
|
|
|
/// Try to get an immutable reference to the Top screen
|
|
|
|
pub fn get_top_screen(&self) -> Result<Ref<'_, Screen>, BorrowError> { |
|
|
|
pub fn get_top_screen(&self) -> Result<Ref<'_, TopScreen>, BorrowError> { |
|
|
|
self.top_screen.try_borrow() |
|
|
|
self.top_screen.try_borrow() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Try to get a mutable reference to the Top screen
|
|
|
|
/// Try to get a mutable reference to the Top screen
|
|
|
|
pub fn get_top_screen_mut(&self) -> Result<RefMut<'_, Screen>, BorrowMutError> { |
|
|
|
pub fn get_top_screen_mut(&self) -> Result<RefMut<'_, TopScreen>, BorrowMutError> { |
|
|
|
self.top_screen.try_borrow_mut() |
|
|
|
self.top_screen.try_borrow_mut() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Try to get an immutable reference to the Bottom screen
|
|
|
|
/// Try to get an immutable reference to the Bottom screen
|
|
|
|
pub fn get_bottom_screen(&self) -> Result<Ref<'_, Screen>, BorrowError> { |
|
|
|
pub fn get_bottom_screen(&self) -> Result<Ref<'_, BottomScreen>, BorrowError> { |
|
|
|
self.bottom_screen.try_borrow() |
|
|
|
self.bottom_screen.try_borrow() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Try to get a mutable reference to the Bottom screen
|
|
|
|
/// Try to get a mutable reference to the Bottom screen
|
|
|
|
pub fn get_bottom_screen_mut(&self) -> Result<RefMut<'_, Screen>, BorrowMutError> { |
|
|
|
pub fn get_bottom_screen_mut(&self) -> Result<RefMut<'_, BottomScreen>, BorrowMutError> { |
|
|
|
self.bottom_screen.try_borrow_mut() |
|
|
|
self.bottom_screen.try_borrow_mut() |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -101,88 +121,88 @@ impl Gfx { |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl Screen { |
|
|
|
impl TopScreen { |
|
|
|
/// Enable or disable the 3D stereoscopic effect
|
|
|
|
/// Enable or disable the 3D stereoscopic effect
|
|
|
|
///
|
|
|
|
pub fn set_3d_enabled(&mut self, enabled: bool) { |
|
|
|
/// #Errors
|
|
|
|
unsafe { |
|
|
|
/// When called by the Bottom screen
|
|
|
|
|
|
|
|
pub fn set_3d_enabled(&mut self, enabled: bool) -> Result<(), String> { |
|
|
|
|
|
|
|
match self { |
|
|
|
|
|
|
|
Screen::Top => unsafe { |
|
|
|
|
|
|
|
ctru_sys::gfxSet3D(enabled); |
|
|
|
ctru_sys::gfxSet3D(enabled); |
|
|
|
Ok(()) |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
Screen::Bottom => Err("Tried to enable 3D on bottom screen".to_string()), |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Enable or disable the wide screen mode (top screen).
|
|
|
|
/// Enable or disable the wide screen mode (top screen).
|
|
|
|
/// This only works when 3D is disabled.
|
|
|
|
/// This only works when 3D is disabled.
|
|
|
|
///
|
|
|
|
pub fn set_wide_mode(&mut self, enabled: bool) { |
|
|
|
/// #Errors
|
|
|
|
unsafe { |
|
|
|
/// When called by the Bottom screen
|
|
|
|
|
|
|
|
pub fn set_wide_mode(&mut self, enabled: bool) -> Result<(), String> { |
|
|
|
|
|
|
|
match self { |
|
|
|
|
|
|
|
Screen::Top => unsafe { |
|
|
|
|
|
|
|
ctru_sys::gfxSetWide(enabled); |
|
|
|
ctru_sys::gfxSetWide(enabled); |
|
|
|
Ok(()) |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
Screen::Bottom => Err("Tried to change wide-mode on bottom screen".to_string()), |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Get the status of wide screen mode.
|
|
|
|
/// Get the status of wide screen mode.
|
|
|
|
///
|
|
|
|
pub fn get_wide_mode(&self) -> bool { |
|
|
|
/// #Errors
|
|
|
|
unsafe { ctru_sys::gfxIsWide() } |
|
|
|
/// When called by the Bottom screen
|
|
|
|
|
|
|
|
pub fn get_wide_mode(&self) -> Result<bool, String> { |
|
|
|
|
|
|
|
match self { |
|
|
|
|
|
|
|
Screen::Top => unsafe { Ok(ctru_sys::gfxIsWide()) }, |
|
|
|
|
|
|
|
Screen::Bottom => Err("Tried to check wide-mode status on bottom screen".to_string()), |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Sets whether to use double buffering. Enabled by default.
|
|
|
|
impl Screen for TopScreen { |
|
|
|
///
|
|
|
|
fn into_raw(&self) -> ctru_sys::gfxScreen_t { |
|
|
|
/// Note that even when double buffering is disabled, one should still use the `swap_buffers`
|
|
|
|
ctru_sys::GFX_TOP |
|
|
|
/// method on each frame to keep the gsp configuration up to date
|
|
|
|
|
|
|
|
pub fn set_double_buffering(&mut self, screen: Screen, enabled: bool) { |
|
|
|
|
|
|
|
unsafe { ctru_sys::gfxSetDoubleBuffering(screen.into(), enabled) } |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Gets the framebuffer format
|
|
|
|
fn set_double_buffering(&mut self, enabled: bool) { |
|
|
|
pub fn get_framebuffer_format(&self, screen: Screen) -> FramebufferFormat { |
|
|
|
unsafe { ctru_sys::gfxSetDoubleBuffering(ctru_sys::GFX_TOP, enabled) } |
|
|
|
unsafe { ctru_sys::gfxGetScreenFormat(screen.into()).into() } |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Change the framebuffer format
|
|
|
|
fn get_framebuffer_format(&self) -> FramebufferFormat { |
|
|
|
pub fn set_framebuffer_format(&mut self, screen: Screen, fmt: FramebufferFormat) { |
|
|
|
unsafe { ctru_sys::gfxGetScreenFormat(ctru_sys::GFX_TOP).into() } |
|
|
|
unsafe { ctru_sys::gfxSetScreenFormat(screen.into(), fmt.into()) } |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Returns a tuple containing a pointer to the specifified framebuffer (as determined by the
|
|
|
|
fn set_framebuffer_format(&mut self, fmt: FramebufferFormat) { |
|
|
|
/// provided `Screen` and `Side`), the width of the framebuffer in pixels, and the height of
|
|
|
|
unsafe { ctru_sys::gfxSetScreenFormat(ctru_sys::GFX_TOP, fmt.into()) } |
|
|
|
/// the framebuffer in pixels
|
|
|
|
} |
|
|
|
///
|
|
|
|
|
|
|
|
/// Note that the pointer returned by this function can change after each call to this function
|
|
|
|
fn get_raw_framebuffer(&self, side: Side) -> (*mut u8, u16, u16) { |
|
|
|
/// if double buffering is enabled
|
|
|
|
|
|
|
|
pub fn get_raw_framebuffer(&self, screen: Screen, side: Side) -> (*mut u8, u16, u16) { |
|
|
|
|
|
|
|
let mut width: u16 = 0; |
|
|
|
let mut width: u16 = 0; |
|
|
|
let mut height: u16 = 0; |
|
|
|
let mut height: u16 = 0; |
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
let buf: *mut u8 = |
|
|
|
let buf: *mut u8 = ctru_sys::gfxGetFramebuffer( |
|
|
|
ctru_sys::gfxGetFramebuffer(screen.into(), side.into(), &mut width, &mut height); |
|
|
|
ctru_sys::GFX_TOP, |
|
|
|
|
|
|
|
side.into(), |
|
|
|
|
|
|
|
&mut width, |
|
|
|
|
|
|
|
&mut height, |
|
|
|
|
|
|
|
); |
|
|
|
(buf, width, height) |
|
|
|
(buf, width, height) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl From<Screen> for ctru_sys::gfxScreen_t { |
|
|
|
impl Screen for BottomScreen { |
|
|
|
fn from(g: Screen) -> ctru_sys::gfxScreen_t { |
|
|
|
fn into_raw(&self) -> ctru_sys::gfxScreen_t { |
|
|
|
use self::Screen::*; |
|
|
|
ctru_sys::GFX_BOTTOM |
|
|
|
match g { |
|
|
|
} |
|
|
|
Top => ctru_sys::GFX_TOP, |
|
|
|
|
|
|
|
Bottom => ctru_sys::GFX_BOTTOM, |
|
|
|
fn set_double_buffering(&mut self, enabled: bool) { |
|
|
|
|
|
|
|
unsafe { ctru_sys::gfxSetDoubleBuffering(ctru_sys::GFX_BOTTOM, enabled) } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn get_framebuffer_format(&self) -> FramebufferFormat { |
|
|
|
|
|
|
|
unsafe { ctru_sys::gfxGetScreenFormat(ctru_sys::GFX_BOTTOM).into() } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn set_framebuffer_format(&mut self, fmt: FramebufferFormat) { |
|
|
|
|
|
|
|
unsafe { ctru_sys::gfxSetScreenFormat(ctru_sys::GFX_BOTTOM, fmt.into()) } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
fn get_raw_framebuffer(&self, side: Side) -> (*mut u8, u16, u16) { |
|
|
|
|
|
|
|
let mut width: u16 = 0; |
|
|
|
|
|
|
|
let mut height: u16 = 0; |
|
|
|
|
|
|
|
unsafe { |
|
|
|
|
|
|
|
let buf: *mut u8 = ctru_sys::gfxGetFramebuffer( |
|
|
|
|
|
|
|
ctru_sys::GFX_BOTTOM, |
|
|
|
|
|
|
|
side.into(), |
|
|
|
|
|
|
|
&mut width, |
|
|
|
|
|
|
|
&mut height, |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
(buf, width, height) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
@ -201,8 +221,8 @@ impl Default for Gfx { |
|
|
|
fn default() -> Self { |
|
|
|
fn default() -> Self { |
|
|
|
unsafe { ctru_sys::gfxInitDefault() }; |
|
|
|
unsafe { ctru_sys::gfxInitDefault() }; |
|
|
|
Gfx { |
|
|
|
Gfx { |
|
|
|
top_screen: RefCell::new(Screen::Top), |
|
|
|
top_screen: RefCell::new(TopScreen), |
|
|
|
bottom_screen: RefCell::new(Screen::Bottom), |
|
|
|
bottom_screen: RefCell::new(BottomScreen), |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|