diff --git a/src/gfx.rs b/src/gfx.rs new file mode 100644 index 0000000..c767cf5 --- /dev/null +++ b/src/gfx.rs @@ -0,0 +1,31 @@ +use ::raw::gfx; + +pub fn init_default() -> () { + unsafe { + gfx::gfxInitDefault(); + } +} + +pub fn exit() -> () { + unsafe { + gfx::gfxExit(); + } +} + +pub fn set_3d_enabled(enabled: bool) -> () { + unsafe { + gfx::gfxSet3D(match enabled { true => 1u8, false => 0u8 }); + } +} + +pub fn flush_buffers() -> () { + unsafe { + gfx::gfxFlushBuffers(); + } +} + +pub fn swap_buffers() -> () { + unsafe { + gfx::gfxSwapBuffers(); + } +} diff --git a/src/lib.rs b/src/lib.rs index 98bd1ef..b652b63 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,21 +11,6 @@ pub mod raw; pub type Result = i32; pub type Handle = u32; -pub mod srv { - use super::Result; - use super::raw::srv; - pub fn init() -> Result { - unsafe { - return srv::srvInit(); - } - } - pub fn exit() -> Result { - unsafe { - return srv::srvExit(); - } - } - - pub fn awesome() -> i32 { - 0 - } -} +pub mod srv; +pub mod gfx; +pub mod services; diff --git a/src/raw/services/gsp.rs b/src/raw/services/gsp.rs index 6518978..3420186 100644 --- a/src/raw/services/gsp.rs +++ b/src/raw/services/gsp.rs @@ -9,7 +9,7 @@ pub fn GSP_REBASE_REG(r: u32) { } #[repr(C)] -#[derive(Copy)] +#[derive(Clone, Copy)] pub struct GSP_FramebufferInfo { active_framebuf: u32, //"0=first, 1=second" framebuf0_vaddr: *mut u32, //"Framebuffer virtual address, for the main screen this is the 3D left framebuffer" @@ -20,10 +20,6 @@ pub struct GSP_FramebufferInfo { unk: u32 //"?" } -impl Clone for GSP_FramebufferInfo { - fn clone(&self) -> Self { *self } -} - #[repr(C)] pub enum GSP_FramebufferFormats { GSP_RGBA8_OES=0, //pixel_size = 4-bytes diff --git a/src/services/apt.rs b/src/services/apt.rs new file mode 100644 index 0000000..a1eee94 --- /dev/null +++ b/src/services/apt.rs @@ -0,0 +1,110 @@ +use ::Result; + +use core::ops::Fn; + +use ::raw::services::apt; + +pub enum AppStatus { + NotInitialized, + Running, + Suspended, + Exiting, + Suspending, + SleepMode, + PrepareSleepMode, + AppletStarted, + AppletClosed +} + + +fn to_raw_appstatus(status: AppStatus) -> apt::APP_STATUS { + use self::AppStatus::*; + match status { + NotInitialized => apt::APP_STATUS::APP_NOTINITIALIZED, + Running => apt::APP_STATUS::APP_RUNNING, + Suspended => apt::APP_STATUS::APP_SUSPENDED, + Exiting => apt::APP_STATUS::APP_EXITING, + Suspending => apt::APP_STATUS::APP_SUSPENDING, + SleepMode => apt::APP_STATUS::APP_SLEEPMODE, + PrepareSleepMode => apt::APP_STATUS::APP_PREPARE_SLEEPMODE, + AppletStarted => apt::APP_STATUS::APP_APPLETSTARTED, + AppletClosed => apt::APP_STATUS::APP_APPLETCLOSED, + } +} + +fn from_raw_appstatus(status: apt::APP_STATUS) -> AppStatus { + use self::AppStatus::*; + match status { + apt::APP_STATUS::APP_NOTINITIALIZED => NotInitialized, + apt::APP_STATUS::APP_RUNNING => Running, + apt::APP_STATUS::APP_SUSPENDED => Suspended, + apt::APP_STATUS::APP_EXITING => Exiting, + apt::APP_STATUS::APP_SUSPENDING => Suspending, + apt::APP_STATUS::APP_SLEEPMODE => SleepMode, + apt::APP_STATUS::APP_PREPARE_SLEEPMODE => PrepareSleepMode, + apt::APP_STATUS::APP_APPLETSTARTED => AppletStarted, + apt::APP_STATUS::APP_APPLETCLOSED => AppletClosed + } +} + +pub fn init() -> Result { + unsafe { + return apt::aptInit(); + } +} + +pub fn exit() -> () { + unsafe { + apt::aptExit(); + } +} + +pub fn get_status() -> AppStatus { + unsafe { + return from_raw_appstatus(apt::aptGetStatus()); + } +} + +pub fn set_status(status: AppStatus) -> () { + unsafe { + apt::aptSetStatus(to_raw_appstatus(status)); + } +} + +/// Return to the home menu. +/// +/// When `get_status` returns `AppStatus::Suspending`, you should call this, +/// otherwise the app will be left stuck in that state. +/// +/// The program will not return from this function until the system returns +/// to the application, or when the status changes to `AppStatus::Exiting`. +/// +/// # Examples +/// +/// ``` +/// if get_status() == Suspending { +/// return_to_menu(); +/// } +/// ``` +pub fn return_to_menu() -> () { + unsafe { + apt::aptReturnToMenu(); + } +} + +/// Execute a function repeatedly until the apt main loop is over. +/// +/// # Examples +/// +/// ``` +/// main_loop(|| { +/// // do things here +/// }); +/// ``` +pub fn main_loop(f: F) -> () where F : Fn() -> () { + unsafe { + while apt::aptMainLoop() != 0 { + f(); + } + } +} diff --git a/src/services/gsp.rs b/src/services/gsp.rs new file mode 100644 index 0000000..90ed3b2 --- /dev/null +++ b/src/services/gsp.rs @@ -0,0 +1,46 @@ +use ::Result; + +use ::raw::services::gsp; + +pub enum Event { + Psc0, + Psc1, + VBlank0, + VBlank1, + PPF, + P3D, + DMA +} + +fn to_raw_event(ev: Event) -> gsp::GSP_Event { + use ::raw::services::gsp::GSP_Event::*; + use self::Event::*; + + match ev { + Psc0 => GSPEVENT_PSC0, + Psc1 => GSPEVENT_PSC1, + VBlank0 => GSPEVENT_VBlank0, + VBlank1 => GSPEVENT_VBlank1, + PPF => GSPEVENT_PPF, + P3D => GSPEVENT_P3D, + DMA => GSPEVENT_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? + gsp::gspWaitForEvent(to_raw_event(ev), 0); + } +} diff --git a/src/services/hid.rs b/src/services/hid.rs new file mode 100644 index 0000000..03c9c4e --- /dev/null +++ b/src/services/hid.rs @@ -0,0 +1,134 @@ +use ::Result; + +use ::raw::services::hid; + +pub enum PadKey { + A, + B, + Select, + Start, + DPadRight, + DPadLeft, + DPadUp, + DPadDown, + R, + L, + X, + Y, + ZL, + ZR, + Touch, + CSRight, + CSLeft, + CSUp, + CSDown, + CRight, + CLeft, + CUp, + CDown, + + // convenience catch-all for dpad and cpad + Up, + Down, + Left, + Right +} + +fn to_raw_padkey(key: PadKey) -> u32 { + use ::raw::services::hid::PAD_KEY::*; + use self::PadKey::*; + + match key { + Up => KEY_DUP as u32 | KEY_CPAD_UP as u32, + Down => KEY_DDOWN as u32 | KEY_CPAD_DOWN as u32, + Left => KEY_DLEFT as u32 | KEY_CPAD_LEFT as u32, + Right => KEY_DRIGHT as u32 | KEY_CPAD_RIGHT as u32, + + A => KEY_A as u32, + B => KEY_B as u32, + X => KEY_X as u32, + Y => KEY_Y as u32, + L => KEY_L as u32, + R => KEY_R as u32, + ZL => KEY_ZL as u32, + ZR => KEY_ZR as u32, + Start => KEY_START as u32, + Select => KEY_SELECT as u32, + Touch => KEY_TOUCH as u32, + CSRight => KEY_CSTICK_RIGHT as u32, + CSLeft => KEY_CSTICK_LEFT as u32, + CSUp => KEY_CSTICK_UP as u32, + CSDown => KEY_CSTICK_DOWN as u32, + CRight => KEY_CPAD_RIGHT as u32, + CLeft => KEY_CPAD_LEFT as u32, + CDown => KEY_CPAD_DOWN as u32, + CUp => KEY_CPAD_UP as u32, + DPadLeft => KEY_DLEFT as u32, + DPadRight => KEY_DRIGHT as u32, + DPadUp => KEY_DUP as u32, + DPadDown => KEY_DDOWN as u32 + } +} + +pub fn init() -> Result { + unsafe { + // TODO allow sharedMem argument? + return hid::hidInit(0 as *mut u32); + } +} + +pub fn exit() -> () { + unsafe { + hid::hidExit(); + } +} + +/// Update ctrulib's button states. +/// +/// # Examples +/// +/// ``` +/// use ctru::service::apt; +/// +/// apt::main_loop(|| { +/// scan_input(); +/// if key_down(PadKey::A) { +/// apt::set_status(apt::AppStatus::Exiting); +/// } +/// }); +/// ``` +pub fn scan_input() -> () { + unsafe { + hid::hidScanInput(); + } +} + +pub fn key_down(key: PadKey) -> bool { + unsafe { + if hid::hidKeysDown() & to_raw_padkey(key) != 0 { + return true; + } else { + return false; + } + } +} + +pub fn key_held(key: PadKey) -> bool { + unsafe { + if hid::hidKeysHeld() & to_raw_padkey(key) != 0 { + return true; + } else { + return false; + } + } +} + +pub fn key_up(key: PadKey) -> bool { + unsafe { + if hid::hidKeysUp() & to_raw_padkey(key) != 0 { + return true; + } else { + return false; + } + } +} diff --git a/src/services/mod.rs b/src/services/mod.rs new file mode 100644 index 0000000..1bdeae7 --- /dev/null +++ b/src/services/mod.rs @@ -0,0 +1,3 @@ +pub mod apt; +pub mod hid; +pub mod gsp; diff --git a/src/srv.rs b/src/srv.rs new file mode 100644 index 0000000..44fb956 --- /dev/null +++ b/src/srv.rs @@ -0,0 +1,13 @@ +use ::Result; +use ::raw::srv; + +pub fn init() -> Result { + unsafe { + return srv::srvInit(); + } +} +pub fn exit() -> Result { + unsafe { + return srv::srvExit(); + } +}