tinychip/apis/libs/
sdl.rs

1use sdl2::Sdl;
2use sdl2::mouse::MouseButton;
3use sdl2::video::Window;
4use sdl2::{pixels::Color, render::Canvas, rect::Rect};
5use sdl2::event::{Event, WindowEvent};
6use sdl2::keyboard::Keycode;
7use sdl2::audio::{AudioCallback, AudioSpecDesired, AudioDevice};
8
9use std::collections::HashMap;
10
11use crate::models::audio::Audio;
12use crate::{
13    models::api::Api,
14    event::{
15        Hotkey,
16        MouseClick,
17        Mouse,
18        Input
19    },
20    properties::{
21        rectangle::Rectangle,
22        color
23    },
24    apis::api::{
25        WINDOW_MAX_H,
26        WINDOW_MAX_W,
27        WINDOW_MIN_H,
28        WINDOW_MIN_W
29    }
30};
31
32struct SquareWave {
33    phase_inc: f32,
34    phase: f32,
35    volume: f32
36}
37
38impl AudioCallback for SquareWave {
39    type Channel = f32;
40
41    fn callback(&mut self, out: &mut [f32]) {
42        // Generate a square wave
43        for x in out.iter_mut() {
44            *x = if self.phase <= 0.5 {
45                self.volume
46            } else {
47                -self.volume
48            };
49            self.phase = (self.phase + self.phase_inc) % 1.0;
50        }
51    }
52}
53
54/// SDL2 implementation
55pub struct SdlApi {
56    /// Graphic context
57    context: Sdl,
58    /// Audio device
59    audio_device: AudioDevice<SquareWave>,
60    /// Interacting with the window
61    canvas: Canvas<Window>,
62    /// Used to keep the window open
63    is_open: bool,
64    /// Used to handle multiple pressed keys continously
65    key_pressed: HashMap<sdl2::keyboard::Keycode, bool>,
66    /// Window size
67    window_size: (u32, u32)
68}
69
70impl SdlApi {
71    pub fn new(title: String, w: u32, h: u32) -> Self {
72        let context = sdl2::init().unwrap();
73        let video_subsystem = context.video().unwrap();
74        
75        // Init window
76        let mut window = video_subsystem.window(&title, w, h)
77            .position_centered()
78            .resizable()
79            .build()
80            .unwrap();
81        
82        // Set window size limits
83        window.set_minimum_size(WINDOW_MIN_W, WINDOW_MIN_H).unwrap();
84        window.set_maximum_size(WINDOW_MAX_W, WINDOW_MAX_H).unwrap();
85    
86        let canvas = window
87            .into_canvas()
88            .build()
89            .unwrap();
90        
91        let window_size = canvas.window().size();
92        let audio_device = SdlApi::build_audio(&context);
93    
94        Self {
95            context,
96            audio_device,
97            canvas,
98            is_open: true,
99            key_pressed: HashMap::new(),
100            window_size
101        }
102    }
103
104    /// Init audio
105    fn build_audio(context: &Sdl) -> AudioDevice<SquareWave> {
106        let audio_subsystem = context.audio().unwrap();
107
108        let desired_spec = AudioSpecDesired {
109            freq: Some(44100),
110            channels: Some(1),  // mono
111            samples: None       // default sample size
112        };
113
114        audio_subsystem.open_playback(None, &desired_spec, |spec| {
115            // initialize the audio callback
116            SquareWave {
117                phase_inc: 440.0 / spec.freq as f32,
118                phase: 0.0,
119                volume: 0.25
120            }
121        }).unwrap()
122    }
123}
124
125impl Api for SdlApi {
126    fn clear(&mut self) {
127        self.canvas.clear();
128    }
129
130    fn draw_rect(&mut self, rect: Rectangle, color: color::Color) {
131        let filled = Some(rect.into());
132
133        self.canvas.set_draw_color(color);
134        self.canvas.fill_rect(filled).unwrap();
135    }
136
137    fn is_window_open(&self) -> bool {
138        self.is_open
139    }
140
141    fn display(&mut self) {
142        self.canvas.present();
143    }
144
145    fn events(&mut self) -> Vec<Input> {
146        let mut inputs = Vec::<Input>::new();
147        let mut event_pump = self.context.event_pump().unwrap();
148
149        // Events handling
150        for event in event_pump.poll_iter() {
151            match event {
152                Event::Quit { .. } => self.is_open = false,
153
154                // Hotkeys pressed
155                Event::KeyDown { keycode, .. } => {
156                    if keycode.is_some() {
157                        self.key_pressed.insert(
158                            keycode.unwrap(),
159                            true
160                        );
161                    }
162                },
163
164                // Hotkeys released
165                Event::KeyUp { keycode, .. } => {
166                    if keycode.is_some() {
167                        self.key_pressed.insert(
168                            keycode.unwrap(),
169                            false
170                        );
171                    }
172                },
173
174                // Handle the window events
175                Event::Window { win_event, .. } => {
176                    if let WindowEvent::Resized(w, h) = win_event {
177                        self.window_size = (w as u32, h as u32);
178                    }
179                },
180
181                // Mouse buttons
182                Event::MouseButtonDown { mouse_btn, x, y, .. } => {
183                    let mouse = Mouse::new(mouse_btn, x, y);
184
185                    inputs.push(Input::Mouse(mouse));
186                },
187
188                _ => {}
189            }
190        }
191
192        // Add pressed hotkeys
193        for kp in self.key_pressed.iter() {
194            if *kp.1 == true {
195                let hotkey = Hotkey::from(*kp.0);
196    
197                inputs.push(Input::Hotkey(hotkey));
198            }
199        }
200
201        inputs
202    }
203
204    fn window_size(&self) -> (u32, u32) {
205        self.window_size
206    }
207
208}
209
210impl Audio for SdlApi {
211    fn resume_beep(&mut self) {
212        self.audio_device.resume();
213    }
214
215    fn pause_beep(&mut self) {
216        self.audio_device.pause();
217    }
218}
219
220impl From<Rectangle> for Rect {
221    fn from(r: Rectangle) -> Self {
222        Self::new(r.x, r.y, r.w, r.h)
223    }
224}
225
226impl From<color::Color> for Color {
227    fn from(c: color::Color) -> Self {
228        Self {
229            r: c.r,
230            g: c.g,
231            b: c.b,
232            a: c.a,
233        }
234    }
235}
236
237impl From<sdl2::keyboard::Keycode> for Hotkey {
238    fn from(keycode: sdl2::keyboard::Keycode) -> Self {
239        match keycode {
240            Keycode::Backspace => Self::Backspace,
241            Keycode::Tab => Self::Tab,
242            Keycode::Return => Self::Return,
243            Keycode::Escape => Self::Escape,
244            Keycode::Space => Self::Space,
245            Keycode::Exclaim => Self::Exclaim,
246            Keycode::Quotedbl => Self::Quotedbl,
247            Keycode::Hash => Self::Hash,
248            Keycode::Dollar => Self::Dollar,
249            Keycode::Percent => Self::Percent,
250            Keycode::Ampersand => Self::Ampersand,
251            Keycode::Quote => Self::Quote,
252            Keycode::LeftParen => Self::LeftParen,
253            Keycode::RightParen => Self::RightParen,
254            Keycode::Asterisk => Self::Asterisk,
255            Keycode::Plus => Self::Plus,
256            Keycode::Comma => Self::Comma,
257            Keycode::Minus => Self::Minus,
258            Keycode::Period => Self::Period,
259            Keycode::Slash => Self::Slash,
260            Keycode::Num0 => Self::Num0,
261            Keycode::Num1 => Self::Num1,
262            Keycode::Num2 => Self::Num2,
263            Keycode::Num3 => Self::Num3,
264            Keycode::Num4 => Self::Num4,
265            Keycode::Num5 => Self::Num5,
266            Keycode::Num6 => Self::Num6,
267            Keycode::Num7 => Self::Num7,
268            Keycode::Num8 => Self::Num8,
269            Keycode::Num9 => Self::Num9,
270            Keycode::Colon => Self::Colon,
271            Keycode::Semicolon => Self::Semicolon,
272            Keycode::Less => Self::Less,
273            Keycode::Equals => Self::Equals,
274            Keycode::Greater => Self::Greater,
275            Keycode::Question => Self::Question,
276            Keycode::At => Self::At,
277            Keycode::LeftBracket => Self::LeftBracket,
278            Keycode::Backslash => Self::Backslash,
279            Keycode::RightBracket => Self::RightBracket,
280            Keycode::Caret => Self::Caret,
281            Keycode::Underscore => Self::Underscore,
282            Keycode::Backquote => Self::Backquote,
283            Keycode::A => Self::A,
284            Keycode::B => Self::B,
285            Keycode::C => Self::C,
286            Keycode::D => Self::D,
287            Keycode::E => Self::E,
288            Keycode::F => Self::F,
289            Keycode::G => Self::G,
290            Keycode::H => Self::H,
291            Keycode::I => Self::I,
292            Keycode::J => Self::J,
293            Keycode::K => Self::K,
294            Keycode::L => Self::L,
295            Keycode::M => Self::M,
296            Keycode::N => Self::N,
297            Keycode::O => Self::O,
298            Keycode::P => Self::P,
299            Keycode::Q => Self::Q,
300            Keycode::R => Self::R,
301            Keycode::S => Self::S,
302            Keycode::T => Self::T,
303            Keycode::U => Self::U,
304            Keycode::V => Self::V,
305            Keycode::W => Self::W,
306            Keycode::X => Self::X,
307            Keycode::Y => Self::Y,
308            Keycode::Z => Self::Z,
309            Keycode::Delete => Self::Delete,
310            Keycode::CapsLock => Self::CapsLock,
311            Keycode::F1 => Self::F1,
312            Keycode::F2 => Self::F2,
313            Keycode::F3 => Self::F3,
314            Keycode::F4 => Self::F4,
315            Keycode::F5 => Self::F5,
316            Keycode::F6 => Self::F6,
317            Keycode::F7 => Self::F7,
318            Keycode::F8 => Self::F8,
319            Keycode::F9 => Self::F9,
320            Keycode::F10 => Self::F10,
321            Keycode::F11 => Self::F11,
322            Keycode::F12 => Self::F12,
323            Keycode::PrintScreen => Self::PrintScreen,
324            Keycode::ScrollLock => Self::ScrollLock,
325            Keycode::Pause => Self::Pause,
326            Keycode::Insert => Self::Insert,
327            Keycode::Home => Self::Home,
328            Keycode::PageUp => Self::PageUp,
329            Keycode::End => Self::End,
330            Keycode::PageDown => Self::PageDown,
331            Keycode::Right => Self::Right,
332            Keycode::Left => Self::Left,
333            Keycode::Down => Self::Down,
334            Keycode::Up => Self::Up,
335            Keycode::NumLockClear => Self::NumLockClear,
336            Keycode::KpDivide => Self::KpDivide,
337            Keycode::KpMultiply => Self::KpMultiply,
338            Keycode::KpMinus => Self::KpMinus,
339            Keycode::KpPlus => Self::KpPlus,
340            Keycode::KpEnter => Self::KpEnter,
341            Keycode::Kp1 => Self::Kp1,
342            Keycode::Kp2 => Self::Kp2,
343            Keycode::Kp3 => Self::Kp3,
344            Keycode::Kp4 => Self::Kp4,
345            Keycode::Kp5 => Self::Kp5,
346            Keycode::Kp6 => Self::Kp6,
347            Keycode::Kp7 => Self::Kp7,
348            Keycode::Kp8 => Self::Kp8,
349            Keycode::Kp9 => Self::Kp9,
350            Keycode::Kp0 => Self::Kp0,
351            Keycode::KpPeriod => Self::KpPeriod,
352            Keycode::Application => Self::Application,
353            Keycode::Power => Self::Power,
354            Keycode::KpEquals => Self::KpEquals,
355            Keycode::F13 => Self::F13,
356            Keycode::F14 => Self::F14,
357            Keycode::F15 => Self::F15,
358            Keycode::F16 => Self::F16,
359            Keycode::F17 => Self::F17,
360            Keycode::F18 => Self::F18,
361            Keycode::F19 => Self::F19,
362            Keycode::F20 => Self::F20,
363            Keycode::F21 => Self::F21,
364            Keycode::F22 => Self::F22,
365            Keycode::F23 => Self::F23,
366            Keycode::F24 => Self::F24,
367            Keycode::Execute => Self::Execute,
368            Keycode::Help => Self::Help,
369            Keycode::Menu => Self::Menu,
370            Keycode::Select => Self::Select,
371            Keycode::Stop => Self::Stop,
372            Keycode::Again => Self::Again,
373            Keycode::Undo => Self::Undo,
374            Keycode::Cut => Self::Cut,
375            Keycode::Copy => Self::Copy,
376            Keycode::Paste => Self::Paste,
377            Keycode::Find => Self::Find,
378            Keycode::Mute => Self::Mute,
379            Keycode::VolumeUp => Self::VolumeUp,
380            Keycode::VolumeDown => Self::VolumeDown,
381            Keycode::KpComma => Self::KpComma,
382            Keycode::KpEqualsAS400 => Self::KpEqualsAS400,
383            Keycode::AltErase => Self::AltErase,
384            Keycode::Sysreq => Self::Sysreq,
385            Keycode::Cancel => Self::Cancel,
386            Keycode::Clear => Self::Clear,
387            Keycode::Prior => Self::Prior,
388            Keycode::Return2 => Self::Return2,
389            Keycode::Separator => Self::Separator,
390            Keycode::Out => Self::Out,
391            Keycode::Oper => Self::Oper,
392            Keycode::ClearAgain => Self::ClearAgain,
393            Keycode::CrSel => Self::CrSel,
394            Keycode::ExSel => Self::ExSel,
395            Keycode::Kp00 => Self::Kp00,
396            Keycode::Kp000 => Self::Kp000,
397            Keycode::ThousandsSeparator => Self::ThousandsSeparator,
398            Keycode::DecimalSeparator => Self::DecimalSeparator,
399            Keycode::CurrencyUnit => Self::CurrencyUnit,
400            Keycode::CurrencySubUnit => Self::CurrencySubUnit,
401            Keycode::KpLeftParen => Self::KpLeftParen,
402            Keycode::KpRightParen => Self::KpRightParen,
403            Keycode::KpLeftBrace => Self::KpLeftBrace,
404            Keycode::KpRightBrace => Self::KpRightBrace,
405            Keycode::KpTab => Self::KpTab,
406            Keycode::KpBackspace => Self::KpBackspace,
407            Keycode::KpA => Self::KpA,
408            Keycode::KpB => Self::KpB,
409            Keycode::KpC => Self::KpC,
410            Keycode::KpD => Self::KpD,
411            Keycode::KpE => Self::KpE,
412            Keycode::KpF => Self::KpF,
413            Keycode::KpXor => Self::KpXor,
414            Keycode::KpPower => Self::KpPower,
415            Keycode::KpPercent => Self::KpPercent,
416            Keycode::KpLess => Self::KpLess,
417            Keycode::KpGreater => Self::KpGreater,
418            Keycode::KpAmpersand => Self::KpAmpersand,
419            Keycode::KpDblAmpersand => Self::KpDblAmpersand,
420            Keycode::KpVerticalBar => Self::KpVerticalBar,
421            Keycode::KpDblVerticalBar => Self::KpDblVerticalBar,
422            Keycode::KpColon => Self::KpColon,
423            Keycode::KpHash => Self::KpHash,
424            Keycode::KpSpace => Self::KpSpace,
425            Keycode::KpAt => Self::KpAt,
426            Keycode::KpExclam => Self::KpExclam,
427            Keycode::KpMemStore => Self::KpMemStore,
428            Keycode::KpMemRecall => Self::KpMemRecall,
429            Keycode::KpMemClear => Self::KpMemClear,
430            Keycode::KpMemAdd => Self::KpMemAdd,
431            Keycode::KpMemSubtract => Self::KpMemSubtract,
432            Keycode::KpMemMultiply => Self::KpMemMultiply,
433            Keycode::KpMemDivide => Self::KpMemDivide,
434            Keycode::KpPlusMinus => Self::KpPlusMinus,
435            Keycode::KpClear => Self::KpClear,
436            Keycode::KpClearEntry => Self::KpClearEntry,
437            Keycode::KpBinary => Self::KpBinary,
438            Keycode::KpOctal => Self::KpOctal,
439            Keycode::KpDecimal => Self::KpDecimal,
440            Keycode::KpHexadecimal => Self::KpHexadecimal,
441            Keycode::LCtrl => Self::LCtrl,
442            Keycode::LShift => Self::LShift,
443            Keycode::LAlt => Self::LAlt,
444            Keycode::LGui => Self::LGui,
445            Keycode::RCtrl => Self::RCtrl,
446            Keycode::RShift => Self::RShift,
447            Keycode::RAlt => Self::RAlt,
448            Keycode::RGui => Self::RGui,
449            Keycode::Mode => Self::Mode,
450            Keycode::AudioNext => Self::AudioNext,
451            Keycode::AudioPrev => Self::AudioPrev,
452            Keycode::AudioStop => Self::AudioStop,
453            Keycode::AudioPlay => Self::AudioPlay,
454            Keycode::AudioMute => Self::AudioMute,
455            Keycode::MediaSelect => Self::MediaSelect,
456            Keycode::Www => Self::Www,
457            Keycode::Mail => Self::Mail,
458            Keycode::Calculator => Self::Calculator,
459            Keycode::Computer => Self::Computer,
460            Keycode::AcSearch => Self::AcSearch,
461            Keycode::AcHome => Self::AcHome,
462            Keycode::AcBack => Self::AcBack,
463            Keycode::AcForward => Self::AcForward,
464            Keycode::AcStop => Self::AcStop,
465            Keycode::AcRefresh => Self::AcRefresh,
466            Keycode::BrightnessDown => Self::BrightnessDown,
467            Keycode::BrightnessUp => Self::BrightnessUp,
468            Keycode::DisplaySwitch => Self::DisplaySwitch,
469            Keycode::KbdIllumToggle => Self::KbdIllumToggle,
470            Keycode::KbdIllumDown => Self::KbdIllumDown,
471            Keycode::KbdIllumUp => Self::KbdIllumUp,
472            Keycode::Eject => Self::Eject,
473            Keycode::Sleep => Self::Sleep,
474            Keycode::AcBookmarks => Self::AcBookmarks,
475        }
476    }
477}
478
479impl From<MouseButton> for MouseClick {
480    fn from(button: MouseButton) -> Self {
481        match button {
482            MouseButton::Unknown => Self::Unknown,
483            MouseButton::Left => Self::Left,
484            MouseButton::Middle => Self::Middle,
485            MouseButton::Right => Self::Right,
486            MouseButton::X1 => Self::Unknown,
487            MouseButton::X2 => Self::Unknown,
488        }
489    }
490}