use std::ffi::{CStr, CString};
use std::marker::PhantomData;
use sys::sdl as ll;
use event::EventPump;
use video::WindowBuilder;
#[derive(Copy, Clone, PartialEq)]
pub enum Error {
NoMemError = ll::SDL_ENOMEM as isize,
ReadError = ll::SDL_EFREAD as isize,
WriteError = ll::SDL_EFWRITE as isize,
SeekError = ll::SDL_EFSEEK as isize,
UnsupportedError = ll::SDL_UNSUPPORTED as isize
}
pub type SdlResult<T> = Result<T, String>;
use std::sync::atomic::{AtomicBool, ATOMIC_BOOL_INIT};
static IS_SDL_CONTEXT_ALIVE: AtomicBool = ATOMIC_BOOL_INIT;
pub struct Sdl {
_nosyncsend: PhantomData<*mut ()>
}
impl Sdl {
pub fn was_init(&self, flags: u32) -> u32 {
unsafe {
ll::SDL_WasInit(flags)
}
}
pub fn event_pump(&self) -> EventPump {
unsafe { EventPump::_unchecked_new() }
}
pub fn window(&self, title: &str, width: u32, height: u32) -> WindowBuilder {
WindowBuilder::new(self, title, width, height)
}
}
impl Drop for Sdl {
fn drop(&mut self) {
use std::sync::atomic::Ordering;
let was_alive = IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
assert!(was_alive);
unsafe { ll::SDL_Quit(); }
}
}
pub struct Subsystem<'sdl> {
flags: u32,
_marker: PhantomData<&'sdl Sdl>
}
impl<'sdl> Drop for Subsystem<'sdl> {
fn drop(&mut self) {
unsafe { ll::SDL_QuitSubSystem(self.flags); }
}
}
pub struct InitBuilder {
flags: u32
}
impl InitBuilder {
pub fn new() -> InitBuilder {
InitBuilder { flags: 0 }
}
pub fn build(&self) -> SdlResult<Sdl> {
unsafe {
use std::sync::atomic::Ordering;
let was_alive = IS_SDL_CONTEXT_ALIVE.swap(true, Ordering::Relaxed);
if was_alive {
Err(format!("Cannot have more than one `Sdl` in use at the same time"))
} else {
if ll::SDL_Init(self.flags) == 0 {
Ok(Sdl {
_nosyncsend: PhantomData
})
} else {
IS_SDL_CONTEXT_ALIVE.swap(false, Ordering::Relaxed);
Err(get_error())
}
}
}
}
pub fn unwrap(&self) -> Sdl { self.build().unwrap() }
pub fn build_subsystem(&self, _sdl: &Sdl) -> SdlResult<Subsystem> {
unsafe {
if ll::SDL_InitSubSystem(self.flags) == 0 {
Ok(Subsystem {
flags: self.flags,
_marker: PhantomData
})
} else {
Err(get_error())
}
}
}
pub fn everything(&mut self) -> &mut InitBuilder {
self.flags |= ll::SDL_INIT_EVERYTHING as u32;
self
}
pub fn timer(&mut self) -> &mut InitBuilder {
self.flags |= ll::SDL_INIT_TIMER as u32;
self
}
pub fn audio(&mut self) -> &mut InitBuilder {
self.flags |= ll::SDL_INIT_AUDIO as u32;
self
}
pub fn video(&mut self) -> &mut InitBuilder {
self.flags |= ll::SDL_INIT_VIDEO as u32;
self
}
pub fn joystick(&mut self) -> &mut InitBuilder {
self.flags |= ll::SDL_INIT_JOYSTICK as u32;
self
}
pub fn haptic(&mut self) -> &mut InitBuilder {
self.flags |= ll::SDL_INIT_HAPTIC as u32;
self
}
pub fn game_controller(&mut self) -> &mut InitBuilder {
self.flags |= ll::SDL_INIT_GAMECONTROLLER as u32;
self
}
pub fn events(&mut self) -> &mut InitBuilder {
self.flags |= ll::SDL_INIT_EVENTS as u32;
self
}
}
pub fn init() -> InitBuilder { InitBuilder::new() }
pub fn get_error() -> String {
unsafe {
let err = ll::SDL_GetError();
String::from_utf8_lossy(CStr::from_ptr(err).to_bytes()).to_string()
}
}
pub fn set_error(err: &str) {
let buf = CString::new(err).unwrap().as_ptr();
unsafe { ll::SDL_SetError(buf); }
}
pub fn set_error_from_code(err: Error) {
unsafe { ll::SDL_Error(err as ll::SDL_errorcode); }
}
pub fn clear_error() {
unsafe { ll::SDL_ClearError(); }
}
pub fn get_ticks() -> u32 {
unsafe { ll::SDL_GetTicks() as u32 }
}