Browse Source

Merge pull request #74 from FenrirWolf/gfx

Update and document Gfx module
pull/10/head
FenrirWolf 6 years ago committed by GitHub
parent
commit
97c7652fdd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      ctru-rs/Cargo.toml
  2. 148
      ctru-rs/src/gfx.rs
  3. 78
      ctru-rs/src/services/gspgpu.rs

2
ctru-rs/Cargo.toml

@ -3,7 +3,7 @@ authors = ["Ronald Kinard <furyhunter600@gmail.com>"] @@ -3,7 +3,7 @@ authors = ["Ronald Kinard <furyhunter600@gmail.com>"]
description = "A safe wrapper around smealum's ctrulib."
license = "https://en.wikipedia.org/wiki/Zlib_License"
name = "ctru-rs"
version = "0.7.0"
version = "0.7.1"
[lib]
crate-type = ["rlib"]

148
ctru-rs/src/gfx.rs

@ -1,118 +1,138 @@ @@ -1,118 +1,138 @@
//! LCD screens manipulation helper
use std::default::Default;
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(());
#[derive(Copy, Clone)]
/// Available screens on the 3DS
#[derive(Copy, Clone, Debug)]
pub enum Screen {
/// The top screen
Top,
/// The bottom screen
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 {
/// The left framebuffer. This framebuffer is also the one used when 3D is disabled
Left,
/// The right framebuffer
Right,
}
impl From<::libctru::gfxScreen_t> for Screen {
fn from(g: ::libctru::gfxScreen_t) -> Screen {
use self::Screen::*;
match g {
::libctru::GFX_TOP => Top,
::libctru::GFX_BOTTOM => Bottom,
_ => unreachable!(),
}
}
}
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 {
/// Initialize the Gfx module with the chosen framebuffer formats for the top and bottom
/// screens
///
/// Use `Gfx::default()` instead of this function to initialize the module with default parameters
pub fn new(
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 Gfx {
/// Enable or disable the 3D stereoscopic effect
pub fn set_3d_enabled(&self, enabled: bool) {
unsafe {
::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 {
use std::slice::from_raw_parts_mut;
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)
::libctru::gfxSetDoubleBuffering(screen.into(), enabled)
}
}
/// Flushes the current framebuffers
pub fn flush_buffers(&self) {
unsafe { ::libctru::gfxFlushBuffers() };
}
/// Swaps the framebuffers and sets the gsp state
///
/// Use this function when working with software rendering
pub fn swap_buffers(&self) {
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) {
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 {
unsafe { ::libctru::gfxGetScreenFormat(screen.into()).into() }
}
pub fn set_framebuffer_format(&self, screen: Screen,
fmt: FramebufferFormat) {
/// Change the framebuffer format for a screen
pub fn set_framebuffer_format(&self, screen: Screen, fmt: FramebufferFormat) {
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 {
::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) {
unsafe {
::libctru::gspWaitForEvent(::libctru::GSPGPU_EVENT_VBlank0, true)
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<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,
}
}
}

78
ctru-rs/src/services/gspgpu.rs

@ -1,5 +1,8 @@ @@ -1,5 +1,8 @@
//! GSPGPU service
use std::convert::From;
#[derive(Copy, Clone, Debug)]
pub enum Event {
Psc0,
Psc1,
@ -10,31 +13,46 @@ pub enum Event { @@ -10,31 +13,46 @@ pub enum Event {
DMA,
}
#[derive(Copy, Clone)]
/// The different framebuffer formats supported by the 3DS
#[derive(Copy, Clone, Debug)]
pub enum FramebufferFormat {
/// RGBA8. 4 bytes per pixel
Rgba8,
/// BGR8. 3 bytes per pixel
Bgr8,
/// RGB565. 2 bytes per pixel
Rgb565,
/// RGB5A1. 2 bytes per pixel
Rgb5A1,
/// RGBA4. 2 bytes per pixel
Rgba4,
}
impl FramebufferFormat {
/// Returns the number of bytes per pixel used by this FramebufferFormat
pub fn pixel_depth_bytes(&self) -> usize {
use self::FramebufferFormat::*;
match *self {
Rgba8 => 4usize,
Bgr8 => 3usize,
Rgb565 => 2usize,
Rgb5A1 => 2usize,
Rgba4 => 2usize,
Rgba8 => 4,
Bgr8 => 3,
Rgb565 => 2,
Rgb5A1 => 2,
Rgba4 => 2,
}
}
}
/// Waits for a GSPGPU event to occur.
///
/// `discard_current` determines whether to discard the current event and wait for the next event
pub fn wait_for_event(ev: Event, discard_current: bool) {
unsafe {
::libctru::gspWaitForEvent(ev.into(), discard_current);
}
}
impl From<::libctru::GSPGPU_FramebufferFormats> for FramebufferFormat {
#[inline]
fn from(g: ::libctru::GSPGPU_FramebufferFormats) -> FramebufferFormat {
fn from(g: ::libctru::GSPGPU_FramebufferFormats) -> Self {
use self::FramebufferFormat::*;
match g {
::libctru::GSP_RGBA8_OES => Rgba8,
@ -48,8 +66,7 @@ impl From<::libctru::GSPGPU_FramebufferFormats> for FramebufferFormat { @@ -48,8 +66,7 @@ impl From<::libctru::GSPGPU_FramebufferFormats> for FramebufferFormat {
}
impl From<FramebufferFormat> for ::libctru::GSPGPU_FramebufferFormats {
#[inline]
fn from(g: FramebufferFormat) -> ::libctru::GSPGPU_FramebufferFormats {
fn from(g: FramebufferFormat) -> Self {
use self::FramebufferFormat::*;
match g {
Rgba8 => ::libctru::GSP_RGBA8_OES,
@ -61,34 +78,17 @@ impl From<FramebufferFormat> for ::libctru::GSPGPU_FramebufferFormats { @@ -61,34 +78,17 @@ impl From<FramebufferFormat> for ::libctru::GSPGPU_FramebufferFormats {
}
}
fn to_raw_event(ev: Event) -> ::libctru::GSPGPU_Event {
use self::Event::*;
match ev {
Psc0 => ::libctru::GSPGPU_EVENT_PSC0,
Psc1 => ::libctru::GSPGPU_EVENT_PSC1,
VBlank0 => ::libctru::GSPGPU_EVENT_VBlank0,
VBlank1 => ::libctru::GSPGPU_EVENT_VBlank1,
PPF => ::libctru::GSPGPU_EVENT_PPF,
P3D => ::libctru::GSPGPU_EVENT_P3D,
DMA => ::libctru::GSPGPU_EVENT_DMA,
}
}
/// Sleep until GSP event fires.
///
/// # Examples
///
/// Wait for VBlank.
///
/// ```
/// use ctru::services::apt;
/// apt::main_loop(|| {
/// wait_for_event(Event::VBlank0);
/// });
pub fn wait_for_event(ev: Event) -> () {
unsafe {
// TODO second argument?
::libctru::gspWaitForEvent(to_raw_event(ev), false);
impl From<Event> for ::libctru::GSPGPU_Event {
fn from(ev: Event) -> Self {
use self::Event::*;
match ev {
Psc0 => ::libctru::GSPGPU_EVENT_PSC0,
Psc1 => ::libctru::GSPGPU_EVENT_PSC1,
VBlank0 => ::libctru::GSPGPU_EVENT_VBlank0,
VBlank1 => ::libctru::GSPGPU_EVENT_VBlank1,
PPF => ::libctru::GSPGPU_EVENT_PPF,
P3D => ::libctru::GSPGPU_EVENT_P3D,
DMA => ::libctru::GSPGPU_EVENT_DMA,
}
}
}

Loading…
Cancel
Save