glerminal 0.1.5

A lightweight OpenGL terminal
Documentation
use glutin::{ContextBuilder, ElementState, Event, EventsLoop, GlContext, GlWindow, WindowBuilder,
             WindowEvent, GlRequest, Api};
use gl;

use renderer::{self, Matrix4};
use input::Input;
use std::cell::{Cell, RefCell};

#[cfg(test)]
use glutin::VirtualKeyCode;

pub struct Display {
    pub proj_matrix: Cell<Matrix4>,
    aspect_ratio: Cell<f32>,
    window: GlWindow,
    input: RefCell<Input>,
    events_loop: RefCell<EventsLoop>,
    width: Cell<u32>,
    height: Cell<u32>,
}

impl Display {
    pub fn new<T: Into<String>>(
        title: T,
        dimensions: (u32, u32),
        clear_color: (f32, f32, f32, f32),
        visibility: bool,
    ) -> Display {
        let (width, height) = dimensions;
        let aspect_ratio = width as f32 / height as f32;
        let title = title.into();
        let events_loop = EventsLoop::new();
        let window = WindowBuilder::new()
            .with_title(title)
            .with_dimensions(width, height)
            .with_visibility(visibility);
        let context = ContextBuilder::new().with_vsync(true)
            .with_gl(GlRequest::Specific(Api::OpenGl, (3, 1)));
        let window = match GlWindow::new(window, context, &events_loop) {
            Ok(window) => window,
            Err(err) => panic!(err),
        };

        unsafe {
            let (r, g, b, a) = clear_color;
            if let Err(err) = window.make_current() {
                panic!(err);
            }
            gl::load_with(|symbol| window.get_proc_address(symbol) as *const _);
            gl::ClearColor(r, g, b, a);
            gl::Enable(gl::BLEND);
            gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA);
        };

        let proj_matrix = renderer::create_proj_matrix((width as f32, height as f32), aspect_ratio);

        Display {
            window: window,
            input: RefCell::new(Input::new()),
            events_loop: RefCell::new(events_loop),
            aspect_ratio: Cell::new(aspect_ratio),
            proj_matrix: Cell::new(proj_matrix),
            width: Cell::new(width),
            height: Cell::new(height),
        }
    }

    pub fn refresh(&self) -> bool {
        let mut running = true;

        let mut dimensions: Option<(u32, u32)> = None;

        let input = self.input.borrow_mut().clear_just_lists();
        drop(input);

        self.window.swap_buffers().ok();

        self.events_loop
            .borrow_mut()
            .poll_events(|event| match event {
                Event::WindowEvent { event, .. } => match event {
                    WindowEvent::Closed => {
                        running = false;
                    }
                    WindowEvent::Resized(width, height) => {
                        dimensions = Some((width, height));
                    }
                    WindowEvent::KeyboardInput { input, .. } => {
                        if let (state, Some(keycode)) = (input.state, input.virtual_keycode) {
                            self.input
                                .borrow_mut()
                                .update_virtual_keycode(keycode, state == ElementState::Pressed);
                        }
                    }
                    _ => (),
                },
                _ => (),
            });

        if let Some((width, height)) = dimensions {
            self.width.set(width);
            self.height.set(height);
            self.update_view();
        }

        running
    }

    pub fn get_current_input(&self) -> Input {
        self.input.borrow().clone()
    }

    pub fn set_title(&mut self, title: &str) {
        self.window.set_title(title);
    }

    pub fn show(&mut self) {
        self.window.show();
    }

    pub(crate) fn get_aspect_ratio(&self) -> f32 {
        self.aspect_ratio.get()
    }

    pub(crate) fn set_aspect_ratio(&self, aspect_ratio: f32) {
        self.aspect_ratio.set(aspect_ratio);
        self.update_view()
    }

    #[cfg(test)]
    pub(crate) fn update_virtual_keycode(&mut self, keycode: VirtualKeyCode, pressed: bool) {
        self.input
            .borrow_mut()
            .update_virtual_keycode(keycode, pressed);
    }

    fn update_view(&self) {
        self.proj_matrix.set(renderer::create_proj_matrix(
            (self.width.get() as f32, self.height.get() as f32),
            self.aspect_ratio.get(),
        ));
        renderer::update_viewport((self.width.get(), self.height.get()));
    }
}