use std::*;
use std::sync::mpsc;
use std::collections::HashSet;
use std::marker::PhantomData;
use crate::types::*;
use crate::types::events::Event;
extern crate sdl2;
use self::sdl2::*;
use self::sdl2::event::Event as SdlEvent;
use self::sdl2::keyboard::Keycode;
use self::sdl2::pixels::PixelFormatEnum;
pub struct Renderer<P> {
w: u32,
h: u32,
context: sdl2::Sdl,
canvas: render::WindowCanvas,
pub event_rx: mpsc::Receiver<events::Event>,
event_tx: mpsc::Sender<events::Event>,
prev_buttons: HashSet<mouse::MouseButton>,
_pixel: PhantomData<P>,
}
impl <P>Renderer<P> {
pub fn new(name: &str, w: u32, h: u32) -> Self {
let context = sdl2::init().unwrap();
let video_subsystem = context.video().unwrap();
let window = video_subsystem
.window(name, w, h)
.position_centered()
.build()
.unwrap();
let canvas = window.into_canvas().software().build().unwrap();
let (event_tx, event_rx): (mpsc::Sender<events::Event>, mpsc::Receiver<events::Event>) = mpsc::channel();
let prev_buttons = HashSet::new();
return Renderer{w, h, context, canvas, event_rx, event_tx, prev_buttons, _pixel: PhantomData};
}
pub fn update(&mut self) -> bool {
let mut running = true;
let mut sdl_events = self.context.event_pump().unwrap();
for event in sdl_events.poll_iter() {
match event {
SdlEvent::KeyDown { keycode: Some(Keycode::Escape), .. } |
SdlEvent::Quit { .. } => { running = false; },
SdlEvent::KeyDown { keycode: Some(Keycode::Up), .. } => { self.event_tx.send(Event::Up).unwrap(); },
SdlEvent::KeyDown { keycode: Some(Keycode::Down), .. } => { self.event_tx.send(Event::Down).unwrap(); },
SdlEvent::KeyDown { keycode: Some(Keycode::Left), .. } => { self.event_tx.send(Event::Left).unwrap(); },
SdlEvent::KeyDown { keycode: Some(Keycode::Right), .. } => { self.event_tx.send(Event::Right).unwrap(); },
SdlEvent::KeyDown { keycode: Some(Keycode::Return), .. } => { self.event_tx.send(Event::Select).unwrap(); },
SdlEvent::KeyDown { keycode: Some(Keycode::Backspace), .. } => { self.event_tx.send(Event::Back).unwrap(); },
_ => {}
}
}
let state = sdl_events.mouse_state();
let buttons = state.pressed_mouse_buttons().collect();
let new_buttons = &buttons - &self.prev_buttons;
let old_buttons = &self.prev_buttons - &buttons;
if !new_buttons.is_empty() && old_buttons.is_empty() {
self.event_tx.send(Event::Click{x: state.x() as usize, y: state.y() as usize}).unwrap();
}
self.prev_buttons = buttons;
return running;
}
fn render_common(&mut self, data: &[u8]) {
let creator = self.canvas.texture_creator();
let mut texture = creator.create_texture_target(PixelFormatEnum::RGBA8888, self.w, self.h).unwrap();
texture.update(None, data, (self.w * 4) as usize).unwrap();
self.canvas.copy_ex(&texture, None, None, 0.0, None, false, false).unwrap();
self.canvas.present();
}
}
impl Renderer<PixelBW> {
pub fn render(&mut self, pixels: &[u8]) {
let data = Self::bw_to_rgba32(self.w as usize, self.h as usize, pixels);
self.render_common(data.as_slice());
}
fn bw_to_rgba32(w: usize, h: usize, pixels: &[u8]) -> Vec<u8> {
let size = w * h * 4;
let mut data: Vec<u8> = vec![0; size];
for y in 0..h {
let i = y * w / 8;
let row = &pixels[i .. i + w / 8];
for x in 0..w {
let pixel_index = x / 8 as usize;
let pixel_mask = 1 << (7-(x % 8));
let data_index = (y * w + x) * 4 as usize;
let m = if row[pixel_index] & pixel_mask == 0 {
0xFF
} else {
0x00
};
for i in 0..4 {
data[data_index + i] = m;
}
}
}
data
}
}
impl Renderer<PixelRGB24> {
pub fn render(&mut self, pixels: &[u8]) {
let data = Self::rgb24_to_rgba32(self.w as usize, self.h as usize, &pixels);
self.render_common(data.as_slice());
}
fn rgb24_to_rgba32(w: usize, h: usize, pixels: &[u8]) -> Vec<u8> {
let size = w * h * 4;
let mut data: Vec<u8> = vec![0; size];
for y in 0..h {
for x in 0..w {
let pixel_index = (y * w + x) * 3;
let data_index = (y * w + x) * 4;
data[data_index+0] = 255;
data[data_index+1] = pixels[pixel_index+2];
data[data_index+2] = pixels[pixel_index+1];
data[data_index+3] = pixels[pixel_index+0];
}
}
data
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_bw_to_rgba32() {
let pixels = [
0b1000_0001,
0b0100_0010,
];
let expected = [
0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
].to_vec();
let mapped = Renderer::<PixelBW>::bw_to_rgba32(8, 2, &pixels);
assert_eq!(expected.len(), mapped.len());
assert_eq!(expected, mapped);
}
#[test]
fn test_rgb24_to_rgba32() {
let pixels = [
0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc,
];
let expected = [
0xff, 0x33, 0x22, 0x11, 0xff, 0x66, 0x55, 0x44,
0xff, 0x99, 0x88, 0x77, 0xff, 0xcc, 0xbb, 0xaa,
].to_vec();
let mapped = Renderer::<PixelRGB24>::rgb24_to_rgba32(2, 2, &pixels);
assert_eq!(expected.len(), mapped.len());
assert_eq!(expected, mapped);
}
}