micro_gui/
native.rs

1//! Native rendering module provides mechanisms for rendering ugui interfaces
2//! on standard computers using sdl2.
3//!
4//! Copyright 2017 Ryan Kurte
5
6
7use std::*;
8use std::sync::mpsc;
9use std::collections::HashSet;
10use std::marker::PhantomData;
11
12use crate::types::*;
13use crate::types::events::Event;
14
15extern crate sdl2;
16use self::sdl2::*;
17use self::sdl2::event::Event as SdlEvent;
18use self::sdl2::keyboard::Keycode;
19use self::sdl2::pixels::PixelFormatEnum;
20
21/// Renderer implements an SDL2 based micro-gui renderer
22pub struct Renderer<P> {
23    w: u32,
24    h: u32,
25    context: sdl2::Sdl,
26    canvas: render::WindowCanvas,
27    pub event_rx: mpsc::Receiver<events::Event>,
28    event_tx: mpsc::Sender<events::Event>,
29    prev_buttons: HashSet<mouse::MouseButton>,
30    _pixel: PhantomData<P>,
31}
32
33impl <P>Renderer<P> {
34    /// Create a new native (SDL2 based) renderer
35    pub fn new(name: &str, w: u32, h: u32) -> Self {
36        let context = sdl2::init().unwrap();
37        let video_subsystem = context.video().unwrap();
38        let window = video_subsystem
39            .window(name, w, h)
40            .position_centered()
41            .build()
42            .unwrap();
43
44        let canvas = window.into_canvas().software().build().unwrap();
45
46        let (event_tx, event_rx): (mpsc::Sender<events::Event>, mpsc::Receiver<events::Event>) = mpsc::channel();
47
48        let prev_buttons = HashSet::new();
49
50        return Renderer{w, h, context, canvas, event_rx, event_tx, prev_buttons, _pixel: PhantomData};
51    }
52
53    /// Update should be run in the main loop
54    /// This parses SDL events and converts them to ugui events on the event channel
55    pub fn update(&mut self) -> bool {
56        let mut running = true;
57
58        let mut sdl_events = self.context.event_pump().unwrap();
59
60        // Handle keyboard events
61        for event in sdl_events.poll_iter() {
62            match event {
63                SdlEvent::KeyDown { keycode: Some(Keycode::Escape), .. } |
64                SdlEvent::Quit { .. } => { running = false; },
65                SdlEvent::KeyDown { keycode: Some(Keycode::Up), .. } => { self.event_tx.send(Event::Up).unwrap(); },       
66                SdlEvent::KeyDown { keycode: Some(Keycode::Down), .. } => { self.event_tx.send(Event::Down).unwrap(); },
67                SdlEvent::KeyDown { keycode: Some(Keycode::Left), .. } => { self.event_tx.send(Event::Left).unwrap(); },
68                SdlEvent::KeyDown { keycode: Some(Keycode::Right), .. } => { self.event_tx.send(Event::Right).unwrap(); },
69                SdlEvent::KeyDown { keycode: Some(Keycode::Return), .. } => { self.event_tx.send(Event::Select).unwrap(); },
70                SdlEvent::KeyDown { keycode: Some(Keycode::Backspace), .. } => { self.event_tx.send(Event::Back).unwrap(); },        
71                _ => {}
72            }
73        }
74
75        // Handle mouse events
76        let state = sdl_events.mouse_state();
77
78        // Create a set of pressed Keys.
79        let buttons = state.pressed_mouse_buttons().collect();
80
81        // Get the difference between the new and old sets.
82        let new_buttons = &buttons - &self.prev_buttons;
83        let old_buttons = &self.prev_buttons - &buttons;
84
85        if !new_buttons.is_empty() && old_buttons.is_empty() {
86            self.event_tx.send(Event::Click{x: state.x() as usize, y: state.y() as usize}).unwrap();
87        }
88
89        self.prev_buttons = buttons;
90        
91        return running;
92    }
93
94    fn render_common(&mut self, data: &[u8]) {
95        let creator = self.canvas.texture_creator();
96        let mut texture = creator.create_texture_target(PixelFormatEnum::RGBA8888, self.w, self.h).unwrap();
97
98        texture.update(None, data, (self.w * 4) as usize).unwrap();
99
100        self.canvas.copy_ex(&texture, None, None, 0.0, None, false, false).unwrap();
101        self.canvas.present();
102    }
103
104
105
106
107}
108
109
110impl Renderer<PixelBW> {
111    pub fn render(&mut self, pixels: &[u8]) {
112        let data = Self::bw_to_rgba32(self.w as usize, self.h as usize, pixels);
113
114        self.render_common(data.as_slice()); 
115    }
116
117    /// Convert a bit-packed black and white representation to RGBA32
118    fn bw_to_rgba32(w: usize, h: usize, pixels: &[u8]) -> Vec<u8> {
119        let size = w * h * 4;
120        let mut data: Vec<u8> = vec![0; size];
121
122        for y in 0..h {
123            let i = y * w / 8;
124            let row = &pixels[i .. i + w / 8];
125
126            for x in 0..w {
127                let pixel_index = x / 8 as usize;
128                let pixel_mask = 1 << (7-(x % 8));
129                let data_index = (y * w + x) * 4 as usize;
130
131                let m = if row[pixel_index] & pixel_mask == 0 {
132                    0xFF
133                } else {
134                    0x00
135                };
136                
137                for i in 0..4 {
138                    data[data_index + i] = m;
139                }
140            }
141        }
142
143        data
144    }
145}
146
147
148impl Renderer<PixelRGB24> {
149    /// Render an rgb24 (8,8,8) encoded image
150    pub fn render(&mut self, pixels: &[u8]) {
151        let data = Self::rgb24_to_rgba32(self.w as usize, self.h as usize, &pixels);
152
153        self.render_common(data.as_slice()); 
154    }
155
156    /// Convert a bit-packed black and white representation to RGBA32
157    fn rgb24_to_rgba32(w: usize, h: usize, pixels: &[u8]) -> Vec<u8> {
158        let size = w * h * 4;
159        let mut data: Vec<u8> = vec![0; size];
160
161        for y in 0..h {
162            for x in 0..w {
163                let pixel_index = (y * w + x) * 3;
164                let data_index = (y * w + x) * 4;
165
166                data[data_index+0] = 255;
167                data[data_index+1] = pixels[pixel_index+2];
168                data[data_index+2] = pixels[pixel_index+1];
169                data[data_index+3] = pixels[pixel_index+0];
170            }
171        }
172
173        data
174    }
175}
176
177
178#[cfg(test)]
179mod tests {
180    use super::*;
181
182    #[test]
183    fn test_bw_to_rgba32() {
184        let pixels = [
185            0b1000_0001, 
186            0b0100_0010,
187        ];
188        let expected = [
189            0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
190            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
191            0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
192            0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
193        ].to_vec();
194
195
196        let mapped = Renderer::<PixelBW>::bw_to_rgba32(8, 2, &pixels);
197
198        assert_eq!(expected.len(), mapped.len());
199        assert_eq!(expected, mapped);
200    }
201
202    #[test]
203    fn test_rgb24_to_rgba32() {
204        let pixels = [
205            0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 
206            0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc,
207        ];
208        let expected = [
209            //0x11, 0x22, 0x33, 0xFF, 0x44, 0x55, 0x66, 0xFF,
210            //0x66, 0x77, 0x88, 0xFF, 0x99, 0xaa, 0xbb, 0xFF,
211            0xff, 0x33, 0x22, 0x11, 0xff, 0x66, 0x55, 0x44,
212            0xff, 0x99, 0x88, 0x77, 0xff, 0xcc, 0xbb, 0xaa,
213        ].to_vec();
214
215
216        let mapped = Renderer::<PixelRGB24>::rgb24_to_rgba32(2, 2, &pixels);
217
218        assert_eq!(expected.len(), mapped.len());
219        assert_eq!(expected, mapped);
220    }
221}