extern crate sdl2;
use std::ops::Deref;
use sdl2::{video, VideoSubsystem};
use crate::math::mat::Mat;
use crate::math::vect::Vect;
use sdl2::video::GLContext;
use crate::render::buffer::Buffer;
use crate::render::batch::Target;
use self::sdl2::{EventPump, Sdl};
use crate::math::rect::Rect;
use crate::render::canvas::Canvas;
use crate::render::texture::TextureSize;
use crate::{Texture};
use crate::render::program::Program;
use crate::math::rgba::{RGBA, BLACK, WHITE};
use std::collections::HashSet;
use self::sdl2::keyboard::Keycode;
use self::sdl2::event::Event;
use self::sdl2::mouse::MouseButton;
pub struct Window {
pub canvas: Canvas,
pub window: video::Window,
background_color: RGBA,
}
impl Deref for Window {
type Target = video::Window;
fn deref(&self) -> &Self::Target {
&self.window
}
}
impl Window {
pub fn new<F>(gen: F) -> (Window, EventPump, GLContext, Sdl, VideoSubsystem)
where F: FnOnce(&VideoSubsystem) -> video::Window {
let sdl = sdl2::init().expect("You probably did not set up your project correctly go to \
crates documentation, you can find all answers there.");
let video_subsystem = sdl.video().unwrap();
let gl_attr = video_subsystem.gl_attr();
gl_attr.set_context_profile(sdl2::video::GLProfile::Core);
gl_attr.set_context_version(4, 0);
let window = gen(&video_subsystem);
let gl = window.gl_create_context().unwrap();
let _fl = gl::load_with(|s| video_subsystem.gl_get_proc_address(s) as *const std::os::raw::c_void);
unsafe {
gl::Enable(gl::BLEND);
gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
}
let (w, h) = window.size();
(Window{canvas: Canvas::new(TextureSize::new(w as i32, h as i32)) ,window, background_color: BLACK}, sdl.event_pump().unwrap(), gl, sdl, video_subsystem)
}
pub fn update(&mut self) {
let size = self.size();
if size != self.canvas.size() {
self.canvas.resize(TextureSize::new(size.0 as i32, size.1 as i32))
}
self.canvas.draw(&mut self.window, &Mat::IM, &WHITE);
self.gl_swap_window();
}
pub fn get_viewport_rect(&self) -> Rect {
let (w, h) = self.size();
let w = w as i32 /2;
let h = h as i32 /2;
let mut corners: [Vect; 4] = [
vect!(-w, -h),
vect!(w, -h),
vect!(w, h),
vect!(-w, h),
];
for i in 0..corners.len() {
corners[i] = self.canvas.camera.unprj(corners[i]);
}
Rect::bounds_for(&corners)
}
pub fn set_background_color(&mut self, color: &RGBA) {
self.background_color = color.clone();
}
#[inline]
pub fn clear(&self) {
super::clear(&self.background_color);
self.canvas.reset()
}
pub fn project_mouse(&self, mouse: Vect) -> Vect {
let (w, h) = self.window.size();
let mut pos = mouse - vect!(w, h)/2.0;
pos.y *= -1.0;
self.canvas.camera.unprj(pos)
}
}
impl Target for video::Window {
fn append(&mut self, data: &[f32], pattern: &[u32], _: u32, program: Option<&Program>, texture: Option<&Texture>, buffer: Option<&Buffer>) {
let (w, h) = self.size();
unsafe {
gl::Viewport(0, 0, w as i32, h as i32);
}
match program {
Some(p) => {
p.bind();
p.set_camera(&Mat::IM);
p.set_view_size(vect!(w, h));
}
None => panic!("program mustn't be none when drawing to window, use something that has \
program in it like canvas of GeomDrawer."),
}
if let Some(t) = texture {
t.bind()
} else {
Texture::NONE.bind();
}
let buffer = match buffer {
Some(b) => b,
None => panic!("buffer mustn't be none when drawing to window, use something that has \
program in it like canvas or GeomDrawer."),
};
buffer.set_vertices_and_indices(data, pattern);
buffer.bind();
buffer.draw(pattern.len());
}
}
pub type KeySet = HashSet<Keycode>;
pub struct KeyState {
down: KeySet,
up: KeySet,
pressed: KeySet,
}
impl KeyState {
#[inline]
pub fn zero() -> Self {
Self {
down: HashSet::new(),
up: HashSet::new(),
pressed: HashSet::new(),
}
}
#[inline]
pub fn merge(&mut self, other: Self) {
self.pressed.extend(other.down);
self.pressed.extend(other.pressed);
}
pub fn new(events: &Vec<Event>, previos: Self) -> Self {
let mut key_state = Self::zero();
key_state.merge(previos);
for event in events {
match event {
Event::KeyDown { keycode, repeat, .. } => {
if let Some(key) = keycode {
if !repeat {
key_state.down.insert(*key);
}
}
}
Event::KeyUp { keycode, repeat, .. } => {
if let Some(key) = keycode {
if !repeat {
key_state.pressed.remove(key);
key_state.up.insert(*key);
}
}
}
_ => ()
}
}
key_state
}
pub fn pressed(&self, key: Keycode) -> bool {
self.pressed.contains(&key)
}
}
type ButtonSet = HashSet<MouseButton>;
pub struct MouseState {
down: ButtonSet,
up: ButtonSet,
pressed: ButtonSet,
pub pos: Vect,
pub prev_pos: Vect,
pub scroll: Vect,
pub double_click: bool,
}
impl MouseState {
pub fn zero() -> Self {
Self {
down: HashSet::new(),
up: HashSet::new(),
pressed: HashSet::new(),
pos: Vect::ZERO,
prev_pos: Vect::ZERO,
scroll: Vect::ZERO,
double_click: false,
}
}
pub fn merge(&mut self, other: Self) {
self.prev_pos = other.pos;
self.pos = other.pos;
self.pressed.extend(other.pressed);
self.pressed.extend(other.down);
}
pub fn new(events: &Vec<Event>, previous: Self, win: &Window) -> Self {
let mut new = Self::zero();
new.merge(previous);
for event in events {
match event {
Event::MouseWheel { x, y, .. } => {
new.scroll = vect!(*x, *y);
}
Event::MouseMotion { x, y, ..} => {
new.pos = win.project_mouse(vect!(*x, *y));
}
Event::MouseButtonDown {mouse_btn, clicks, ..} => {
if clicks == &2u8 {
new.double_click = true;
}
new.down.insert(*mouse_btn);
}
Event::MouseButtonUp { mouse_btn, clicks, ..} => {
if clicks == &2u8 {
new.double_click = true;
}
new.pressed.remove(&mouse_btn);
new.up.insert(*mouse_btn);
}
_ => ()
}
}
new
}
pub fn pressed(&self, button: MouseButton) -> bool {
self.pressed.contains(&button)
}
}