Skip to main content

ndless_sdl/
sdl.rs

1use core::str;
2use cstr_core::{CStr, CString};
3use ndless::hw::has_colors;
4use ndless::prelude::*;
5
6// Setup linking for all targets.
7#[cfg(target_os = "macos")]
8mod mac {
9	#[cfg(mac_framework)]
10	#[link(name = "SDL", kind = "framework")]
11	extern "C" {}
12
13	#[cfg(not(mac_framework))]
14	#[link(name = "SDL")]
15	extern "C" {}
16}
17
18#[cfg(not(target_os = "macos"))]
19mod others {
20	#[link(name = "SDL")]
21	extern "C" {}
22}
23
24pub mod ll {
25	#![allow(non_camel_case_types)]
26
27	use cty::{c_char as c_schar, c_int, c_uint, uint32_t};
28	pub type SDL_errorcode = c_uint;
29
30	pub const SDL_ENOMEM: SDL_errorcode = 0;
31	pub const SDL_EFREAD: SDL_errorcode = 1;
32	pub const SDL_EFWRITE: SDL_errorcode = 2;
33	pub const SDL_EFSEEK: SDL_errorcode = 3;
34	pub const SDL_UNSUPPORTED: SDL_errorcode = 4;
35	pub const SDL_LASTERROR: SDL_errorcode = 5;
36
37	pub type SDL_InitFlag = uint32_t;
38
39	pub const SDL_INIT_TIMER: SDL_InitFlag = 0x0000_0001;
40	pub const SDL_INIT_AUDIO: SDL_InitFlag = 0x0000_0010;
41	pub const SDL_INIT_VIDEO: SDL_InitFlag = 0x0000_0020;
42	pub const SDL_INIT_CDROM: SDL_InitFlag = 0x0000_0100;
43	pub const SDL_INIT_JOYSTICK: SDL_InitFlag = 0x0000_0200;
44	pub const SDL_INIT_NOPARACHUTE: SDL_InitFlag = 0x0010_0000;
45	pub const SDL_INIT_EVENTTHREAD: SDL_InitFlag = 0x0100_0000;
46	pub const SDL_INIT_EVERYTHING: SDL_InitFlag = 0x0000_FFFF;
47
48	extern "C" {
49		pub fn SDL_ClearError();
50		pub fn SDL_Error(code: SDL_errorcode);
51		pub fn SDL_SetError(fmt: *const c_schar);
52		pub fn SDL_GetError() -> *mut c_schar;
53		pub fn SDL_Quit();
54		pub fn SDL_QuitSubSystem(flags: SDL_InitFlag);
55		pub fn SDL_Init(flags: uint32_t) -> c_int;
56		pub fn SDL_InitSubSystem(flags: SDL_InitFlag) -> c_int;
57		pub fn SDL_WasInit(flags: SDL_InitFlag) -> SDL_InitFlag;
58		pub fn SDL_GetTicks() -> uint32_t;
59	}
60}
61
62#[repr(C)]
63#[derive(PartialEq, Copy, Clone, Debug, Eq, Hash)]
64pub struct Rect {
65	pub x: i16,
66	pub y: i16,
67	pub w: u16,
68	pub h: u16,
69}
70
71#[allow(non_snake_case)]
72pub fn Rect(x: i16, y: i16, w: u16, h: u16) -> Rect {
73	Rect { x, y, w, h }
74}
75
76impl Rect {
77	pub fn new(x: i16, y: i16, w: u16, h: u16) -> Rect {
78		Rect { x, y, w, h }
79	}
80}
81
82#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
83pub enum InitFlag {
84	Timer = ll::SDL_INIT_TIMER as isize,
85	Audio = ll::SDL_INIT_AUDIO as isize,
86	Video = ll::SDL_INIT_VIDEO as isize,
87	CDRom = ll::SDL_INIT_CDROM as isize,
88	Joystick = ll::SDL_INIT_JOYSTICK as isize,
89	NoParachute = ll::SDL_INIT_NOPARACHUTE as isize,
90	EventThread = ll::SDL_INIT_EVENTTHREAD as isize,
91	Everything = ll::SDL_INIT_EVERYTHING as isize,
92}
93
94#[derive(PartialEq, Eq, Copy, Clone, Debug, Hash)]
95pub enum Error {
96	NoMem = ll::SDL_ENOMEM as isize,
97	Read = ll::SDL_EFREAD as isize,
98	Write = ll::SDL_EFWRITE as isize,
99	Seek = ll::SDL_EFSEEK as isize,
100	Unsupported = ll::SDL_UNSUPPORTED as isize,
101}
102
103pub fn init(flags: &[InitFlag]) -> bool {
104	unsafe {
105		ll::SDL_Init(
106			flags
107				.iter()
108				.fold(0u32, |flags, &flag| flags | flag as ll::SDL_InitFlag),
109		) == 0
110	}
111}
112
113pub fn init_default() -> Result<crate::video::Surface, String> {
114	if !init(&[crate::InitFlag::Video]) {
115		return Err("Failed to initialize video".to_string());
116	}
117	crate::video::set_video_mode(
118		320,
119		240,
120		if has_colors() { 16 } else { 8 },
121		&[crate::video::SurfaceFlag::SWSurface],
122		&[],
123	)
124}
125
126pub fn init_subsystem(flags: &[InitFlag]) -> bool {
127	unsafe {
128		ll::SDL_InitSubSystem(
129			flags
130				.iter()
131				.fold(0u32, |flags, &flag| flags | flag as ll::SDL_InitFlag),
132		) == 0
133	}
134}
135
136pub fn quit_subsystem(flags: &[InitFlag]) {
137	let flags = flags
138		.iter()
139		.fold(0u32, |flags, &flag| flags | flag as ll::SDL_InitFlag);
140
141	unsafe {
142		ll::SDL_QuitSubSystem(flags);
143	}
144}
145
146pub fn quit() {
147	unsafe {
148		ll::SDL_Quit();
149	}
150}
151
152pub fn was_inited(flags: &[InitFlag]) -> Vec<InitFlag> {
153	let flags = flags
154		.iter()
155		.fold(0u32, |flags, &flag| flags | flag as ll::SDL_InitFlag);
156	let bitflags = unsafe { ll::SDL_WasInit(flags) };
157
158	let flags = [
159		InitFlag::Timer,
160		InitFlag::Audio,
161		InitFlag::Video,
162		InitFlag::CDRom,
163		InitFlag::Joystick,
164		InitFlag::NoParachute,
165		InitFlag::EventThread,
166		InitFlag::Everything,
167	];
168
169	flags
170		.iter()
171		.filter_map(|&flag| {
172			if bitflags & (flag as ll::SDL_InitFlag) != 0 {
173				Some(flag)
174			} else {
175				None
176			}
177		})
178		.collect()
179}
180
181pub fn get_error() -> String {
182	unsafe {
183		let cstr = ll::SDL_GetError() as *const cty::c_char;
184		let slice = CStr::from_ptr(cstr).to_bytes();
185
186		str::from_utf8(slice).unwrap().to_string()
187	}
188}
189
190pub fn set_error(err: &str) {
191	unsafe {
192		ll::SDL_SetError(CString::new(err.as_bytes()).unwrap().as_ptr());
193	}
194}
195
196pub fn set_error_from_code(err: Error) {
197	unsafe { ll::SDL_Error(err as ll::SDL_errorcode) }
198}
199
200pub fn clear_error() {
201	unsafe {
202		ll::SDL_ClearError();
203	}
204}
205
206pub fn get_ticks() -> usize {
207	unsafe { ll::SDL_GetTicks() as usize }
208}