Browse Source

Merge branch 'master' into example/time-rtc

pull/23/head
Ian Chamberlain 3 years ago
parent
commit
aaca346f38
No known key found for this signature in database
GPG Key ID: AE5484D09405AA60
  1. 3
      ctru-rs/Cargo.toml
  2. 4
      ctru-rs/examples/buttons.rs
  3. 13
      ctru-rs/examples/gfx-wide-mode.rs
  4. 6
      ctru-rs/examples/hello-both-screens.rs
  5. 59
      ctru-rs/examples/hello-world.rs
  6. 65
      ctru-rs/examples/network-sockets.rs
  7. 4
      ctru-rs/examples/software-keyboard.rs
  8. 19
      ctru-rs/src/console.rs
  9. 144
      ctru-rs/src/gfx.rs

3
ctru-rs/Cargo.toml

@ -18,3 +18,6 @@ pthread-3ds = { git = "https://github.com/Meziu/pthread-3ds.git" }
libc = "0.2" libc = "0.2"
bitflags = "1.0.0" bitflags = "1.0.0"
widestring = "0.2.2" widestring = "0.2.2"
[dev-dependencies]
ferris-says = "0.2.1"

4
ctru-rs/examples/buttons.rs

@ -1,5 +1,5 @@
use ctru::console::Console; use ctru::console::Console;
use ctru::gfx::{Gfx, Screen}; use ctru::gfx::Gfx;
use ctru::services::apt::Apt; use ctru::services::apt::Apt;
use ctru::services::hid::{Hid, KeyPad}; use ctru::services::hid::{Hid, KeyPad};
@ -9,7 +9,7 @@ fn main() {
let apt = Apt::init().unwrap(); let apt = Apt::init().unwrap();
let hid = Hid::init().unwrap(); let hid = Hid::init().unwrap();
let gfx = Gfx::default(); let gfx = Gfx::default();
let console = Console::init(&gfx, Screen::Top); let console = Console::init(gfx.top_screen.borrow_mut());
println!("Hi there! Try pressing a button"); println!("Hi there! Try pressing a button");
println!("\x1b[29;16HPress Start to exit"); println!("\x1b[29;16HPress Start to exit");

13
ctru-rs/examples/gfx_wide_mode.rs → ctru-rs/examples/gfx-wide-mode.rs

@ -1,7 +1,4 @@
extern crate ctru;
use ctru::console::Console; use ctru::console::Console;
use ctru::gfx::Screen;
use ctru::services::hid::KeyPad; use ctru::services::hid::KeyPad;
use ctru::services::{Apt, Hid}; use ctru::services::{Apt, Hid};
use ctru::Gfx; use ctru::Gfx;
@ -11,7 +8,7 @@ fn main() {
let apt = Apt::init().unwrap(); let apt = Apt::init().unwrap();
let hid = Hid::init().unwrap(); let hid = Hid::init().unwrap();
let gfx = Gfx::default(); let gfx = Gfx::default();
let _console = Console::init(&gfx, Screen::Top); let mut console = Console::init(gfx.top_screen.borrow_mut());
println!("Press A to enable/disable wide screen mode."); println!("Press A to enable/disable wide screen mode.");
@ -23,7 +20,13 @@ fn main() {
} }
if hid.keys_down().contains(KeyPad::KEY_A) { if hid.keys_down().contains(KeyPad::KEY_A) {
gfx.set_wide_mode(!gfx.get_wide_mode()); drop(console);
let wide_mode = gfx.top_screen.borrow().get_wide_mode();
gfx.top_screen.borrow_mut().set_wide_mode(!wide_mode);
console = Console::init(gfx.top_screen.borrow_mut());
println!("Press A to enable/disable wide screen mode.");
} }
gfx.flush_buffers(); gfx.flush_buffers();

6
ctru-rs/examples/hello-both-screens.rs

@ -1,5 +1,5 @@
use ctru::console::Console; use ctru::console::Console;
use ctru::gfx::{Gfx, Screen}; use ctru::gfx::Gfx;
use ctru::services::apt::Apt; use ctru::services::apt::Apt;
use ctru::services::hid::{Hid, KeyPad}; use ctru::services::hid::{Hid, KeyPad};
@ -11,11 +11,11 @@ fn main() {
let gfx = Gfx::default(); let gfx = Gfx::default();
// Start a console on the top screen // Start a console on the top screen
let top_screen = Console::init(&gfx, Screen::Top); let top_screen = Console::init(gfx.top_screen.borrow_mut());
// Start a console on the bottom screen. // Start a console on the bottom screen.
// The most recently initialized console will be active by default // The most recently initialized console will be active by default
let bottom_screen = Console::init(&gfx, Screen::Bottom); let bottom_screen = Console::init(gfx.bottom_screen.borrow_mut());
// Let's print on the top screen first // Let's print on the top screen first
top_screen.select(); top_screen.select();

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

@ -1,56 +1,41 @@
use ctru::console::Console; use ctru::console::Console;
use ctru::gfx::{Gfx, Screen}; use ctru::gfx::Gfx;
use ctru::services::apt::Apt; use ctru::services::apt::Apt;
use ctru::services::hid::{Hid, KeyPad}; use ctru::services::hid::{Hid, KeyPad};
use std::io::BufWriter;
fn main() { fn main() {
// Initialize ctrulib service handles.
// Service handles are internally reference-counted. When all instances of a
// service handle go out of scope, the service will be closed.
ctru::init(); ctru::init();
// The APT service handles application management functions, such as enabling sleep
// mode and jumping to the home menu or to other applications
let apt = Apt::init().unwrap();
// The HID service handles button and touch screen inputs.
let hid = Hid::init().unwrap();
// The GFX service manages the framebuffers for the top and bottom screens.
let gfx = Gfx::default(); let gfx = Gfx::default();
let hid = Hid::init().expect("Couldn't obtain HID controller");
let apt = Apt::init().expect("Couldn't obtain APT controller");
let _console = Console::init(gfx.top_screen.borrow_mut());
// Initialize a ctrulib console and direct standard output to it. let out = b"Hello fellow Rustaceans, I'm on the Nintendo 3DS!";
// Consoles can be initialized on both the top and bottom screens. let width = 24;
let _console = Console::init(&gfx, Screen::Top);
// Now we can print to stdout! let mut writer = BufWriter::new(Vec::new());
println!("Hello, world!"); ferris_says::say(out, width, &mut writer).unwrap();
// We can use escape sequences to move the cursor around the terminal. println!(
// The following text will be moved down 29 rows and right 16 characters "\x1b[0;0H{}",
// before printing begins. String::from_utf8_lossy(&writer.into_inner().unwrap())
println!("\x1b[29;16HPress Start to exit"); );
// Main application loop. // Main loop
while apt.main_loop() { while apt.main_loop() {
// Flushes and swaps the framebuffers when double-buffering //Scan all the inputs. This should be done once for each frame
// is enabled
gfx.flush_buffers();
gfx.swap_buffers();
// Wait for the next frame to begin
gfx.wait_for_vblank();
// Scan for user input.
hid.scan_input(); hid.scan_input();
// Check if the user has pressed the given button on this frame.
// If so, break out of the loop.
if hid.keys_down().contains(KeyPad::KEY_START) { if hid.keys_down().contains(KeyPad::KEY_START) {
break; break;
} }
} // Flush and swap framebuffers
gfx.flush_buffers();
gfx.swap_buffers();
// All of our service handles will drop out of scope at this point, //Wait for VBlank
// triggering the end of our application. gfx.wait_for_vblank();
}
} }

65
ctru-rs/examples/network-sockets.rs

@ -0,0 +1,65 @@
use ctru::console::Console;
use ctru::gfx::Gfx;
use ctru::services::apt::Apt;
use ctru::services::hid::{Hid, KeyPad};
use ctru::services::soc::Soc;
use std::io::{Read, Write};
use std::net::{Shutdown, TcpListener};
use std::time::Duration;
fn main() {
ctru::init();
let gfx = Gfx::default();
let _console = Console::init(gfx.top_screen.borrow_mut());
let hid = Hid::init().unwrap();
let apt = Apt::init().unwrap();
println!("\nlibctru sockets demo\n");
let soc = Soc::init().unwrap();
let server = TcpListener::bind("0.0.0.0:80").unwrap();
server.set_nonblocking(true).unwrap();
println!("Point your browser to http://{}/\n", soc.host_address());
while apt.main_loop() {
gfx.wait_for_vblank();
match server.accept() {
Ok((mut stream, socket_addr)) => {
println!("Got connection from {}", socket_addr);
let mut buf = [0u8; 4096];
match stream.read(&mut buf) {
Ok(_) => {
let req_str = String::from_utf8_lossy(&buf);
println!("{}", req_str);
}
Err(e) => println!("Unable to read stream: {}", e),
}
let response = b"HTTP/1.1 200 OK\r\nContent-Type: text/html; charset=UTF-8\r\n\r\n<html><body>Hello world</body></html>\r\n";
if let Err(e) = stream.write(response) {
println!("Error writing http response: {}", e);
}
stream.shutdown(Shutdown::Both).unwrap();
}
Err(e) => match e.kind() {
std::io::ErrorKind::WouldBlock => {}
_ => {
println!("Error accepting connection: {}", e);
std::thread::sleep(Duration::from_secs(2));
}
},
}
hid.scan_input();
if hid.keys_down().contains(KeyPad::KEY_START) {
break;
};
}
}

4
ctru-rs/examples/software-keyboard.rs

@ -1,6 +1,6 @@
use ctru::applets::swkbd::{Button, Swkbd}; use ctru::applets::swkbd::{Button, Swkbd};
use ctru::console::Console; use ctru::console::Console;
use ctru::gfx::{Gfx, Screen}; use ctru::gfx::Gfx;
use ctru::services::apt::Apt; use ctru::services::apt::Apt;
use ctru::services::hid::{Hid, KeyPad}; use ctru::services::hid::{Hid, KeyPad};
@ -9,7 +9,7 @@ fn main() {
let apt = Apt::init().unwrap(); let apt = Apt::init().unwrap();
let hid = Hid::init().unwrap(); let hid = Hid::init().unwrap();
let gfx = Gfx::default(); let gfx = Gfx::default();
let _console = Console::init(&gfx, Screen::Top); let _console = Console::init(gfx.top_screen.borrow_mut());
println!("Press A to enter some text or press Start to quit"); println!("Press A to enter some text or press Start to quit");

19
ctru-rs/src/console.rs

@ -1,28 +1,25 @@
use std::cell::RefMut;
use std::default::Default; use std::default::Default;
use std::marker::PhantomData;
use ctru_sys::{consoleClear, consoleInit, consoleSelect, consoleSetWindow, PrintConsole}; use ctru_sys::{consoleClear, consoleInit, consoleSelect, consoleSetWindow, PrintConsole};
use crate::gfx::{Gfx, Screen}; use crate::gfx::Screen;
pub struct Console<'gfx> { pub struct Console<'screen> {
context: Box<PrintConsole>, context: Box<PrintConsole>,
_gfx: PhantomData<&'gfx ()>, screen: RefMut<'screen, dyn Screen>,
} }
impl<'gfx> Console<'gfx> { impl<'screen> Console<'screen> {
/// Initialize a console on the chosen screen, overwriting whatever was on the screen /// Initialize a console on the chosen screen, overwriting whatever was on the screen
/// previously (including other consoles). The new console is automatically selected for /// previously (including other consoles). The new console is automatically selected for
/// printing. /// printing.
pub fn init(_gfx: &'gfx Gfx, screen: Screen) -> Self { pub fn init(screen: RefMut<'screen, dyn Screen>) -> Self {
let mut context = Box::new(PrintConsole::default()); let mut context = Box::new(PrintConsole::default());
unsafe { consoleInit(screen.into(), context.as_mut()) }; unsafe { consoleInit(screen.as_raw(), context.as_mut()) };
Console { Console { context, screen }
context,
_gfx: PhantomData,
}
} }
/// Select this console as the current target for stdout /// Select this console as the current target for stdout

144
ctru-rs/src/gfx.rs

@ -1,25 +1,56 @@
//! LCD screens manipulation helper //! LCD screens manipulation helper
use std::cell::RefCell;
use std::default::Default; use std::default::Default;
use std::ops::Drop; use std::ops::Drop;
use crate::services::gspgpu::{self, FramebufferFormat}; use crate::services::gspgpu::{self, FramebufferFormat};
/// A handle to libctru's gfx module. This module is a wrapper around the GSPGPU service that /// Trait implemented by TopScreen and BottomScreen for common methods
/// provides helper functions and utilities for software rendering. pub trait Screen {
/// Returns the libctru value for the Screen kind
fn as_raw(&self) -> ctru_sys::gfxScreen_t;
/// Sets whether to use double buffering. Enabled by default.
/// ///
/// The service exits when this struct is dropped. /// Note that even when double buffering is disabled, one should still use the `swap_buffers`
pub struct Gfx(()); /// method on each frame to keep the gsp configuration up to date
fn set_double_buffering(&mut self, enabled: bool) {
unsafe { ctru_sys::gfxSetDoubleBuffering(self.as_raw(), enabled) }
}
/// Available screens on the 3DS /// Gets the framebuffer format
#[derive(Copy, Clone, Debug)] fn get_framebuffer_format(&self) -> FramebufferFormat {
pub enum Screen { unsafe { ctru_sys::gfxGetScreenFormat(self.as_raw()).into() }
/// The top screen
Top,
/// The bottom screen
Bottom,
} }
/// Change the framebuffer format
fn set_framebuffer_format(&mut self, fmt: FramebufferFormat) {
unsafe { ctru_sys::gfxSetScreenFormat(self.as_raw(), fmt.into()) }
}
/// 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) {
let mut width: u16 = 0;
let mut height: u16 = 0;
unsafe {
let buf: *mut u8 =
ctru_sys::gfxGetFramebuffer(self.as_raw(), side.into(), &mut width, &mut height);
(buf, width, height)
}
}
}
#[non_exhaustive]
pub struct TopScreen;
#[non_exhaustive]
pub struct BottomScreen;
#[derive(Copy, Clone, Debug)] #[derive(Copy, Clone, Debug)]
/// Side of top screen framebuffer /// Side of top screen framebuffer
/// ///
@ -31,6 +62,16 @@ pub enum Side {
Right, Right,
} }
/// 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.
#[non_exhaustive]
pub struct Gfx {
pub top_screen: RefCell<TopScreen>,
pub bottom_screen: RefCell<BottomScreen>,
}
impl Gfx { impl Gfx {
/// Initialize the Gfx module with the chosen framebuffer formats for the top and bottom /// Initialize the Gfx module with the chosen framebuffer formats for the top and bottom
/// screens /// screens
@ -44,32 +85,10 @@ impl Gfx {
unsafe { unsafe {
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(TopScreen),
bottom_screen: RefCell::new(BottomScreen),
} }
/// Enable or disable the 3D stereoscopic effect
pub fn set_3d_enabled(&self, enabled: bool) {
unsafe { ctru_sys::gfxSet3D(enabled) }
}
/// Enable or disable the wide screen mode (top screen).
///
/// This only works when 3D is disabled.
pub fn set_wide_mode(&self, enabled: bool) {
unsafe { ctru_sys::gfxSetWide(enabled) };
}
/// Get the status of wide screen mode.
pub fn get_wide_mode(&self) -> bool {
unsafe { ctru_sys::gfxIsWide() }
}
/// 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 { ctru_sys::gfxSetDoubleBuffering(screen.into(), enabled) }
} }
/// Flushes the current framebuffers /// Flushes the current framebuffers
@ -97,41 +116,39 @@ impl Gfx {
pub fn wait_for_vblank(&self) { pub fn wait_for_vblank(&self) {
gspgpu::wait_for_event(gspgpu::Event::VBlank0, true); 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 { ctru_sys::gfxGetScreenFormat(screen.into()).into() }
} }
/// Change the framebuffer format for a screen impl TopScreen {
pub fn set_framebuffer_format(&self, screen: Screen, fmt: FramebufferFormat) { /// Enable or disable the 3D stereoscopic effect
unsafe { ctru_sys::gfxSetScreenFormat(screen.into(), fmt.into()) } pub fn set_3d_enabled(&mut self, enabled: bool) {
unsafe {
ctru_sys::gfxSet3D(enabled);
}
} }
/// Returns a tuple containing a pointer to the specifified framebuffer (as determined by the /// Enable or disable the wide screen mode (top screen).
/// provided `Screen` and `Side`), the width of the framebuffer in pixels, and the height of /// This only works when 3D is disabled.
/// the framebuffer in pixels pub fn set_wide_mode(&mut self, enabled: bool) {
///
/// 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 {
let mut width: u16 = 0; ctru_sys::gfxSetWide(enabled);
let mut height: u16 = 0;
let buf: *mut u8 =
ctru_sys::gfxGetFramebuffer(screen.into(), side.into(), &mut width, &mut height);
(buf, width, height)
} }
} }
/// Get the status of wide screen mode.
pub fn get_wide_mode(&self) -> bool {
unsafe { ctru_sys::gfxIsWide() }
}
} }
impl From<Screen> for ctru_sys::gfxScreen_t { impl Screen for TopScreen {
fn from(g: Screen) -> ctru_sys::gfxScreen_t { fn as_raw(&self) -> ctru_sys::gfxScreen_t {
use self::Screen::*; ctru_sys::GFX_TOP
match g { }
Top => ctru_sys::GFX_TOP,
Bottom => ctru_sys::GFX_BOTTOM,
} }
impl Screen for BottomScreen {
fn as_raw(&self) -> ctru_sys::gfxScreen_t {
ctru_sys::GFX_BOTTOM
} }
} }
@ -148,7 +165,10 @@ impl From<Side> for ctru_sys::gfx3dSide_t {
impl Default for Gfx { impl Default for Gfx {
fn default() -> Self { fn default() -> Self {
unsafe { ctru_sys::gfxInitDefault() }; unsafe { ctru_sys::gfxInitDefault() };
Gfx(()) Gfx {
top_screen: RefCell::new(TopScreen),
bottom_screen: RefCell::new(BottomScreen),
}
} }
} }

Loading…
Cancel
Save