|
|
@ -1,118 +1,138 @@ |
|
|
|
|
|
|
|
//! LCD screens manipulation helper
|
|
|
|
|
|
|
|
|
|
|
|
use std::default::Default; |
|
|
|
use std::default::Default; |
|
|
|
use std::ops::Drop; |
|
|
|
use std::ops::Drop; |
|
|
|
|
|
|
|
|
|
|
|
use services::gspgpu::FramebufferFormat; |
|
|
|
use services::gspgpu::{self, FramebufferFormat}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// A handle to libctru's gfx module. This module is a wrapper around the GSPGPU service that
|
|
|
|
|
|
|
|
/// provides helper functions and utilities for software rendering.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// The service exits when this struct is dropped.
|
|
|
|
pub struct Gfx(()); |
|
|
|
pub struct Gfx(()); |
|
|
|
|
|
|
|
|
|
|
|
#[derive(Copy, Clone)] |
|
|
|
/// Available screens on the 3DS
|
|
|
|
|
|
|
|
#[derive(Copy, Clone, Debug)] |
|
|
|
pub enum Screen { |
|
|
|
pub enum Screen { |
|
|
|
|
|
|
|
/// The top screen
|
|
|
|
Top, |
|
|
|
Top, |
|
|
|
|
|
|
|
/// The bottom screen
|
|
|
|
Bottom, |
|
|
|
Bottom, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[derive(Copy, Clone)] |
|
|
|
#[derive(Copy, Clone, Debug)] |
|
|
|
|
|
|
|
/// Side of top screen framebuffer
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// The top screen of the 3DS can have two separate sets of framebuffers to support its 3D functionality
|
|
|
|
pub enum Side { |
|
|
|
pub enum Side { |
|
|
|
|
|
|
|
/// The left framebuffer. This framebuffer is also the one used when 3D is disabled
|
|
|
|
Left, |
|
|
|
Left, |
|
|
|
|
|
|
|
/// The right framebuffer
|
|
|
|
Right, |
|
|
|
Right, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
impl From<::libctru::gfxScreen_t> for Screen { |
|
|
|
impl Gfx { |
|
|
|
fn from(g: ::libctru::gfxScreen_t) -> Screen { |
|
|
|
/// Initialize the Gfx module with the chosen framebuffer formats for the top and bottom
|
|
|
|
use self::Screen::*; |
|
|
|
/// screens
|
|
|
|
match g { |
|
|
|
///
|
|
|
|
::libctru::GFX_TOP => Top, |
|
|
|
/// Use `Gfx::default()` instead of this function to initialize the module with default parameters
|
|
|
|
::libctru::GFX_BOTTOM => Bottom, |
|
|
|
pub fn new( |
|
|
|
_ => unreachable!(), |
|
|
|
top_fb_fmt: FramebufferFormat, bottom_fb_fmt: FramebufferFormat, use_vram_buffers: bool) -> Self { |
|
|
|
} |
|
|
|
unsafe { ::libctru::gfxInit(top_fb_fmt.into(), bottom_fb_fmt.into(), use_vram_buffers); } |
|
|
|
} |
|
|
|
Gfx(()) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl From<Screen> for ::libctru::gfxScreen_t { |
|
|
|
|
|
|
|
fn from(g: Screen) -> ::libctru::gfxScreen_t { |
|
|
|
|
|
|
|
use self::Screen::*; |
|
|
|
|
|
|
|
match g { |
|
|
|
|
|
|
|
Top => ::libctru::GFX_TOP, |
|
|
|
|
|
|
|
Bottom => ::libctru::GFX_BOTTOM, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl From<::libctru::gfx3dSide_t> for Side { |
|
|
|
|
|
|
|
fn from(s: ::libctru::gfx3dSide_t) -> Side { |
|
|
|
|
|
|
|
use self::Side::*; |
|
|
|
|
|
|
|
match s { |
|
|
|
|
|
|
|
::libctru::GFX_LEFT => Left, |
|
|
|
|
|
|
|
::libctru::GFX_RIGHT => Right, |
|
|
|
|
|
|
|
_ => unreachable!(), |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl From<Side> for ::libctru::gfx3dSide_t { |
|
|
|
|
|
|
|
fn from(s: Side) -> ::libctru::gfx3dSide_t { |
|
|
|
|
|
|
|
use self::Side::*; |
|
|
|
|
|
|
|
match s { |
|
|
|
|
|
|
|
Left => ::libctru::GFX_LEFT, |
|
|
|
|
|
|
|
Right => ::libctru::GFX_RIGHT, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl Gfx { |
|
|
|
/// Enable or disable the 3D stereoscopic effect
|
|
|
|
pub fn set_3d_enabled(&self, enabled: bool) { |
|
|
|
pub fn set_3d_enabled(&self, enabled: bool) { |
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
::libctru::gfxSet3D(enabled) |
|
|
|
::libctru::gfxSet3D(enabled) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn get_framebuffer(&self, screen: Screen, side: Side) -> (&'static mut [u8], u16, u16) { |
|
|
|
/// Sets whether to use double buffering. Enabled by default.
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// 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
|
|
|
|
|
|
|
|
pub fn set_double_buffering(&self, screen: Screen, enabled: bool) { |
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
use std::slice::from_raw_parts_mut; |
|
|
|
::libctru::gfxSetDoubleBuffering(screen.into(), enabled) |
|
|
|
|
|
|
|
|
|
|
|
let mut w: u16 = 0; |
|
|
|
|
|
|
|
let mut h: u16 = 0; |
|
|
|
|
|
|
|
let buf: *mut u8 = ::libctru::gfxGetFramebuffer(screen.into(), |
|
|
|
|
|
|
|
side.into(), |
|
|
|
|
|
|
|
&mut w as *mut u16, |
|
|
|
|
|
|
|
&mut h as &mut u16); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
let fbfmt = self.get_framebuffer_format(screen); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
(from_raw_parts_mut(buf, (w as usize * h as usize) * fbfmt.pixel_depth_bytes()), w, h) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Flushes the current framebuffers
|
|
|
|
pub fn flush_buffers(&self) { |
|
|
|
pub fn flush_buffers(&self) { |
|
|
|
unsafe { ::libctru::gfxFlushBuffers() }; |
|
|
|
unsafe { ::libctru::gfxFlushBuffers() }; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Swaps the framebuffers and sets the gsp state
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// Use this function when working with software rendering
|
|
|
|
pub fn swap_buffers(&self) { |
|
|
|
pub fn swap_buffers(&self) { |
|
|
|
unsafe { ::libctru::gfxSwapBuffers() }; |
|
|
|
unsafe { ::libctru::gfxSwapBuffers() }; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Swaps the framebuffers without manipulating the gsp state
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// Use this function when working with GPU rendering
|
|
|
|
pub fn swap_buffers_gpu(&self) { |
|
|
|
pub fn swap_buffers_gpu(&self) { |
|
|
|
unsafe { ::libctru::gfxSwapBuffersGpu() }; |
|
|
|
unsafe { ::libctru::gfxSwapBuffersGpu() }; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Waits for the vertical blank interrupt
|
|
|
|
|
|
|
|
///
|
|
|
|
|
|
|
|
/// Use this to synchronize your application with the refresh rate of the LCD screens
|
|
|
|
|
|
|
|
pub fn wait_for_vblank(&self) { |
|
|
|
|
|
|
|
gspgpu::wait_for_event(gspgpu::Event::VBlank0, true); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/// Gets the framebuffer format for a screen
|
|
|
|
pub fn get_framebuffer_format(&self, screen: Screen) -> FramebufferFormat { |
|
|
|
pub fn get_framebuffer_format(&self, screen: Screen) -> FramebufferFormat { |
|
|
|
unsafe { ::libctru::gfxGetScreenFormat(screen.into()).into() } |
|
|
|
unsafe { ::libctru::gfxGetScreenFormat(screen.into()).into() } |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn set_framebuffer_format(&self, screen: Screen, |
|
|
|
/// Change the framebuffer format for a screen
|
|
|
|
fmt: FramebufferFormat) { |
|
|
|
pub fn set_framebuffer_format(&self, screen: Screen, fmt: FramebufferFormat) { |
|
|
|
unsafe { ::libctru::gfxSetScreenFormat(screen.into(), fmt.into()) } |
|
|
|
unsafe { ::libctru::gfxSetScreenFormat(screen.into(), fmt.into()) } |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn set_double_buffering(&self, screen: Screen, enabled: bool) { |
|
|
|
/// Returns a tuple containing a pointer to the specifified framebuffer (as determined by the
|
|
|
|
|
|
|
|
/// provided `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
|
|
|
|
|
|
|
|
pub fn get_raw_framebuffer(&self, screen: Screen, side: Side) -> (*mut u8, u16, u16) { |
|
|
|
unsafe { |
|
|
|
unsafe { |
|
|
|
::libctru::gfxSetDoubleBuffering(screen.into(), enabled) |
|
|
|
let mut width: u16 = 0; |
|
|
|
|
|
|
|
let mut height: u16 = 0; |
|
|
|
|
|
|
|
let buf: *mut u8 = ::libctru::gfxGetFramebuffer( |
|
|
|
|
|
|
|
screen.into(), |
|
|
|
|
|
|
|
side.into(), |
|
|
|
|
|
|
|
&mut width, |
|
|
|
|
|
|
|
&mut height, |
|
|
|
|
|
|
|
); |
|
|
|
|
|
|
|
(buf, width, height) |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn wait_for_vblank(&self) { |
|
|
|
impl From<Screen> for ::libctru::gfxScreen_t { |
|
|
|
unsafe { |
|
|
|
fn from(g: Screen) -> ::libctru::gfxScreen_t { |
|
|
|
::libctru::gspWaitForEvent(::libctru::GSPGPU_EVENT_VBlank0, true) |
|
|
|
use self::Screen::*; |
|
|
|
|
|
|
|
match g { |
|
|
|
|
|
|
|
Top => ::libctru::GFX_TOP, |
|
|
|
|
|
|
|
Bottom => ::libctru::GFX_BOTTOM, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl From<Side> for ::libctru::gfx3dSide_t { |
|
|
|
|
|
|
|
fn from(s: Side) -> ::libctru::gfx3dSide_t { |
|
|
|
|
|
|
|
use self::Side::*; |
|
|
|
|
|
|
|
match s { |
|
|
|
|
|
|
|
Left => ::libctru::GFX_LEFT, |
|
|
|
|
|
|
|
Right => ::libctru::GFX_RIGHT, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|