1use core::str;
2use cstr_core::{CStr, CString};
3use ndless::hw::has_colors;
4use ndless::prelude::*;
5
6#[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}